From b7c51c9cf4864df6aabb99a1ae843becd577237c Mon Sep 17 00:00:00 2001 From: raywu Date: Fri, 15 Jun 2018 00:00:50 +0800 Subject: init. 1AQQW051 --- Core/EM/Ahci/AInt13.c | 1366 ++++++++++++ Core/EM/Ahci/AInt13.dxs | 37 + Core/EM/Ahci/AInt13.h | 395 ++++ Core/EM/Ahci/AhciBus.c | 4477 ++++++++++++++++++++++++++++++++++++++ Core/EM/Ahci/AhciBus.h | 919 ++++++++ Core/EM/Ahci/AhciComponentName.c | 314 +++ Core/EM/Ahci/AhciController.c | 3403 +++++++++++++++++++++++++++++ Core/EM/Ahci/AhciController.h | 633 ++++++ Core/EM/Ahci/AhciInt13Dxe.c | 412 ++++ Core/EM/Ahci/AhciInt13Dxe.dxs | 51 + Core/EM/Ahci/AhciInt13Smm.c | 1157 ++++++++++ Core/EM/Ahci/AhciInt13Smm.cif | 15 + Core/EM/Ahci/AhciInt13Smm.dxs | 65 + Core/EM/Ahci/AhciInt13Smm.h | 155 ++ Core/EM/Ahci/AhciInt13Smm.mak | 72 + Core/EM/Ahci/AhciInt13Smm.sdl | 58 + Core/EM/Ahci/AhciSmm/AhciSmm.c | 2217 +++++++++++++++++++ Core/EM/Ahci/AhciSmm/AhciSmm.cif | 14 + Core/EM/Ahci/AhciSmm/AhciSmm.dxs | 87 + Core/EM/Ahci/AhciSmm/AhciSmm.h | 237 ++ Core/EM/Ahci/AhciSmm/AhciSmm.mak | 82 + Core/EM/Ahci/AhciSmm/AhciSmm.sdl | 24 + Core/EM/Ahci/AhciSources.chm | Bin 0 -> 257910 bytes Core/EM/Ahci/AhciSrc.cif | 19 + Core/EM/Ahci/AhciSrc.mak | 102 + Core/EM/Ahci/AhciSrc.sdl | 105 + Core/EM/Ahci/Aint13.cif | 18 + Core/EM/Ahci/Aint13.inf | 5 + Core/EM/Ahci/Aint13.mak | 105 + Core/EM/Ahci/Aint13.sdl | 67 + 30 files changed, 16611 insertions(+) create mode 100644 Core/EM/Ahci/AInt13.c create mode 100644 Core/EM/Ahci/AInt13.dxs create mode 100644 Core/EM/Ahci/AInt13.h create mode 100644 Core/EM/Ahci/AhciBus.c create mode 100644 Core/EM/Ahci/AhciBus.h create mode 100644 Core/EM/Ahci/AhciComponentName.c create mode 100644 Core/EM/Ahci/AhciController.c create mode 100644 Core/EM/Ahci/AhciController.h create mode 100644 Core/EM/Ahci/AhciInt13Dxe.c create mode 100644 Core/EM/Ahci/AhciInt13Dxe.dxs create mode 100644 Core/EM/Ahci/AhciInt13Smm.c create mode 100644 Core/EM/Ahci/AhciInt13Smm.cif create mode 100644 Core/EM/Ahci/AhciInt13Smm.dxs create mode 100644 Core/EM/Ahci/AhciInt13Smm.h create mode 100644 Core/EM/Ahci/AhciInt13Smm.mak create mode 100644 Core/EM/Ahci/AhciInt13Smm.sdl create mode 100644 Core/EM/Ahci/AhciSmm/AhciSmm.c create mode 100644 Core/EM/Ahci/AhciSmm/AhciSmm.cif create mode 100644 Core/EM/Ahci/AhciSmm/AhciSmm.dxs create mode 100644 Core/EM/Ahci/AhciSmm/AhciSmm.h create mode 100644 Core/EM/Ahci/AhciSmm/AhciSmm.mak create mode 100644 Core/EM/Ahci/AhciSmm/AhciSmm.sdl create mode 100644 Core/EM/Ahci/AhciSources.chm create mode 100644 Core/EM/Ahci/AhciSrc.cif create mode 100644 Core/EM/Ahci/AhciSrc.mak create mode 100644 Core/EM/Ahci/AhciSrc.sdl create mode 100644 Core/EM/Ahci/Aint13.cif create mode 100644 Core/EM/Ahci/Aint13.inf create mode 100644 Core/EM/Ahci/Aint13.mak create mode 100644 Core/EM/Ahci/Aint13.sdl (limited to 'Core/EM/Ahci') diff --git a/Core/EM/Ahci/AInt13.c b/Core/EM/Ahci/AInt13.c new file mode 100644 index 0000000..1df91f1 --- /dev/null +++ b/Core/EM/Ahci/AInt13.c @@ -0,0 +1,1366 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//**************************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/INT13/AInt13.c 25 11/24/14 11:59p Kapilporwal $ +// +// $Revision: 25 $ +// +// $Date: 11/24/14 11:59p $ +// +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/AHCI/INT13/AInt13.c $ +// +// 25 11/24/14 11:59p Kapilporwal +// [TAG] EIP191939 +// [Category] Improvement +// [Description] Issue about BIG_REAL_MODE_MMIO_ACCESS of AHCI module +// [Files] AI13.bin +// AHCIACC.ASM +// AhciInt13Dxe.c +// AhciInt13Dxe.dxs +// AhciInt13Smm.c +// AhciInt13Smm.cif +// AhciInt13Smm.dxs +// AhciInt13Smm.h +// AhciInt13Smm.mak +// AhciInt13Smm.sdl +// AInt13.c +// Aint13.cif +// AInt13.h +// AhciSmm.c +// AhciSmm.h +// AhciSmmProtocol.h +// +// 24 9/10/12 2:50a Rameshr +// [TAG] EIP95440 +// [Category] Improvement +// [Description] Add HddSecurity and HddSmart feature under UEFI Raid +// driver mode +// [Files] Ahcibus.c, Pahcibus.h, Aint13.c +// +// 23 8/02/12 8:11a Deepthins +// [TAG] EIP93480 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] AHCI legacy support module is corrupting the memory. +// [RootCause] AHCI legacy support module is corrupting the memory as it +// was using wrong offset for storing the base address. +// [Solution] Properly calculating offset for storing the base address. +// [Files] AINT13.EQU, AInt13.c, AInt13.h and AHCIACC.ASM +// +// 22 6/02/12 2:53a Anandakrishnanl +// [TAG] EIP91233 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] pBS->CloseEvent(Event) has to be added in function of +// SetEbdaAddressForPort() asit cabn handle the multiple legacy boot +// events. +// [RootCause] CloseEvent not handled properly as SetEbdaAddressForPort +// will be re executed +// [Solution] Event should be closed in SetEbdaAddressForPort when the +// event callback happens +// [Files] AInt13.c +// +// 21 4/24/12 12:53a Deepthins +// [TAG] EIP86336 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Can't boot from AHCI if SATA_PORT_COUNT=12 +// [RootCause] The controller number was not updated in DEV_INFO_STRUC +// for all the Hard Disk +// [Solution] Updated the controller number in the DEV_INFO_STRUC for +// all the AHCI devices. +// [Files] AInt13.c, AInt13.h +// +// 20 1/13/12 12:15a Deepthins +// [TAG] EIP78099 +// [Category] Improvement +// [Description] Handle multiple AHCI controller in legacy. +// [Files] Aint13.sdl , AInt13.c , AInt13.h , AHCIACC.ASM , AHCI.EQU , +// AINT13.bin (AHCIACC.ASM , AINT13.EQU) +// +// 19 11/29/11 4:23a Rameshr +// [TAG] EIP76393 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Any time AHCI is starting when EBDA size is more than 64K, +// the problem will show as memory corruption. +// [RootCause] AHCI INT13 code does not use EBDA properly when at the +// time of EBDA allocation current size of EBDA exceeds 64K +// [Solution] Modified code to extend the width of EbdaStart offset from +// 16-bit to 32-bit. +// [Files] Aint13.asm, Ahcibsp.asm, Aint13.c, Aint13.h, Aint13.bin +// +// 18 6/06/11 2:04a Rameshr +// [TAG]- EIP 57762 +// [Category]-IMPROVEMENT +// [Description]- Please help to put SATA ODD PxCLB and PxCLBU to E820 and +// below 1M. +// [Files]- Aint13.c +// +// 17 2/10/11 10:49a Rameshr +// [TAG] EIP53704 +// [Category] Improvement +// [Description] AMI headers update for Alaska Ahci Driver +// [Files] Aint13.mak +// AInt13.h +// AInt13.c +// +// 16 6/21/10 5:31a Rameshr +// AHCI Legacy booting through MMIO reg. +// EIP 38444 +// +// 15 4/16/10 4:18p Pats +// EIP 30719: Support for the HDD with sector size more than 512bytes. +// +// 14 7/08/09 5:28p Rameshr +// Bugfix in ConfigureHddParameter function. EIP#23599 +// +// 13 7/02/09 10:26a Olegi +// Bugfix in ConfigureHddParameter function. EIP#23599 +// +// 12 4/28/09 5:33p Rameshr +// +// HDD password support in RAID mode +// EIP:20421 +// +// 11 11/26/08 12:24p Olegi +// Added device handle into BBS table. +// +// 10 9/09/08 3:20p Michaela +// Added AHCI_CD_CSM_ID_OFFSET for assigning +// device numbers for CDs/DVDs in order to +// avoid a CSM16 conflict with PATA CD devices, which +// may be present on some systems +// +// 9 6/04/08 11:10a Olegi +// Use externally defined GUIDs instead of redefining them. +// +// 8 5/28/08 9:42a Rameshraju +// Updated the AMI Address. +// +// 7 5/13/08 4:31p Olegi +// Changes related to the latest release of AI13.BIN +// +// 6 5/01/08 1:40p Olegi +// Increase EBDA size by 1KB to be used in runtime for stack. +// +// 5 3/28/08 12:16p Michaela +// updated copyright +// +// 4 28/02/08 6:12p Anandakrishnanl +// Updated for device detection in AHCI mode. +// +// 3 2/09/08 4:41p Olegi +// Modifications related to the changed AllocateEbda interface. +// +// 2 19/12/07 4:32p Anandakrishnanl +// Transition from EDK AHCI driver to AMI AHCI driver. +// +// 1 12/07/07 11:17a Olegi +// +//**************************************************************************** + +// +//********************************************************************** +// +// Name: AInt13.c +// Description: AHCI Int13 structures initialization routines +// +//**************************************************************************** +// + +#include "Aint13.h" +#include "AmiDxeLib.h" + +#include "Protocol\LegacyBiosExt.h" +#include "Protocol\LegacyAhci.h" +#include "Protocol\BlockIo.h" +#include "Protocol\DevicePath.h" +#include "AhciBus.h" + +EFI_STATUS InitDrivesInformation (VOID*, UINT16); + +EFI_AHCI_INT13_INIT_PROTOCOL gAint13; +UINT32 EbdaStartOffset; + +VOID *gLegacyMemoryAddress; +VOID *gImage; +LEGACY16_TO_EFI_DATA_TABLE_STRUC *gLegacy16Data = 0; +EFI_PCI_IO_PROTOCOL *gPciIo = NULL; +UINT8 *gHddReadData; +BOOLEAN gAint13InstallationExecuted = FALSE; + +EFI_STATUS InitAhciInt13Support(); +UINT8 gController=0; +CONTROLLER_INFO_STRUC ControllerInfo[AHCI_CONTROLLER_COUNT]; +EFI_LEGACY_BIOS_EXT_PROTOCOL *gBiosExtensions = NULL; + +// +//--------------------------------------------------------------------------- +// Procedure: Ai13EntryPoint +// +// Description: Installs gAhciInt13Init protocol +// +// Input: IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS Ai13EntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + + InitAmiLib(ImageHandle, SystemTable); + + gAint13.InitAhciInt13Support = InitAhciInt13Support; + + Status = pBS->InstallProtocolInterface( + &ImageHandle, + &gAint13ProtocolGuid, + EFI_NATIVE_INTERFACE, + &gAint13 + ); + + return Status; +} + + +// +//---------------------------------------------------------------------------- +// Procedure: CountDrives +// +// Description: This routine returns the number of connected AHCI drives as well +// as it fills the optional SATA_DEVICE_INTERFACE* buffer with the +// device information. +// +//---------------------------------------------------------------------------- +// + +UINT16 +CountDrives( + IN EFI_HANDLE *HandleBuffer, + IN UINTN HandleCount, + IN VOID *Devices +) +{ + EFI_STATUS Status; + DLINK *dlink; + SATA_DEVICE_INTERFACE *SataDevInterface = NULL; + UINT16 Drives = 0; + UINTN n; + AHCI_BUS_PROTOCOL *AhciBusInterface; + + // + // Go through all controllers, count the number of valid connected drives + // + for (n = 0; n < HandleCount; n++) { + Status = pBS->HandleProtocol(HandleBuffer[n], &gAciBusInitProtocolGuid, &AhciBusInterface); + if (EFI_ERROR(Status)) return Drives; + + for (dlink = AhciBusInterface->SataDeviceList.pHead; dlink; dlink = dlink->pNext) { + SataDevInterface = OUTTER(dlink, SataDeviceLink, SATA_DEVICE_INTERFACE); + if (SataDevInterface->DeviceState == DEVICE_CONFIGURED_SUCCESSFULLY && + (SataDevInterface->DeviceType == ATA || SataDevInterface->DeviceType == ATAPI)) { + if (Devices != NULL) { + *((UINTN*)Devices)++ = (UINTN)SataDevInterface; + } + Drives++; + } + } + } + + return Drives; +} + +// +//---------------------------------------------------------------------------- +// Procedure: SetEbdaAddressForPort +// +// Description: This function will be called when Legacy boot Event Signled +// This function will set the EBDA address for PxCLB and PxFB +// +// Input: IN EFI_EVENT Event - signalled event +// IN VOID *Context - calling context +// +// Output: VOID +// +//---------------------------------------------------------------------------- +// +VOID SetEbdaAddressForPort (IN EFI_EVENT Event, IN VOID *Context) +{ + AHCI_BUS_PROTOCOL *AhciBusInterface=(AHCI_BUS_PROTOCOL*)Context; + UINT32 PortsImplemented; + UINT8 i, PortNumber; + UINT32 CurrentEbda; + UINT32 PortCommandListBaseAddr=0; + UINT32 PortFISBaseAddr=0; + + PortsImplemented = AhciBusInterface->HBAPortImplemented; + PortNumber = 0; + + // + // Find the EBDA Address from the EbdaStartOffset + // + if (EbdaStartOffset) { + CurrentEbda = (UINT32)(UINTN)(*(UINT16*)0x40e << 4); + EbdaStartOffset += CurrentEbda; + EbdaStartOffset += (1024-1); + PortCommandListBaseAddr = EbdaStartOffset & (~(1024-1)); + PortFISBaseAddr=PortCommandListBaseAddr + 1024; + } + + for (i=0; PortsImplemented; PortsImplemented>>=1, PortNumber++){ + if (PortsImplemented & 1) { + + // + // Clear Start + // + HBA_PORT_REG32_AND (AhciBusInterface->AhciBaseAddress, PortNumber, HBA_PORTS_CMD, ~(HBA_PORTS_CMD_ST)); + + // + // Program PxCLB and PxFB + // + HBA_PORT_WRITE_REG32 (AhciBusInterface->AhciBaseAddress, + PortNumber, + HBA_PORTS_CLB, + PortCommandListBaseAddr); + + HBA_PORT_WRITE_REG32 (AhciBusInterface->AhciBaseAddress, + PortNumber, 0x0008, + PortFISBaseAddr); + + i++; + } + } + + pBS->CloseEvent(Event); + + return; +} + +// +//--------------------------------------------------------------------------- +// Procedure: InitAhciInt13Support +// +// Description: LegacyAhci driver API function. It initializes drive infomation +// and places it in BBS table as well as in AHCI INT13 runtime area. +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +InitAhciInt13Support() +{ + EFI_HANDLE *HandleBuffer = 0; + UINTN HandleCount = 0; + UINT16 DevCount = 0; + VOID *Devices; + EFI_STATUS Status; + EFI_EVENT LegacyEvent; + AHCI_BUS_PROTOCOL *AhciBusInterface; + SATA_DEVICE_INTERFACE *Device; + + + // + // First, find out if we have been called already. If yes - do not do anything + // since INT13 installation is not intended to be called multiple times. + // + if (gAint13InstallationExecuted) return EFI_SUCCESS; + + Status = pBS->LocateHandleBuffer( + ByProtocol, + &gAciBusInitProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer); + +// ASSERT_EFI_ERROR(Status); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + DevCount = CountDrives(HandleBuffer, HandleCount, NULL); + // + // For the 1st time CountDrives was called to get the number of connected + // drives; for the 2nd time it will actually return the device information + // + if (DevCount == 0) return EFI_SUCCESS; + + Status = pBS->AllocatePool(EfiBootServicesData, sizeof(VOID*)*DevCount, &Devices); + ASSERT_EFI_ERROR(Status); + + CountDrives(HandleBuffer, HandleCount, Devices); + + Status = InitDrivesInformation(Devices, DevCount); + + // + // Program the EBDA Address on Legacy boot Event. + // + Device = *((SATA_DEVICE_INTERFACE**)Devices); + AhciBusInterface=Device->AhciBusInterface; + CreateLegacyBootEvent(TPL_CALLBACK, &SetEbdaAddressForPort, (VOID*)AhciBusInterface, &LegacyEvent); + + pBS->FreePool(Devices); + + gAint13InstallationExecuted = TRUE; + + return EFI_SUCCESS; + +} + + +// +//--------------------------------------------------------------------------- +// Procedure: GetNumberOfSectors +// +// Description: Returns the total number of sectors from IDENTIFY_DATA +// +// Input: IdendifyData - ptr to the IDENTIFY_DATA array +// +// Output: Total0 - lower DWORD of the total number of blocks +// Total1 - higher WORD of the total number of blocks +// +//--------------------------------------------------------------------------- +// + +VOID +GetNumberOfSectors( + IN UINT16 *IdentifyData, + OUT UINT32 *Total0, + OUT UINT16 *Total1 +) +{ + UINT32 d0 = 0; + UINT16 d1 = 0; + + // + // Get total #of sectors + // Word-61, Word-60 = Total #of user addressable sectors + // Word-103, Word-102, Word-101, Word-100 = Max user LBA for 48bit LBA + // + d0 = *(UINT32*)((UINTN)IdentifyData+60*2); // get Words 60-61 + + // + // If 48-bit LBA enabled then get total number of sectors + // from words 100..102 + // + if (IdentifyData[86] & 0x400) { + d0 = *(UINT32*)((UINTN)IdentifyData+100*2); // get Words 100-101 + d1 = *(UINT16*)((UINTN)IdentifyData+102*2); // get Word 102 + } + + *Total0 = d0; + *Total1 = d1; + +} + + +// +//--------------------------------------------------------------------------- +// Procedure: CalcTranslatedCyl +// +// Description: Returns the CHS-translated number of cylinders +// +//--------------------------------------------------------------------------- +// + +VOID +CalcTranslatedCyl( + IN OUT UINT16 *Cyl, + IN OUT UINT8 *Heads, + IN OUT UINT8 *Sectors, + IN UINT32 TotalBlocks +) +{ + UINT8 heads = *Heads; + UINT8 sec = *Sectors; + UINT16 cyl; + + for (cyl=TotalBlocks/(UINT16)heads*(UINT16)sec; cyl>1024;) { + // + // Current xlat scheme does not make #of cylinders <= 1024, try next scheme + // + cyl = 1024; + if (heads == 0xFF) { + break; // Head limit reached + } + heads <<= 1; // Double the heads + if (heads == 0) heads = 0xFF; + } + *Heads = heads; + *Sectors = sec; + *Cyl = cyl; +} + + +// +//--------------------------------------------------------------------------- +// Procedure: TranslateHdSec +// +// Description: This function returns the translated max #of heads (1-based), +// number of cylinders and sectors/track. +// +// Input: Heads - Maximum head number (1-based) +// Sectors - Sectors/track +// Cyl - Number of cylinders +// TotalBlocks - Total number of sectors +// +// Output: Cyl - Translated number of cylinders +// Heads - Translated max head number (1-based) +// Sectors - Translated number of sectors/track +// +// Notes: - If total #of sectors < 1032192 (i.e. FC000 hex), +// translation is not needed. +// - If total #of sectors <= 2064384 (i.e. 1F8000 hex), +// use 63 SPT and 32 HD for translation. +// - If total #of sectors <= 4128768 (i.e. 3F0000 hex), +// use 63 SPT and 64 HD for translation. +// - If total #of sectors <= 8257536 (i.e. 7E0000 hex), +// use 63 SPT and 128 HD for translation, else +// use 63 SPT and 255 HD for translation. +// - In any case, check the parameters for maximum values allowed +// by BIOS and ATA specs (i.e. 1024 cyl, 16 heads, 63 sec/track) +//--------------------------------------------------------------------------- +// + +VOID +TranslateHdSec( + IN OUT UINT16 *Cyl, + IN OUT UINT8 *Heads, + IN OUT UINT8 *Sectors, + IN UINT32 TotalBlocks +) +{ + UINT8 heads = *Heads; + UINT8 sec = *Sectors; + UINT16 cyl = *Cyl; + + if (TotalBlocks >= 0xFC000) { + heads = 32; sec = 63; + if (TotalBlocks >= 0x1F8000) { + heads = 64; sec = 63; + if (TotalBlocks >= 0x3F0000) { + heads = 128; sec = 63; + if (TotalBlocks >= 0x7E0000) { + heads = 255; sec = 63; + } + } + } + CalcTranslatedCyl(&cyl, &heads, &sec, TotalBlocks); + } + else { + // hd <= 528MB, no translation is needed normally + // check maxm value of the parameters + if (cyl>1024 || heads>16 || sec>63) { + heads = 32; sec = 63; + CalcTranslatedCyl(&cyl, &heads, &sec, TotalBlocks); + } + } + *Heads = heads; + *Sectors = sec; + *Cyl = cyl; +} + + +// +//--------------------------------------------------------------------------- +// Procedure: ConfigureHddParameter +// +// Description: This function fills the DEV_PARAM information for the drive. +// +//--------------------------------------------------------------------------- +// + +VOID +ConfigureHddParameter( + IN EFI_BLOCK_IO_PROTOCOL *BlkIo, + IN UINT16 *IdentifyData, + IN OUT DEV_PARAM_STRUC *DevParam, + IN DEV_INFO_STRUC *DevInfo, + IN DEV_PTR_STRUC *DevPtr +) +{ + EFI_STATUS Status; + UINT8 PartNo; + UINT8 *PartPtr; + UINT8 *NonActivePartPtr = NULL; + UINT32 OemName; + BOOLEAN ValidTable = FALSE; + BOOLEAN ValidMBR=FALSE; + UINT8 heads, sec; + UINT16 cyl; + UINT16 SecTimesHeads; + UINT32 TotalBlocks; + + // + // Check whether the hard disk is already formatted. If already formatted, + // find out what mode it was formatted with. + // + if(BlkIo == NULL ) { + return; + } + Status = BlkIo->ReadBlocks(BlkIo, BlkIo->Media->MediaId, 0, 0x200, gHddReadData); + if (!EFI_ERROR(Status) && (*(UINT16*)(gHddReadData+0x1FE) == 0xAA55)) { + // + // Drive has a partition table, take parameter from 1st bootable partition + // + PartPtr = gHddReadData+0x1BE; + + for (PartNo=0; PartNo<4; PartNo++, PartPtr+=0x10) { + if ((*PartPtr) == 0x80) { + ValidTable = TRUE; + break; + } + if (((*(UINT16*)(PartPtr+5)) & 0x3F00) == 0) { + // not well formed paritioned table, end sector# = 0 + continue; + } + if (NonActivePartPtr == NULL) { + NonActivePartPtr = PartPtr; + } + } + + if (!ValidTable && (NonActivePartPtr != NULL)) { + // + // No active partition found, use 1st non-active valid partition + // + PartPtr = NonActivePartPtr; + ValidTable = TRUE; + } + + if (ValidTable) { + // + // Either active or first non-active entry found at PartPtr + // Read it at gHddReadData + 0xE00 + // + Status = BlkIo->ReadBlocks(BlkIo, BlkIo->Media->MediaId, + *(UINT32*)(PartPtr+8), 0x200, gHddReadData+0x800); + if (!EFI_ERROR(Status) && (*(UINT16*)(gHddReadData+0x800+0x1FE) == 0xAA55)) { + // + // Read succeeded so the drive is formatted; check for + // valid MSDOS/MSWIN/NTFS boot record + // + OemName = *(UINT32*)(gHddReadData+0x800+3); + + // 'ODSM' for MSDO + // 'IWSM' for MSWI + // 'SFTN' for NTFS + if((OemName == 0x4F44534D) || (OemName == 0x4957534D) || (OemName == 0x5346544E)) { + ValidMBR=TRUE; + } else { + // Check for valid FAT,FAT16,FAT32 boot records + *(gHddReadData+0x800+0x36+3) = 0x20; // Ignore the 4th byte and fill it with space + if ((*(UINT32*)(gHddReadData+0x800+0x36) == 0x20544146) // " TAF" for FATx + || (*(UINT32*)(gHddReadData+0x800+0x52) == 0x33544146)) // "3TAF" for FAT3 + { + ValidMBR = TRUE; + } + } + } + if (ValidMBR) { + heads = *(gHddReadData+0x800+0x1A); // number of heads + sec = *(gHddReadData+0x800+0x18); // Sectors/track + SecTimesHeads = heads * sec; + if (SecTimesHeads == 0) { + ValidMBR = FALSE; + } else { + // + // Here we have heads/sectors info from partition boot record of known OSes. + // NOTE: sectors/track and #of heads is the information with which + // the concerned partition was created. This information must be used to + // calculate #of cylinders to maintain the current translation scheme. + // + + // Find the total #of sectors in the hard disk C * H * S + TotalBlocks = DevParam->bMAXHN * DevParam->bMAXSN * DevParam->wMAXCYL; + // Calculate #of cylinders using the same translation scheme + cyl = TotalBlocks / SecTimesHeads; + if (cyl>1024) cyl = 1024; + } + } + } + } + + if (!ValidMBR) { + // + // Hard disk was not formatted OR no valid partition table entry was found; + // find the translation scheme which will be used for the hard disk. + // + cyl = DevParam->wMAXCYL; + heads = DevParam->bMAXHN; + sec = DevParam->bMAXSN; + TotalBlocks = cyl * sec * heads; + + TranslateHdSec(&cyl, &heads, &sec, TotalBlocks); + } + + + DevParam->wLBACYL = DevParam->wMAXCYL; + DevParam->bLBAHD = DevParam->bMAXHN; + DevParam->bLBASPT = DevParam->bMAXSN; + + DevParam->wMAXCYL = cyl; + DevParam->bMAXHN = heads; + DevParam->bMAXSN = sec; + + if (heads > 8) { + DevParam->bCBYTE = 8; // More than 8 heads indication + } +} + + +// +//--------------------------------------------------------------------------- +// Procedure: InitAhciHddDev +// +// Description: This function initializes the AHCI HD drive specific information. +// +//--------------------------------------------------------------------------- +// + +VOID +InitAhciHddDev ( + IN SATA_DEVICE_INTERFACE *Dev, + IN DEV_PARAM_STRUC *DevParam, + IN DEV_INFO_STRUC *DevInfo, + IN DEV_PTR_STRUC *DevPtr, + AHCI_RT_MISC_DATA *AhciRtMiscData +) +{ + UINT16 *IdentifyData; + UINT32 d0; + UINT16 d1; + UINT8 DevNo; + UINT32 SegOfs; + UINT16 heads, spt, cyl; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + UINT32 Temp; + UINT8 Temp2 = 0; + + IdentifyData = (UINT16*)&Dev->IdentifyData; + + heads = IdentifyData[3]; + spt = IdentifyData[6]; + ASSERT((heads<255) && (spt<255)); // Both heads & sectors/track must be 8-bit + + // + // Save AHCI HD Mode Information + // + DevInfo->bPIOInfo = (UINT8)IdentifyData[64]; + DevInfo->bUDMAInfo = (UINT8)IdentifyData[88]; + + cyl = IdentifyData[1]; + + DevParam->wMAXCYL = cyl; + DevParam->bMAXHN = (UINT8)heads; + DevParam->bMAXSN = (UINT8)spt; + + GetNumberOfSectors(IdentifyData, &d0, &d1); + DevInfo->dTotalSectorsLo = d0; + DevInfo->dTotalSectorsHi = (UINT32)d1; + + DevNo = AhciRtMiscData->NumAhciDevice++; + DevInfo->bInt13Num = DevNo | 0x80; + DevPtr->bInt13Num = DevNo | 0x80; + DevPtr->bPMnum = Dev->PortNumber; + DevPtr->bPortNum = Dev->PMPortNumber; + // + // Update SEG:OFS address for current DevParam and DevInfo + // + SegOfs = ((UINT32)gLegacyMemoryAddress<<12)+(UINT32)((UINTN)DevParam-(UINTN)gImage); + DevPtr->dParamTablePtr = SegOfs; + + SegOfs = ((UINT32)gLegacyMemoryAddress<<12)+(UINT32)((UINTN)DevInfo-(UINTN)gImage); + DevPtr->dInfoTablePtr = SegOfs; + + // + // Indicate device is LBA capable + // Note: Non-LBA device are not supported in this release + // + DevInfo->bSelector |= SELECTOR_LBA; + + // + // Check whether device is 48-bit LBA capable + // + if (IdentifyData[86] & 0x400) { + DevInfo->bInfoFlag |= INFO_LBA_48; + } + // + // Update sector size if necessary + // + if ( (IdentifyData[106] & 0x4000) && (!(IdentifyData[106] & 0x8000)) && (IdentifyData[106] & 0x1000) ) { + Temp = (UINT32)(IdentifyData[117] + (IdentifyData[118] << 16)) * 2; + while (Temp > 1) { + Temp = Temp >> 1; + Temp2++; + } + DevInfo->bSectorSizeN = Temp2; + } + // + // Note: Interrupt driven mechanism is not supported + // + DevInfo->bInfoFlag &= ~(INFO_IRQ); + + // + // Do the LBA to CHS translation; use BlkIo to read partition/boot record + // + BlkIo = &Dev->SataBlkIo->BlkIo; + ConfigureHddParameter(BlkIo, IdentifyData, DevParam, DevInfo, DevPtr); +} + + +// +//--------------------------------------------------------------------------- +// Procedure: InitAhciCd +// +// Description: This function initializes AHCI CD/DVDROM device information. +// +//--------------------------------------------------------------------------- +// + +VOID +InitAhciCd( + IN SATA_DEVICE_INTERFACE *Dev, + IN DEV_PARAM_STRUC *DevParam, + IN DEV_INFO_STRUC *DevInfo, + IN DEV_PTR_STRUC *DevPtr, + AHCI_RT_MISC_DATA *AhciRtMiscData +) +{ + UINT8 DevNo; + UINT32 SegOfs; + + DevNo = AhciRtMiscData->NumAhciDevice++; + DevInfo->bInt13Num = (DevNo + AHCI_CD_CSM_ID_OFFSET) | BIT7 ; + DevPtr->bInt13Num = (DevNo + AHCI_CD_CSM_ID_OFFSET) | BIT7; + DevPtr->bPMnum = Dev->PortNumber; + DevPtr->bPortNum = Dev->PMPortNumber; + // + // Update SEG:OFS address for current DevParam and DevInfo + // + SegOfs = ((UINT32)gLegacyMemoryAddress<<12)+(UINT32)((UINTN)DevParam-(UINTN)gImage); + DevPtr->dParamTablePtr = SegOfs; + + SegOfs = ((UINT32)gLegacyMemoryAddress<<12)+(UINT32)((UINTN)DevInfo-(UINTN)gImage); + DevPtr->dInfoTablePtr = SegOfs; +} + +// +//--------------------------------------------------------------------------- +// Procedure: UpdateControllerInfoToLegacy +// +// Description: This function will check if the BusDevFunc is existing in +// the array, if it exist then it returns EFI_SUCCESS and if not then +// it will add BusDevFunc into the array and returns EFI_NOT_FOUND. +// +// Input: Dev - Structure pointing to SATA_DEVICE_INTERFACE +// DevInfo - Stucture that maintatin device information +// wBusDevFunc - It contatin the BusDevFunc number for a device +// +// Output: EFI_NOT_FOUND - If wBusDevFunc is not present in the array. +// i.e a new controller is found +// EFI_SUCCESS - If wBusDevFunc is present in the array +// +//--------------------------------------------------------------------------- +// +VOID +UpdateControllerInfoToLegacy( + IN SATA_DEVICE_INTERFACE *Dev, + IN DEV_INFO_STRUC *DevInfo, + IN UINT16 wBusDevFunc + ) +{ + UINT8 i; + EFI_STATUS Status; + UINT32 Addr16=0; + UINT16 *TempAddress; + + for(i=0;ibControllerNo=ControllerInfo[i].ControllerNo; + return; + } + } + + // + // A new controller is found so BusDevFunc and ControllerNo is added + // into the array of structure. + // + ControllerInfo[gController].BusDevFun = wBusDevFunc; + ControllerInfo[gController].ControllerNo = gController; + DevInfo->bControllerNo= gController++; + + // + // Store the current controller's PciIO in global variable + // + gPciIo = Dev->AhciBusInterface->PciIO; + Status = gBiosExtensions->Get16BitFuncAddress( + CSM16_CSP_AHCI_ACCESSHBA, + &Addr16 + ); + + // + //At 'Addr16+2' there is a pointer that point to the structure + //that maintains index, data and base address for a controller + // + TempAddress=(UINT16*)(Addr16+2); + Addr16=Addr16 + (*TempAddress); + + // + // No Addr16 points to ReadWriteRegisterDword routine implemented in + // AHCIACC.ASM in CSP module part + // + if (!EFI_ERROR(Status)) { + Status = InitCspData((UINT16)((Addr16>>4) & 0xF000), (UINT16)Addr16, (UINT32)(Dev->AhciBusInterface->AhciBaseAddress),DevInfo->bControllerNo); + ASSERT_EFI_ERROR(Status); + } + + return; +} + +// +//--------------------------------------------------------------------------- +// Procedure: InitAhciDev +// +// Description: This function initializes AHCI device specific information. +// +//--------------------------------------------------------------------------- +// + +VOID +InitAhciDev( + IN SATA_DEVICE_INTERFACE *Dev, + IN DEV_PARAM_STRUC *DevParam, + IN DEV_INFO_STRUC *DevInfo, + IN DEV_PTR_STRUC *DevPtr, + AHCI_RT_MISC_DATA *AhciRtMiscData +) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN seg, bus, dev, func; + UINT8 bIrq; + UINT32 dHbaBase; + UINT8 bPort; + EFI_STATUS Status; + + PciIo = Dev->AhciBusInterface->PciIO; + + bPort = Dev->PortNumber; + DevInfo->bPortNum = bPort; + DevInfo->bPMNum = Dev->PMPortNumber; + + Status = PciIo->Pci.Read(PciIo, EfiPciIoWidthUint8, 0x3C, 1, &bIrq); + ASSERT_EFI_ERROR(Status); + DevInfo->bIrq = bIrq; + + Status = PciIo->GetLocation(PciIo, &seg, &bus, &dev, &func); + ASSERT_EFI_ERROR(Status); + DevInfo->wBusDevFunc = ((UINT16)bus<<8) + ((UINT16)dev<<3) + (UINT16)func; + + // + // Pass the Controller Information to Legacy. + // + UpdateControllerInfoToLegacy(Dev,DevInfo,DevInfo->wBusDevFunc); + + DevInfo->dHbaCap = Dev->AhciBusInterface->HBACapability; + DevInfo->bSelector = SELECTOR_NON_LBA; + DevInfo->bSectorSizeN = SECTOR_LENGTH_N; // N value of default sector size 2^N; + dHbaBase = (UINT32)Dev->AhciBusInterface->AhciBaseAddress; + DevInfo->dHbaBase = dHbaBase; + DevInfo->dPortBase = dHbaBase + PORT_REGISTER_START + ((UINT32)bPort<DeviceType == ATAPI) { + DevInfo->bInfoFlag |= INFO_ATAPI; + InitAhciCd(Dev, DevParam, DevInfo, DevPtr, AhciRtMiscData); + } else { + InitAhciHddDev(Dev, DevParam, DevInfo, DevPtr, AhciRtMiscData); + } +} + + +// +//--------------------------------------------------------------------------- +// Procedure: CreateAhciDriveString +// +// Description: This function generates the readable string with the name of +// device and the SATA port number this device is connected to. +// +//--------------------------------------------------------------------------- +// + +VOID +CreateAhciDriveString( + IN OUT UINT8 *DescString, + IN UINT16 *IdentifyData, + IN UINT8 DevicePortNum, + IN UINT8 DevicePortMulNum +) +{ + UINT8 s[MAX_DESCRIPTION_STRLEN] = "xP :"; + UINT8 i, data8; + + s[0] = DevicePortNum+0x30; + + // Get the drive name out of IdentifyDrive data word 27..46 (upto 40 chars) + pBS->CopyMem(&s[4], IdentifyData+27, MAX_DESCRIPTION_STRLEN-5); + // Swap the bytes + for (i=0; iCopyMem(DescString, s, MAX_DESCRIPTION_STRLEN); +} + + +// +//--------------------------------------------------------------------------- +// Procedure: CreateBbsEntry +// +// Description: This function creates BBS entry with the device data filled +// according to the actual device information. +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +CreateBbsEntry( + IN SATA_DEVICE_INTERFACE *Dev, + IN OUT DEV_BBS_OUTFIT *DevOutfit, + IN OUT BBS_TABLE *BbsEntry, + IN UINT8 Int13Handle, + IN UINT16 BcvOffset +) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN seg, bus, dev, func; + EFI_STATUS Status; + UINT8 dData[4]; + UINT8 bDevAndSysType; + UINT8 bHandle; + UINT8 bMasterSlave = 0; + UINT8 bBaidDeviceType; + + pBS->SetMem(BbsEntry, sizeof(BBS_TABLE), 0); + + // + // Get PCI location + // + PciIo = Dev->AhciBusInterface->PciIO; + Status = PciIo->GetLocation(PciIo, &seg, &bus, &dev, &func); + BbsEntry->Bus = (UINT32)bus; + BbsEntry->Device = (UINT32)dev; + BbsEntry->Function = (UINT32)func; + + // + // Get class/subclass information + // + Status = PciIo->Pci.Read( + PciIo, + EfiPciIoWidthUint32, + 8, // offset + 1, // width + &dData); + ASSERT_EFI_ERROR(Status); + + BbsEntry->Class = dData[3]; + BbsEntry->SubClass = dData[2]; + + CreateAhciDriveString( + DevOutfit->DescString, + (UINT16*)&Dev->IdentifyData, + Dev->PortNumber, + Dev->PMPortNumber + ); + + BbsEntry->DescStringSegment = (UINT16)((UINTN)gLegacyMemoryAddress >> 4); + BbsEntry->DescStringOffset = (UINT16)((UINTN)DevOutfit->DescString-(UINTN)gImage); + + bDevAndSysType = (SYSTYPE_ATA << 4)+DEVTYPE_SYS; + bHandle = Int13Handle; + + if (Dev->DeviceType == ATAPI) { + bBaidDeviceType = BAID_TYPE_CDROM; + BbsEntry->DeviceType = BBS_CDROM; + BbsEntry->BootHandlerSegment = 0xF000; + BbsEntry->BootHandlerOffset = gLegacy16Data->CdrBevOffset; + + } else { + BbsEntry->DeviceType = BBS_HARDDISK; + bBaidDeviceType = BAID_TYPE_HDD; + BbsEntry->BootHandlerSegment = (UINT16)((UINTN)gLegacyMemoryAddress >> 4); + BbsEntry->BootHandlerOffset = BcvOffset + (Int13Handle & 0x7F)*4; + } + + BbsEntry->InitPerReserved = ((UINT32)bBaidDeviceType<<24) + +((UINT32)bMasterSlave<<16) + +((UINT32)bHandle<<8) + +(UINT32)bDevAndSysType; + + *(UINTN*)(&BbsEntry->IBV1) = (UINTN)Dev->IdeDeviceHandle; + + return EFI_SUCCESS; +} + + +// +//--------------------------------------------------------------------------- +// +// Name: InitDrivesInformation +// +// Description: Initialization of data structures and placement of runtime +// code of AHCI INT13 +// +// Input: Devices - pointer to the beginning of the instances of +// SATA_DEVICE_INTERFACE* +// DeviceCount - number of valid AHCI devices pointed by +// Devices parameter +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +InitDrivesInformation( + IN VOID *Devices, + IN UINT16 DeviceCount +) +{ + EFI_LEGACY_BIOS_PROTOCOL *Bios = NULL; + UINTN ImageSize; + EFI_STATUS Status; + AHCI_I13_RTDATA *Ai13Data; + UINTN Count, i; + UINT32 EbdaAddress; + BBS_TABLE BbsEntry; + UINT32 LockUnlockAddr, LockUnlockSize; + UINT16 CheckForAhciCdromOffset; + UINT32 CheckForAhciCdromAddress; + UINT8 *addr; + SATA_DEVICE_INTERFACE *Device; + UINT8 PciConfig[16]; + + + if (DeviceCount == 0) return EFI_SUCCESS; // No devices connected + + Status = pBS->LocateProtocol( + &gEfiLegacyBiosProtocolGuid, NULL, &Bios); + if (EFI_ERROR(Status)) return Status; + + // + // Get the AHCI INT13 runtime image + // + Status = pBS->LocateProtocol( + &gEfiLegacyBiosExtProtocolGuid, NULL, &gBiosExtensions); + if (EFI_ERROR(Status)) return Status; + + Status = gBiosExtensions->GetEmbeddedRom( + CSM16_MODULEID, CSM16_VENDORID, CSM16_AHCI_RT_DID, &gImage, &ImageSize); + if (EFI_ERROR(Status)) return Status; + + // + // Instantiate data area + // + Ai13Data = (AHCI_I13_RTDATA*)gImage; + + // + // Fill the data area with the init values + // + pBS->SetMem(Ai13Data, sizeof (AHCI_I13_RTDATA), 0); + pBS->SetMem(Ai13Data->DevPtr, sizeof(DEV_PTR_STRUC)*SATA_PORT_COUNT, 0xFF); + + // + // Allocate legacy region in E000 segment; store SEG:OFS of the allocated + // memory in global variables + // + Status = Bios->GetLegacyRegion(Bios, ImageSize, 2, 0x10, &gLegacyMemoryAddress); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) return Status; + + // + // Allocate EBDA area for Command List/Command Table/FIS + // + Status = gBiosExtensions->AllocateEbda( + gBiosExtensions, + SIZE_CLCTFIS_AREA_K+1, // 1K extra for stack + &EbdaAddress, + &EbdaStartOffset ); + ASSERT_EFI_ERROR(Status); + +#if AINT13_AVOID_MULTIPLE_SMI + Ai13Data->AhciRtMiscData.RunAttribute |= A_INT13_SWSMI_USED; + Ai13Data->AhciRtMiscData.AhciSmmRt.MiscInfo = 1; + Ai13Data->AhciRtMiscData.AhciSmmRt.SmmAttr = 0; + Ai13Data->AhciRtMiscData.AhciSmmRt.SmmPort = SW_SMI_IO_ADDRESS; + Ai13Data->AhciRtMiscData.AhciSmmRt.SmmData = AHCI_INT13_SMM_SWSMI_VALUE; +#endif + + Ai13Data->AhciRtMiscData.AhciEbdaStart = EbdaStartOffset; + Ai13Data->AhciRtMiscData.RunAttribute |= A_EBDA_USED; + + gBiosExtensions->UnlockShadow( + (UINT8*)gLegacyMemoryAddress, ImageSize, + &LockUnlockAddr, &LockUnlockSize); + + gLegacy16Data = (LEGACY16_TO_EFI_DATA_TABLE_STRUC*)(UINTN)(0xF0000 + *(UINT16*)0xFFF4C); + + Status = pBS->AllocatePool(EfiBootServicesData, 0x1000, &gHddReadData); + ASSERT_EFI_ERROR(Status) + + // + // Here is a tricky part: we will have to convert the data passed by Ahci Bus + // driver to the data used by INT13 + // + for (Count=0, i=0; iDevParam[Count], + &Ai13Data->DevInfo[Count], + &Ai13Data->DevPtr[Count], + &Ai13Data->AhciRtMiscData + ); + + Status = gPciIo->Pci.Read ( gPciIo, + EfiPciIoWidthUint8, + 0, + sizeof (PciConfig), + PciConfig + ); + + // + //Under Raid mode ATA devices are not added into BBS table. + // + if((PciConfig [IDE_SUB_CLASS_CODE]!= SCC_RAID_CONTROLLER) || (Device->DeviceType != ATA)) { + Status = CreateBbsEntry(Device, + &Ai13Data->DevOutfit[Count], + &BbsEntry, + Ai13Data->DevPtr[Count].bInt13Num, + ((AHCI_I13_DATA*)Ai13Data)->AhciBcvOffset + ); + + ASSERT_EFI_ERROR(Status); + + Status = gBiosExtensions->AddBbsEntry(&BbsEntry); + ASSERT_EFI_ERROR(Status); + } + + Count++; + if (Count==SATA_PORT_COUNT) break; + } + + // + // Patch farReturnCDROMSupportAPIPointer routine with "call farCheckForAHCICdrom" + // + CheckForAhciCdromOffset = ((AHCI_I13_DATA*)Ai13Data)->CheckForAhciCdromOffset; + CheckForAhciCdromAddress = + (UINT32)((UINTN)gLegacyMemoryAddress<<12) + (UINT32)CheckForAhciCdromOffset; + + addr = (UINT8*)(UINTN)(0xF0000+gLegacy16Data->CDROMSupportAPIOfs+10); + *addr++ = 0x9A; // far call opcode + *(UINT32*)addr = CheckForAhciCdromAddress; + + // + // Copy the image into the shadow + // + pBS->CopyMem(gLegacyMemoryAddress, gImage, ImageSize); + + gBiosExtensions->LockShadow(LockUnlockAddr, LockUnlockSize); + + pBS->FreePool(gHddReadData); + + return EFI_SUCCESS; +} + + +// +//--------------------------------------------------------------------------- +// +// Name: InitCspData +// +// Description: Initialization of chipset specific fields of AHCI runtime +// (INT 13) code. +// +// Input: Seg16, Ofs16 - 16-bit address of chipset specific 16-bit code/data. +// +// Output: Status of operation +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +InitCspData( + IN UINT16 Seg16, + IN UINT16 Ofs16, + IN UINT32 BaseAddress, + IN UINT8 ControllerNumber + +) +{ + UINT16 indx, data; + UINT16 *addr; + EFI_STATUS Status; + + ASSERT(gPciIo); + + // + // Calculate the address according to the segment ,offset and controller + // number. + addr = (UINT16*)(UINTN)(((UINTN)Seg16<<4)+(UINTN)Ofs16)+ 4*(ControllerNumber); + + // + // Update the Ahci Base Address + // + *(UINT32*)(addr+2)=BaseAddress; + + Status = GetAccessInfo (gPciIo, &indx, &data); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Update the Index and Data Port + // + *addr++ = indx; + *addr = data; + return EFI_SUCCESS; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AInt13.dxs b/Core/EM/Ahci/AInt13.dxs new file mode 100644 index 0000000..877fea3 --- /dev/null +++ b/Core/EM/Ahci/AInt13.dxs @@ -0,0 +1,37 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** +#include "token.h" +#ifdef CSM_SUPPORT +#include +#endif + +DEPENDENCY_START +#if CSM_SUPPORT + EFI_LEGACY_BIOS_PROTOCOL_GUID +#endif +DEPENDENCY_END + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/Ahci/AInt13.h b/Core/EM/Ahci/AInt13.h new file mode 100644 index 0000000..a55d3d0 --- /dev/null +++ b/Core/EM/Ahci/AInt13.h @@ -0,0 +1,395 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//**************************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/INT13/AInt13.h 17 11/25/14 12:00a Kapilporwal $ +// +// $Revision: 17 $ +// +// $Date: 11/25/14 12:00a $ +// +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/AHCI/INT13/AInt13.h $ +// +// 17 11/25/14 12:00a Kapilporwal +// [TAG] EIP191939 +// [Category] Improvement +// [Description] Issue about BIG_REAL_MODE_MMIO_ACCESS of AHCI module +// [Files] AI13.bin +// AHCIACC.ASM +// AhciInt13Dxe.c +// AhciInt13Dxe.dxs +// AhciInt13Smm.c +// AhciInt13Smm.cif +// AhciInt13Smm.dxs +// AhciInt13Smm.h +// AhciInt13Smm.mak +// AhciInt13Smm.sdl +// AInt13.c +// Aint13.cif +// AInt13.h +// AhciSmm.c +// AhciSmm.h +// AhciSmmProtocol.h +// +// 16 11/29/12 12:58a Rameshr +// [TAG] EIP107365 +// [Category] Improvement +// [Description] Increase the SATA_PORT_COUNT to 32 to support 32 SATA +// devices on Legacyboot +// [Files] Aint13.h, Ahci.sdl ( Ain13.bin) +// +// 15 8/02/12 8:12a Deepthins +// [TAG] EIP93480 +// [Category] Bug Fix +// [Symptom] AHCI legacy support module is corrupting the memory. +// [RootCause] AHCI legacy support module is corrupting the memory as it +// was using wrong offset for storing the base address. +// [Solution] Properly calculating offset for storing the base address. +// [Files] AINT13.EQU, AInt13.c, AInt13.h and AHCIACC.ASM +// +// 14 7/20/12 6:12a Anandakrishnanl +// [TAG] EIP88683 +// [Category] New Feature +// [Description] EFI_ATA_PASS_THRU_PROTOCOL Support for Aptio IDE +// [Files] AhciBus.c +// AhciBus.h +// AInt13.h +// IdeBus.c +// IdeBus.h +// PIDEBus.h +// PAhciBus.h +// AtaPassThru.sdl +// AtaPassThru.mak +// AtaPassThru.c +// AtaPassThruSupport.h +// AtaPassThru.chm +// +// 13 4/24/12 12:54a Deepthins +// [TAG] EIP86336 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Can't boot from AHCI if SATA_PORT_COUNT=12 +// [RootCause] The controller number was not updated in DEV_INFO_STRUC +// for all the Hard Disk +// [Solution] Updated the controller number in the DEV_INFO_STRUC for +// all the AHCI devices. +// [Files] AInt13.c, AInt13.h +// +// 12 1/13/12 12:18a Deepthins +// [TAG] EIP78099 +// [Category] Improvement +// [Description] Handle multiple AHCI controller in legacy. +// [Files] Aint13.sdl , AInt13.c , AInt13.h , AHCIACC.ASM , AHCI.EQU , +// AINT13.bin (AHCIACC.ASM , AINT13.EQU) +// +// 11 11/29/11 4:27a Rameshr +// [TAG] EIP76393 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Any time AHCI is starting when EBDA size is more than 64K, +// the problem will show as memory corruption. +// [RootCause] AHCI INT13 code does not use EBDA properly when at the +// time of EBDA allocation current size of EBDA exceeds 64K +// [Solution] Modified code to extend the width of EbdaStart offset from +// 16-bit to 32-bit. +// [Files] Aint13.asm, Ahcibsp.asm, Aint13.c, Aint13.h, Aint13.bin +// +// 10 2/10/11 10:49a Rameshr +// [TAG] EIP53704 +// [Category] Improvement +// [Description] AMI headers update for Alaska Ahci Driver +// [Files] Aint13.mak +// AInt13.h +// AInt13.c +// +// 9 6/21/10 5:32a Rameshr +// AHCI Legacy booting through MMIO reg. +// EIP 38444 +// +// 8 9/09/08 3:19p Michaela +// Added AHCI_CD_CSM_ID_OFFSET for assigning +// device numbers for CDs/DVDs in order to +// avoid a CSM16 conflict with PATA devices, which +// may be present on some systems +// +// 7 5/28/08 9:41a Rameshraju +// Updated the AMI Address. +// +// 6 5/13/08 4:31p Olegi +// Modifications in DEV_PARAM_STRUC and DEV_PTR_STRUC to accomodate the +// new AI13.BIN that is based on the latest AHCI Core8 src. +// +// 3 3/28/08 12:16p Michaela +// updated copyright +// +// 2 19/12/07 4:29p Anandakrishnanl +// +// 1 12/07/07 11:17a Olegi +// +//**************************************************************************** + +#ifndef __AI13_HEADER__ +#define __AI13_HEADER__ + +#include "efi.h" +#include "Protocol\PciIo.h" + +#pragma pack(1) + +// +//--------------------------------------------------------------------------- +// +// Name: AINT13.H +// Description: Definitions and structures for AHCI INT13 +// +//--------------------------------------------------------------------------- +// + +typedef struct _DEV_INFO_STRUC { + UINT8 bDetectType; // Detected Device Type (Details Below) + UINT8 bInstalledType; // Device Installed Type (See Below) + UINT16 wStatus; // Bit-mapped device Init Status (Details Below) + UINT8 bInt13Num; // Device# for INT13 (8xh) + UINT8 bPMNum; // Port Multipier Port # + UINT8 bPortNum; // SATA Port# (0-Based) where device is present + UINT16 wBusDevFunc; // Bus#, Dev#, Func# of Controller + UINT8 bControllerNo; // Ahci Controller number + UINT32 dHbaBase; // HBA Base Address of Generic Host Control Registers + UINT32 dHbaCap; // HBA Capabilities + UINT32 dPortBase; // Base Address of SATA port where device is present + UINT8 bSelector; // Device selector value + UINT8 bIrq; // IRQ used by this device + UINT8 bInfoFlag; // Information Flag (details below) + UINT8 bSectorSizeN; // N value of Sector size 2^N ;For 512bytes sector, N = 9 + UINT16 wSmartInfo; // SMART info (details below) + UINT32 dTotalSectorsLo;// Total #of sectors in device (1-based) + UINT32 dTotalSectorsHi; + UINT16 wXferCount; // Device transfer count. Used for ATAPI packer size + UINT8 bBlockInfo; + UINT8 b32BitInfo; + UINT8 bUDMAInfo; + UINT8 bPIOInfo; +} DEV_INFO_STRUC; + +typedef struct _CONTROLLER_INFO_STRUC +{ + UINT16 BusDevFun; // Bus, Device and Function number for a controller + UINT8 ControllerNo; // Controler number for a controller +}CONTROLLER_INFO_STRUC; + +// Details of bDetectType + +#define DETECT_NO 0 +#define DETECT_ATA 1 +#define DETECT_ATAPI_CD 2 +#define DETECT_ATAPI_ARMD 3 + +// Details of bInstalledType + +#define INSTALLED_NO 0 +#define INSTALLED_HDD 1 +#define INSTALLED_CDROM 2 +#define INSTALLED_ARMD_FDD 3 +#define INSTALLED_ARMD_HDD 4 + +// Details of wStatus + +// Bit 0 = 1, successful (device is installed in this case) +// Bit 1 = 1, Identify Device Failed +// Bit 2 = 1, Invalid Device Geometry +// Bit 3 = 1, Init device parameter failed +// Bit 4 = 1, Recalibrate failed +// Bit 5 = 1, SMART failed +// Bit 6 = 1, Verify failed +// Bit 7 = 1, Security Freeze Lock failed +// Bit 8 = 1, Port Reset failed +// Bit 9 = 1, SMART Event was found +// Bit 10 = 1, Device will be supported by RIAD OROM, not AHCI OROM (ex. HDD) +// Bit 14-11, Reserved for future use +// Bit 15 = 1, Device not supported + +#define ST_SUCCESS 0x0001 +#define ST_ID_DEV_ERR 0x0002 +#define ST_DEV_GEOMETRY_ERR 0x0004 +#define ST_INIT_DEV_PARAM_ERR 0x0008 +#define ST_RECALI_ERR 0x0010 +#define ST_SMART_ERR 0x0020 +#define ST_VERIFY_ERR 0x0040 +#define ST_FREEZE_LOCK_ERR 0x0080 +#define ST_PORT_RESET_ERR 0x0100 +#define ST_SMART_EVENT 0x0200 +#define ST_RAID_SUPPORT_ERR 0x0400 +#define ST_NOT_SUPPORT_ERR 0x8000 + + +// Details of bInt13Num + +// Bit 7 = 1, this bit must be set for CDs/HDDs +// AHCI_CD_CSM_ID_OFFSET, PATA CDs/DVDs use the device handle range 0x80-0x8F +// so this value will be added to ensure AHCI CDs/DVDs +// are above that range + +#define AHCI_CD_CSM_ID_OFFSET 0x10 + + +// Details of bInfoFlag, a bit-mapped field + +// Bit 0 = 1, Device supports removable media +// Bit 1 = 1, 48bit LBA enabled +// Bit 2 = 1, Device uses IRQ; 0, Device uses DRQ +// Bit 6-2, Reserved +// Bit 7 = 1, ATAPI Device; 0, ATA Device + +#define INFO_REMOVABLE 0x01 +#define INFO_LBA_48 0x02 +#define INFO_IRQ 0x04 +#define INFO_ATAPI 0x80 + +// Details wSmartInfo + +// Bit 0 = 0/1, SMART (Not Supported/Supported) +// Bit 1 = 0/1, SMART (Disabled/Enabled) +// Bit 2 = 0/1, Device Status Good/Bad +// Bit 7 = 0/1, SMART Execution Successful/Error +// Bit 15-8, Reserved + +#define AHCI_SMART_SUPPORT 0x01 +#define AHCI_SMART_ENABLE 0x02 +#define AHCI_SMART_EN 0x02 +#define AHCI_SMART_STATUS 0x04 +#define AHCI_SMART_COMMAND_STATUS 0x80 + +#define SECTOR_LENGTH_N 9 +#define SELECTOR_NON_LBA 0xA0 +#define SELECTOR_LBA 0xE0 +#define MAX_STND_XFER_SECTOR 0x80 +#define MAX_EXTD_XFER_SECTOR 0x7F +#define BLOCK_SIZE 0x80 +#define BLOCK_SIZE_N 0xB + +typedef struct _DEV_PTR_STRUC { + UINT8 bInt13Num; // INT13 Drive# for this Port + UINT8 bDetectType; // Detected Device Type + UINT8 bPMnum; // Port Multipier port # + UINT8 bPortNum; // Port# (0-based) on Controller + UINT32 dParamTablePtr; // Ptr to device parameter table + UINT32 dInfoTablePtr; // Ptr to device info table +} DEV_PTR_STRUC; + +typedef struct _DEV_PARAM_STRUC { + UINT16 wMAXCYL; // maximum no. of cylinders..INT13 interface. (logical) + UINT8 bMAXHN; // maximum no. of heads..INT13 interface. (logical) + UINT8 bLBASIG; // LBA signature + UINT8 bLBASPT; // #of sectors per track drive is configured for. (physical) + UINT16 wWPCYL; // start write precomp cyl no. + UINT8 bReserved; // reserved + UINT8 bCBYTE; // bit 3 for more than 8 heads + UINT16 wLBACYL; // #of cylinders drive is configured for. (physical) + UINT8 bLBAHD; // #of heads drive is configured for. (physical) + UINT16 wLANDZ; // Landing zone + UINT8 bMAXSN; // no. of sectors per track..INT13 interface. (logical) + UINT8 bLBACHK; // checksum..LBA +} DEV_PARAM_STRUC; + +// +// The following definitions should be in sync with 16-bit definition +// +#define SATA_PORT_COUNT 32 +#define MAX_DESCRIPTION_STRLEN 32 + +typedef struct _AHCI_SMM_RTS { + UINT8 MiscInfo; + UINT16 SmmAttr; + UINT32 SmmPort; + UINT32 SmmData; +} AHCI_SMM_RTS; + +typedef struct _AHCI_RT_MISC_DATA { + UINT8 NumAhciDevice; // #of AHCI device installed by BIOS + UINT8 RunAttribute; // Bit-mapped information about runtime environment + UINT8 AhciEbdaSizeK; // Size of EBDA in unit of 1k that is created by AHCI init + UINT32 AhciEbdaStart; // Start offset of AHCI communication area in EBDA + AHCI_SMM_RTS AhciSmmRt; // Port and Data information to generate software SMI +} AHCI_RT_MISC_DATA; + +typedef struct _DEV_BBS_OUTFIT { + UINT8 DescString[MAX_DESCRIPTION_STRLEN]; +} DEV_BBS_OUTFIT; + +typedef struct _AHCI_I13_RTDATA { + DEV_PARAM_STRUC DevParam[SATA_PORT_COUNT]; + DEV_INFO_STRUC DevInfo[SATA_PORT_COUNT+1]; + DEV_PTR_STRUC DevPtr[SATA_PORT_COUNT]; + AHCI_RT_MISC_DATA AhciRtMiscData; + DEV_BBS_OUTFIT DevOutfit[SATA_PORT_COUNT]; +} AHCI_I13_RTDATA; + +typedef struct _AHCI_I13_DATA { + AHCI_I13_RTDATA rtdata; + UINT16 CheckForAhciCdromOffset; + UINT16 AhciBcvOffset; +} AHCI_I13_DATA; + +// Details of bSignature field: A signature Axh indicates that the table is translated. +#define DPTBL_SIG_MASK 0x0F0 +// A0h signature indicating LBA translation +#define LBA_SIGNATURE 0x0A0 + +//------------------------------------------------------------------------- +// Port registers +// +#define PORT_REGISTER_START 0x100 +#define PORT_REGISTER_SET_SIZE 0x80 +#define PORT_REGISTER_SET_SIZE_N 7 + +#define SIZE_CLCTFIS_AREA_K 4 +#define A_EBDA_USED 1 +#define A_INT13_SWSMI_USED BIT2 + +#define BAID_TYPE_HDD 1 +#define BAID_TYPE_RMD_HDD 2 +#define BAID_TYPE_CDROM 3 +#define BAID_TYPE_RMD_FDD 4 +#define BAID_TYPE_FDD 5 + +#define DEFAULT_DEVICE_STATUS 0x50 +#define SYSTYPE_ATA 0 +#define DEVTYPE_SYS 1 + +EFI_STATUS GetAccessInfo (EFI_PCI_IO_PROTOCOL*, UINT16*, UINT16*); +EFI_STATUS InitCspData (UINT16, UINT16,UINT32,UINT8); +UINT16 CountDrives(IN EFI_HANDLE *HandleBuffer, + IN UINTN HandleCount, + IN VOID *Devices + ); +#pragma pack() + +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AhciBus.c b/Core/EM/Ahci/AhciBus.c new file mode 100644 index 0000000..ae1fd38 --- /dev/null +++ b/Core/EM/Ahci/AhciBus.c @@ -0,0 +1,4477 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/AhciBus.c 74 6/25/14 10:01a Anandakrishnanl $ +// +// $Revision: 74 $ +// +// $Date: 6/25/14 10:01a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/AHCI/AhciBus.c $ +// +// 74 6/25/14 10:01a Anandakrishnanl +// [TAG] EIP170118 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] MDAT can't program correctly in AHCI module +// [RootCause] Identify Data Word 76_79 Offset for DiPM Support/Enabled +// is incorrect for validation +// [Solution] Changed separating DiPM and Device Sleep into two routines +// and also modified the tokens to disable both support by default . +// Corrected Identify data validations. +// [Files] AhciBus.c +// AhciBus.h +// AhciSrc.sdl +// PAhciBus.h +// PIDEBus.h +// +// 73 6/09/14 9:56a Anbuprakashp +// [TAG] EIP172443 +// [Category] Improvement +// [Description] "RaidDriverBlockingStatus" is using +// gEfiGlobalVariableGuid that violates UEFI 2.4 spec in +// IdeSecurityBdsCall.c and Runtime attribute set of this variable need to +// be removed +// [Files] IdeSecurityBdsCall.c, AhciBus.c +// +// 72 1/27/14 4:55a Rameshr +// [TAG] EIP148180 +// [Category] Improvement +// [Description] change from EFI_MBR_WRITE_PROTECTION_PROTOCOL to +// AMI_BLOCKIO_WRITE_PROTECTION_PROTOCOL +// [Files] Ahcibus.c, Ahcibus.h, AhciComponentName.c, AhciController.c +// +// 71 1/13/14 4:26a Rameshr +// [TAG] EIP147909 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Boot devices can not find after resume from s4 +// [RootCause] HddPassword Verification failed because of +// gHddSecurityEndProtocolGuid is uninstalled on the controller handle +// [Solution] If the gHddSecurityEndProtocolGuid protocol is already +// installed , to signel the event Reinstall Protocol interface is done +// instead of uninstalling the protocol interface. +// [Files] Ahcibus.c +// +// 70 12/20/13 4:06a Rameshr +// [TAG] EIP126640 +// [Category] Improvement +// [Description] AHCIBUS driver need to preserve the port settings in +// GeneratePortReset +// [Files] Ahcibus.c, AhciController.c +// +// 69 12/18/13 3:17a Srikantakumarp +// [TAG] EIP127356 +// [Category] Improvement +// [Description] Flash NVRAM seems to cause HDD can't be unlocked when +// S3 resume. +// [Files] IdeSecurity.c, IDESMM.c, HddPassword.c, AhciBus.c, AhciBus.h +// +// 68 12/02/13 5:46a Anbuprakashp +// [TAG] EIP138377 +// [Category] Improvement +// [Description] "CR has Bad Signature" error on AHCI eModule when +// "disconnect -r" from shell +// [Files] AhciBus.c +// +// 67 9/26/13 2:22a Rameshr +// [TAG] EIP128963 +// [Category] Improvement +// [Description] Uninitilized variable cleaned up in AhciBus Stop +// function. +// [Files] Ahcibus.c +// +// 66 9/26/13 2:10a Rameshr +// [TAG] EIP125006 +// [Category] Improvement +// [Description] Dummy Protocol installed for the protocol event +// signaling is uninstalled. So that Ahcibus driver can signal the event +// again if the bus driver gets starts again. +// [Files] Ahcibus.c +// +// 65 8/27/13 4:19a Rameshr +// [TAG] EIP125560 +// [Category] Improvement +// [Description] MbrWriteProtectionProtocol file name changesd to +// AmiMbrWriteProtectionProtocol.h +// [Files] AhciController.c, AhciBus.h, Ahcibus.c +// +// 64 8/22/13 2:52a Srikantakumarp +// [TAG] EIP106423 +// [Category] Improvement +// [Description] Correcting the previous changes. +// [Files] AhciBus.c +// +// 63 7/23/13 11:52p Srikantakumarp +// [TAG] EIP129989 +// [Category] Improvement +// [Description] Added DIPM support in Aptio 4.x AHCIBUS driver. +// [Files] AhciBus.c, AhciBus.h, AhciController.h, AhciSrc.sdl, +// PAhciBus.h +// +// 62 7/22/13 2:05a Rameshr +// [TAG] EIP129028 +// [Category] Improvement +// [Description] Implement the POWERUP_IN_STANDBY_MODE support in +// AHCIBUS driver +// [Files] Ahcibus.c, Ahcibus.h, Pahcibus.h +// +// 61 7/18/13 4:21a Rameshr +// [TAG] EIP127919 +// [Category] Improvement +// [Description] "Device is Atapi" bit of PxCMD will be set if the ATAPI +// device connected on the Port and "Drive LED on ATAPI" Enabled by AHCI +// platform policy +// [Files] Pahcibus.h, Ahcibus.c, Ahcibus.h +// +// 60 7/01/13 4:31a Kapilporwal +// [TAG] EIP125560 +// [Category] Improvement +// [Description] Please support Boot Sector Virus Protection for CSM +// Disabled Mode +// [Files] VirusProtect.c, VirusProtect.dxs, AhciBus.c, +// AhciController.c, CsmBlockIo.c, CsmInt13.c, Ata.c, IdeBus.c, +// SdioBlkIo.c, SdioDriver.c, efiusbmass.c +// +// 59 6/06/13 4:22a Rameshr +// [TAG] EIP106423 +// [Category] Improvement +// [Description] HddPassword Support in UEFI Raid and Legacy Raid. And +// also taken care where there is no Conin Device avilable in the post +// [Files] IdeSecurity.cif,IdeSecurity.sdl,IdeSecurity.mak,IdeSecurityB +// dsCall.c,HddPassword.c, Ahcibus.c, Pidebus.h +// +// 58 6/06/13 2:30a Rameshr +// [TAG] EIP119759 +// [Category] Improvement +// [Description] Ahcibus driver should not be stated when the Idebus +// driver is active on the SATA Controller +// [Files] Ahcibus.c +// +// 57 3/25/13 4:55a Rameshr +// [TAG] EIP118033 +// [Category] Improvement +// [Description] If the device is not yet detected in the remaining +// device path port, proceed for the device detection and configuration. +// +// [Files] Ahcibus.c +// +// 56 2/11/13 12:35a Rameshr +// [TAG] EIP114276 +// [Category] Improvement +// [Description] Error in AHCIBus Driver when Power management and HPA +// support is turned on. Removed the unused Power mangement and HPA code +// from Ahcibus driver +// [Files] Ahcibus.c +// +// 55 10/18/12 5:36a Srilathasc +// [TAG] EIP95446 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Diskinfo Identify function returns the invalid Identify +// data after post +// [RootCause] DiskInfoIdentify function copies the identify data from +// buffer. +// +// [Solution] DiskInfoIdentify function should send command and get +// identify data. +// [Files] IdeBus.c, AhciBus.c +// +// 54 9/17/12 1:49a Anandakrishnanl +// [TAG] EIP100891 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] PortFISBaseAddr and PortCommandListBaseAddr allocation to +// support memory allocation above 4gb +// [RootCause] System hangs in Ahci Mode > 4Gb memory allocation, With +// Filesystem and UEFI Boot Failing +// [Solution] Fixed by handling FIS and Command List base Address +// allocation >4gb allocation +// [Files] AhciBus.c +// +// 53 9/17/12 12:48a Rameshr +// [TAG] EIP100335 +// [Category] Improvement +// [Description] Port Multiplier spend long time to connect device. +// [Files] Ahcibus.c, AhciController.c +// +// 52 9/10/12 2:48a Rameshr +// [TAG] EIP95440 +// [Category] Improvement +// [Description] Add HddSecurity and HddSmart feature under UEFI Raid +// driver mode +// [Files] Ahcibus.c, Pahcibus.h, Aint13.c +// +// 51 9/03/12 6:07a Rameshr +// [TAG] EIP94991 +// [Category] Improvement +// [Description] If the link is already established before setting up +// the allowed port speed, current interface speed has not been set based +// on the port speed allowed. ComReset has been issued to setup the +// current interface speed according to the port speed allowed. +// [Files] Ahcibus.c +// +// 50 8/21/12 2:13a Rameshr +// [TAG] EIP98436 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] FISAddress is being set incorrrectly. +// [RootCause] Before setting the FIS Address, it has been used in +// GeneratePortReset function. +// [Solution] Moveed the FIS base address and command list base address +// programming before GeneratePortReset +// [Files] Ahcibus.c +// +// 49 8/16/12 3:05a Rajeshms +// [TAG] EIP97048 +// [Category] New Feature +// [Description] ATAPI PassThru Support using +// EFI_EXT_SCSI_PASS_THRU_PROTOCOL. +// [Files] AhciBus.c, AhciController.c, IdeBus.c, Atapi.c, PIDEBus.h, +// PAhciBus.h, ScsiPassThruAtapi.sdl, ScsiPassThruAtapi.mak, +// ScsiPassThruAtapi.c, ScsiPassThruAtapiSupport.h, ScsiPassThruAtapi.chm, +// ScsiPassThruExt.h +// +// 48 8/16/12 2:27a Anandakrishnanl +// [TAG] EIP97113 +// [Category] Improvement +// [Description] AtaPassThru - Module Enhancement +// [Files] AtaPassThru.c, +// AtaPassThruSupport.h,AtaPassThru.mak,IdeBus.c,AhciBus.c +// +// 47 7/20/12 6:09a Anandakrishnanl +// [TAG] EIP88683 +// [Category] New Feature +// [Description] EFI_ATA_PASS_THRU_PROTOCOL Support for Aptio IDE +// [Files] AhciBus.c +// AhciBus.h +// AInt13.h +// IdeBus.c +// IdeBus.h +// PIDEBus.h +// PAhciBus.h +// AtaPassThru.sdl +// AtaPassThru.mak +// AtaPassThru.c +// AtaPassThruSupport.h +// AtaPassThru.chm +// +// 46 11/03/11 5:44a Rajeshms +// [TAG] EIP73249 +// [Category] Improvement +// [Description] AHCI Driver Follow the UEFI Driver Model as per the +// UEFI Spec. and STOP function was Verified. +// [Files] AhciBus.c +// +// 45 10/11/11 2:21a Rameshr +// [TAG] EIP71410 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] 10 seconds Delay in post if ODD with CD/DVD +// [RootCause] ATA Specific commands are executed for ATAPI devices +// also. +// [Solution] ATA device check added before sending the command. +// [Files] Ahcibus.c +// +// 44 9/19/11 3:03a Lavanyap +// [TAG] EIP69398 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Function ConfigureController() has a runtime error (NULL +// pointer dereference) +// [RootCause] variable SupportedModes has been initialized again in +// ConfigureController(). +// [Solution] variable SupportedModes is passed as an input parameter +// for ConfigureController() and ConfigureDevice(). +// [Files] AhciBus.c, AhciBus.h +// +// 43 8/02/11 4:34a Rameshr +// [TAG] - EIP 61076 +// [Category]- IMPROVEMENT +// [Description]- Setting the Interface Speed Support in CAP.ISS. so that +// it's get programmed in PxSCT[7:4]. For this programming the link +// communication should not be established. If it's already established we +// should use GeneratePortReset function to set the speed +// [Files] - AhciBus.c +// +// 42 7/05/11 2:50a Anandakrishnanl +// [TAG] EIP56530 +// [Category] Improvement +// [Description] EFI_IDE_CONTROLLER_INIT_PROTOCOL and +// EFI_DISK_INFO_PROTOCOL are used accordingly to the PI 1.2 spec +// [Files] AhciBus.c, IdeControllerInit.h, PDiskInfo.h +// +// 41 6/14/11 5:48a Rameshr +// [TAG]- EIP 59495 +// [Category]-IMPROVEMENT +// [Description]- Update implementation of EFI_BLOCK_IO_PROTOCOL as +// described in UEFI specification v 2.3.1, page 12.8 +// [Files]- AhciBus.c +// +// 40 5/19/11 3:12a Anandakrishnanl +// [TAG] EIP53565 +// [Category] New Feature +// [Description] UEFI2.3+ Specifications defines Storage Security +// protocol which needs to be implemented. +// [Files] AhciBus.c,IdeBus.c,AHCIOpalSec.c,IDEOpalSec.c,OpalSecurity.c +// ,OpalSecurity.chm,OpalSecurity.cif,OpalSecurity.h,OpalSecurity.mak,Opal +// Security.sdl,PIDEBus.h,StorageSecurityProtocol.CIF,StorageSecurityProto +// col.h +// +// 39 2/18/11 5:04a Rameshr +// [TAG]- EIP 37975 +// [Category]-IMPROVEMENT +// [Description]- Klocwork Issues II - IDE/Ahci module +// [Files]- AhciBus.c, AhciController.c +// +// 38 2/11/11 4:22a Rameshr +// [TAG] EIP53730 +// [Category] Improvement +// [Description] Add Odd Loading type information into ATAPI_DEVICE +// structure in AHCI mode +// [Files] AhciBus.c +// AhciController.c +// AhciBus.h +// +// 37 2/10/11 10:35a Rameshr +// [TAG] EIP53704 +// [Category] Improvement +// [Description] AMI headers update for Alaska Ahci Driver +// [Files] AhciSrc.mak +// AhciBus.c +// AhciController.c +// AhciComponentName.c +// AhciBus.h +// AhciController.h +// +// 36 12/30/10 3:48a Rameshr +// [TAG] - EIP 49229 +// [Category]- BUG FIX +// [Severity]- Minor +// [Symptom] - SATA interface setting (SATA speed) +// [RootCause]- Read the SATA device speed from the Capabilities Register +// and set it to Port Control speed Register +// [Solution] - Read the SATA device speed from the Capabilities Register +// and set it to Port Control speed Register. +// [Files] - AhciBus.c +// +// 35 12/23/10 3:58a Lavanyap +// [TAG] - EIP41445 +// [Category] - NEW FEATURE +// [Description] - Created SataPioDataOut and AtaPioDataOut protocol +// function that can accept additional input parameters. +// [Files] - AhciBus.h, AhciBus.c, AhciController.c, Ata.c, IdeBus.c, +// IdeBus.h, IdeBusMaster.c,PAhciBus.h, PIdeBus.h +// +// 34 11/25/10 7:09a Rameshr +// +// [TAG] - EIP 48045 +// [Category]- BUG FIX +// [Severity]- Minor +// [Symptom] - DISABLE_SOFT_SET_PREV sdl token set 1 , throws build error +// in AHCI driver. +// [RootCause]- Status Variable not declared +// [Solution] - Declared the Status variable. +// [Files] - Ahcibus.c +// +// 33 11/02/10 12:03a Rameshr +// [TAG] - EIP 45266 +// [Category]- BUG FIX +// [Severity]- Minor +// [Symptom] - E-SATA card will hang up on post and debug card show "AE +// [RootCause]- Device doesn't support any of the UDMA mode and function +// ReturnMsbbit returns incorrect values +// [Solution] - If any of the bit is not set in Input value, ReturnMsbbit +// returns 0xFF. +// [Files] - Ata.c, AhciBus.c +// +// 32 10/11/10 6:28p Krishnakumarg +// [TAG] - EIP 44800 +// [Category] - Defect +// [Severity] - Major +// [Symptom] - Side Effect of EIP 40528. HDD security setup option +// disappear on warn boot in AHCI mode. +// [RootCause]- When FORCE_HDD_PASSWORD_PROMPT token enabled,Software +// preservation is disabled only when password is enabled. +// [Solution] - Software preservation is disabled when HDD can support +// software preservation. +// [Files] - AhciBus.c +// +// 31 9/24/10 2:40a Rameshr +// [TAG]- EIP 42817 +// [Category]-IMPROVEMENT +// [Description]- Ide Smart checks HDDs for errors moved after Idebus +// Device path has been installed. +// [Files]- AhciBus.c, IdeBus.c +// +// 30 5/26/10 6:21a Rameshr +// Checked the Device Configuration Overlay feature set supported status +// before sending the DEV_CONFIG_FREEZE_LOCK +// EIP 38384 +// +// 29 5/07/10 11:44a Krishnakumarg +// Coding standard update +// +// 28 4/16/10 4:15p Pats +// EIP 30719: Support for the HDD with sector size more than 512bytes. +// +// 27 3/26/10 5:35p Krishnakumarg +// UEFI2.1 compliance change EIP#34744. +// +// 26 2/15/10 5:51p Srinin +// KlockWork flags "'SupportedModes' is explicitly dereferenced.". Fix +// added. +// +// 25 2/11/10 4:00a Rameshr +// Atapi devices are handled by AhciBus driver based on +// SUPPORT_ATAPI_IN_RAID_MODE SDL token. +// EIP 34583 +// +// 24 1/11/10 12:12p Krishnakumarg +// Update for Eip 11835 - To implement Acoustic Management function +// EIP 30041 - Aptio 4 Device Initiated Power Management (DipM) support +// for SATA devices +// +// 23 10/15/09 11:46p Fasihm +// EIP#28961: Corrected the Disk Info Protocol installation information, +// and corrected it from EFI_BLOCK_IO_PROTOCOL to EFI_DISK_INFO_PROTOCOL. +// +// 22 9/22/09 10:57a Krishnakumarg +// Code modified to update SataDevInterface->identifydata in +// GetIdentifyData function instead of returning in global variable - +// EIP26411 +// +// 21 9/04/09 3:32p Krishnakumarg +// Coding Standard and unwanted code removal in InitAcousticSupport +// function +// +// 20 9/04/09 3:16p Krishnakumarg +// Acoustic Management function updated to set acoustic level according to +// setup option EIP:11835 +// +// 19 8/18/09 2:04p Rameshr +// AhciBus driver doesn't work for Multi Entry. +// Ahci Int13 initilization code moved from AhciBus to CsmHwinfo.c +// EIP: 25369 +// +// 18 8/17/09 2:55p Rameshr +// AHCI bus driver doesn't detect the devices other than port 0 when the +// remaining device path is not null +// EIP:25368 +// +// 17 7/13/09 3:37p Rameshr +// Symptom: After installing the UEFI windows 7 and reboot, system hangs +// on post. +// Rootcause: Devicepath created with NULL when the Remainingdevicepath +// has valid value. +// Solution: Created the Devicepath even if the RemainingDevicePath has +// the valid value. +// +// 16 6/22/09 11:33a Rameshr +// Odd Type information Saved in Atapi Device Structure. +// EIP:21548 +// +// 15 4/28/09 3:47p Rameshr +// +// HDD password support in RAID mode +// EIP:20421 +// +// 14 12/31/08 3:05p Rameshraju +// BugFix- Validate the PIO mode before programming the PIO mode into the +// device EIP:17885 +// +// 13 14/08/08 10:47a Anandakrishnanl +// Compatible Mode AHCI Support Added and Sdl Token Added in IdeBusSrc.sdl +// +// 12 5/28/08 9:38a Rameshraju +// Based on the SDL token index/data or MMIO method used to access the +// AHCI configuration space. +// +// 11 5/14/08 4:42p Rameshraju +// Error code added if error happens while configuring device or +// controller. +// +// 10 5/09/08 9:59a Rameshraju +// Cdrom block size initilized. +// +// 9 5/02/08 3:41p Rameshraju +// Insteed of OR, Write the FIS base address. +// +// 8 4/23/08 12:30p Srinin +// Bug fix in CheckDevicePresence() +// +// 7 4/18/08 2:58p Srinin +// If Device SPINUP is enabled, check is added to see whether +// COMRESET is expected or not. +// +// 6 4/14/08 4:58p Rameshraju +// Security feature stopped when the AHCI bus driver is stopped. +// +// 5 3/27/08 11:23a Srinin +// CreateSataDevicePath() modified to create a devicepath +// even if Remaining devicepath is not NULL. +// +// 4 3/24/08 6:17p Fasihm +// Fixed the issue that HDD Password prompt is not displayed in POST in +// AHCI mode when DISABLE_SOFT_SET_PREV is enabled. +// +// 3 7/03/08 5:31p Anandakrishnanl +// Added Smart Support as a seperate Driver and Corresponding changes to +// invoke Smart Protocols and removed SDL-Token +// +// 2 28/02/08 6:21p Anandakrishnanl +// Cleaned up Code and re Checked - in +// +// 1 28/02/08 6:03p Anandakrishnanl +// AHCI Bus Driver initial check-in. +// +// +// +//********************************************************************** +// +// +// Name: AhciBus.c +// +// Description: Provides AHCI Block IO protocol +// +// +//********************************************************************** + +#include "AhciBus.h" +#include "protocol\legacyahci.h" +#if SBIDE_SUPPORT +#include "SBIDE.h" +#endif + +#if defined CORE_COMBINED_VERSION && (CORE_COMBINED_VERSION > 0x4028E) +AMI_BLOCKIO_WRITE_PROTECTION_PROTOCOL *AmiBlkWriteProtection = NULL; +#endif + +EFI_GUID gEfiAhciBusProtocolGuid = AHCI_BUS_INIT_PROTOCOL_GUID; +EFI_GUID gAhciBusDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID; +EFI_GUID gEfiIdeControllerProtocolGuid = IDE_CONTROLLER_PROTOCOL_GUID; +static EFI_GUID gDevicePathProtocolGuid = EFI_DEVICE_PATH_PROTOCOL_GUID; + +#ifndef EFI_COMPONENT_NAME2_PROTOCOL_GUID +EFI_GUID gComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID; +#else +EFI_GUID gComponentNameProtocolGuid = EFI_COMPONENT_NAME2_PROTOCOL_GUID; +#endif + +static EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID; +EFI_GUID gEfiDiskInfoProtocolGuid = EFI_DISK_INFO_PROTOCOL_GUID; +EFI_GUID gEfiAhciDiskInfoProtocolGuid = EFI_DISK_INFO_AHCI_INTERFACE_GUID; +EFI_GUID gSecurityModeProtocolGuid = IDE_SECURITY_INTERFACE_GUID; +EFI_GUID gSMARTProtocolGuid = IDE_SMART_INTERFACE_GUID; +EFI_GUID gPowerMgmtProtocolGuid = IDE_POWER_MGMT_INTERFACE_GUID; +EFI_GUID gHPAProtocolGuid = IDE_HPA_INTERFACE_GUID; +EFI_GUID gStorageSecurityProtocolGuid = EFI_STORAGE_SECURITY_COMMAND_PROTOCOL_GUID; +EFI_EVENT gIDEBusEvtBootScript = NULL; +static EFI_GUID gHddSecurityInitProtocolGuid= HDD_SECURITY_INIT_PROTOCOL_GUID; +static EFI_GUID gHddSmartInitProtocolGuid = HDD_SMART_INIT_PROTOCOL_GUID; +static EFI_GUID gHddSecurityEndProtocolGuid = HDD_SECURITY_END_PROTOCOL_GUID; +static EFI_GUID gOpalSecInitProtocolGuid = OPAL_SEC_INIT_PROTOCOL_GUID; +static EFI_GUID gAtaPassThruInitProtocolGuid= ATA_PASS_THRU_INIT_PROTOCOL_GUID; +static EFI_GUID gScsiPassThruAtapiInitProtocolGuid = SCSI_PASS_THRU_ATAPI_INIT_PROTOCOL_GUID; +static EFI_GUID gEfiIdeBusInitProtocolGuid = IDE_BUS_INIT_PROTOCOL_GUID; +static EFI_GUID gOnboardRaidControllerGuid = ONBOARD_RAID_CONTROLLER_GUID; +static EFI_GUID gHddPasswordVerifiedGuid = HDD_PASSWORD_VERIFIED_GUID; +static EFI_GUID gAmiGlobalVariableGuid = AMI_GLOBAL_VARIABLE_GUID; + + +#if SBIDE_SUPPORT +EFI_GUID gIdeSetupProtocolguid = IDE_SETUP_PROTOCOL_GUID; +VOID InitMiscConfig(IN SATA_DEVICE_INTERFACE *SataDevInterface); +#endif + + +#if INDEX_DATA_PORT_ACCESS +extern InitilizeIndexDataPortAddress(); +#endif + +extern +EFI_STATUS +ExecutePacketCommand ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN COMMAND_STRUCTURE *CommandStructure, + IN BOOLEAN READWRITE +); + +#if (EFI_SPECIFICATION_VERSION > 0x00020000) +extern EFI_COMPONENT_NAME2_PROTOCOL gAhciBusControllerDriverName; +#else +extern EFI_COMPONENT_NAME_PROTOCOL gAhciBusControllerDriverName; +#endif + + +AHCI_CONTOLLER_LINKED_LIST AhciControllerLinkedList; + +EFI_DRIVER_BINDING_PROTOCOL gAhciBusDriverBinding = { + AhciBusSupported, + AhciBusStart, + AhciBusStop, + AHCI_BUS_DRIVER_VERSION, // version + NULL, // ImageHandle + NULL // DriverBindingHandle +}; + +HDD_SECURITY_INIT_PROTOCOL *HddSecurityInitProtocol; +HDD_SMART_INIT_PROTOCOL *HddSmartInitProtocol; +OPAL_SECURITY_INIT_PROTOCOL *OpalSecInitProtocol; +ATA_PASS_THRU_INIT_PROTOCOL *AtaPassThruInitProtocol; +SCSI_PASS_THRU_ATAPI_INIT_PROTOCOL *gScsiPassThruAtapiInitProtocol; +AHCI_PLATFORM_POLICY_PROTOCOL *AhciPlatformPolicy = NULL; + +// +// Instantiate AHCI_PLATFORM_POLICY_PROTOCOL with default values +// +AHCI_PLATFORM_POLICY_PROTOCOL gDefaultAhciPlatformPolicy = { + FALSE, // Legacy Raid option selected + TRUE, // Ahcibus driver handles the ATAPI devices + FALSE, // Drive LED on ATAPI Enable (DLAE) +#ifdef POWERUP_IN_STANDBY_SUPPORT + POWERUP_IN_STANDBY_SUPPORT, // PowerUpInStandby feature is supported or not +#else + FALSE, +#endif +#ifdef POWERUP_IN_STANDBY_MODE + POWERUP_IN_STANDBY_MODE, // PowerUpInStandby mode +#else + FALSE, +#endif +#ifdef DiPM_SUPPORT + DiPM_SUPPORT, // Device Initiated power management +#else + FALSE, +#endif +#ifdef ENABLE_DIPM + ENABLE_DIPM, +#else + FALSE, +#endif +#ifdef DEVICE_SLEEP_SUPPORT + DEVICE_SLEEP_SUPPORT, +#else + FALSE, +#endif +#ifdef ENABLE_DEVICE_SLEEP + ENABLE_DEVICE_SLEEP +#else + FALSE +#endif + +}; + +//********************************************************************** +// +// +// Procedure: AhciBusEntryPoint +// +// Description: Installs gAhciBusDriverBinding protocol +// +// Input: +// IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitAmiLib InstallMultipleProtocolInterfaces DListInit +// +// Notes: +// Here is the control flow of this function: +// 1. Initialize Ami Lib. +// 2. Install Driver Binding Protocol +// 3. Return EFI_SUCCESS. +// +// +//********************************************************************** +EFI_STATUS AhciBusEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + + gAhciBusDriverBinding.DriverBindingHandle=NULL; + gAhciBusDriverBinding.ImageHandle=ImageHandle; + + InitAmiLib(ImageHandle, SystemTable); + DListInit(&(AhciControllerLinkedList.AhciControllerList)); + Status = pBS->InstallMultipleProtocolInterfaces( + &gAhciBusDriverBinding.DriverBindingHandle, + &gAhciBusDriverBindingProtocolGuid,&gAhciBusDriverBinding, + &gComponentNameProtocolGuid, &gAhciBusControllerDriverName, + NULL + ); + + return Status; +} + +//********************************************************************** +// +// +// Procedure: AhciBusSupported +// +// Description: Checks whether EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID +// is installed on the controller. If 'yes', return SUCCESS else ERROR +// +// Input: +// IN EFI_DRIVER_BINDING_PROTOCOL *This, +// IN EFI_HANDLE Controller, +// IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: OpenProtocol CloseProtocol +// +// Notes: +// Here is the control flow of this function: +// 1. If Devicepath is NULL, check "gEfiIdeControllerInitProtocolGuid" +// is installed by IdeController device driver,if yes, it is the +// IDE controller that this Bus will manage. Then return Success. +// 2. If Devicepath is valid, check if it is a SATA device Path. See +// if gEfiAhciBusProtocolGuid is installed on the device. +// 3. make sure the the Controller class code is AHCI +// +// +//********************************************************************** +EFI_STATUS +AhciBusSupported( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) +{ + + EFI_STATUS Status; + EFI_IDE_CONTROLLER_INIT_PROTOCOL IdeControllerInterface; + SATA_DEVICE_PATH *SataRemainingDevicePath = (SATA_DEVICE_PATH *) RemainingDevicePath; + AHCI_BUS_PROTOCOL *AhciBusInterface; + SATA_DEVICE_INTERFACE *SataDevInterface = NULL; + EFI_PCI_IO_PROTOCOL *PciIO; + UINT8 PciConfig[256]; + + // + // Check for Valid SATA Device Path. If no return UNSUPPORTED + // + if (!(SataRemainingDevicePath == NULL)) { + // + // Check if the SataRemainingDevicePath is valid 8.3.4.1 + // + if (SataRemainingDevicePath->Header.Type != MESSAGING_DEVICE_PATH || + SataRemainingDevicePath->Header.SubType != MSG_USB_SATA_DP && + NODE_LENGTH(&SataRemainingDevicePath->Header) != SATA_DEVICE_PATH_LENGTH) { + return EFI_UNSUPPORTED; + } + + // + // Now check whether it is OK to enumerate the specified device. + // + Status = pBS->OpenProtocol( Controller, + &gEfiAhciBusProtocolGuid, + (VOID **)&AhciBusInterface, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER ); + if (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED) { + pBS->CloseProtocol ( + Controller, + &gEfiAhciBusProtocolGuid, + This->DriverBindingHandle, + Controller); + + SataDevInterface = GetSataDevInterface( + AhciBusInterface, + (UINT8)SataRemainingDevicePath->PortNumber, + (UINT8)SataRemainingDevicePath->MultiplierPortNumber + ); + + // If the device in the remaining device path Port already detected and configued + // return as EFI_ALREADY_STARTED. If the device is not yet detected in the + // remaining device path port, proceed for the device detection and configuration + + if (SataDevInterface && (SataDevInterface->DeviceState >= DEVICE_DETECTION_FAILED)) { + return EFI_ALREADY_STARTED; + } + else { + return EFI_SUCCESS; + } + } + } + + // Check if the IDEBUS installed on the controller. If it is installed + // Idebus driver already handling the Controller. So AHCIBUS driver should not handle + // the controller + + Status = pBS->OpenProtocol( Controller, + &gEfiIdeBusInitProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL ); + + if (Status == EFI_SUCCESS) { + + // Idebus handling the controller. Return with Error. + return EFI_UNSUPPORTED; + } + + + // Check whether IDE_CONTROLLER_PROTOCOL has been installed on + // this controller + // + Status = pBS->OpenProtocol( Controller, + &gEfiIdeControllerInitProtocolGuid, + (VOID **)&IdeControllerInterface, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER ); + + // + // IDE_CONTROLLER_PROTOCOL will be opened by each device. So + // EFI_ALREADY_STARTED is not an error. + // + if ( !(Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED)) { + return EFI_UNSUPPORTED; + } + + // + // Close IDE_CONTROLLER_PROTOCOL + // + pBS->CloseProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Check if Controller is in AHCI mode or not? + // + Status = pBS->OpenProtocol( Controller, + &gEfiPciIoProtocolGuid, + (VOID **)&PciIO, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) {return EFI_UNSUPPORTED;} + + Status = PciIO->Pci.Read ( PciIO, + EfiPciIoWidthUint8, + 0, + sizeof (PciConfig), + PciConfig + ); + + if (PciConfig [IDE_SUB_CLASS_CODE] == SCC_AHCI_CONTROLLER) { +#ifdef AHCI_COMPATIBLE_MODE + #if !(AHCI_COMPATIBLE_MODE) + return EFI_SUCCESS; + #endif +#endif + } + +#ifdef SUPPORT_ATAPI_IN_RAID_MODE +#ifdef HDD_PASSWORD_SUPPORT_UNDER_RAIDMODE + #if SUPPORT_ATAPI_IN_RAID_MODE || HDD_PASSWORD_SUPPORT_UNDER_RAIDMODE + if (PciConfig [IDE_SUB_CLASS_CODE] == SCC_RAID_CONTROLLER) { + + // + // Under Raid mode, don't detect the devices again + // Check if AHCI_BUS_PROTOCOL installed status. If already installed + // Ahcibus started already and device detection done + // + Status = pBS->OpenProtocol( Controller, + &gEfiAhciBusProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + + + if ( EFI_ERROR(Status)) { + return EFI_SUCCESS; + } else { + return EFI_ALREADY_STARTED; + } + } + #endif +#endif +#endif + + return EFI_UNSUPPORTED; + +} + + +//********************************************************************** +// +// +// Procedure: AhciBusStart +// +// Description: Installs AHCI Block IO Protocol +// +// Input: +// IN EFI_DRIVER_BINDING_PROTOCOL *This, +// IN EFI_HANDLE Controller, +// IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: OpenProtocol CloseProtocol InstallProtocolInterface +// AllocatePool InstallAhciBusProtocol CheckPortImplemented +// DetectAndConfigureDevice. +// +// Notes: +// 1. Collect the info about the number of devices to detect and configure. +// 2. Configure the AHCI controller if it is not done yet. +// 3. Detect the device connected to the port +// 4. If the device is a Port Multiplier, detect & configure all the +// devices behind it, else configure the device directly connected +// to the port. +// 5. Continue step 3 and 4 for all the ports on the controller. +// +// +//********************************************************************** +EFI_STATUS +AhciBusStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) +{ + + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIO; + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface; + SATA_DEVICE_INTERFACE *SataDevInterface = NULL; + AHCI_BUS_PROTOCOL *AhciBusInterface; + UINT8 Enumeration_Process = ENUMERATE_ALL; + SATA_DEVICE_PATH *SataRemainingDevicePath = (SATA_DEVICE_PATH *)RemainingDevicePath; + UINT8 PortEnumeration = 0xFF, PMPortEnumeration = 0xFF; // Bit Map + UINT8 CurrentPort = 0, CurrentPMPort = 0xFF; + BOOLEAN Enabled = TRUE; + UINT8 MaxDevices = 0; + UINT8 Data8; + EFI_HANDLE SecHandle=NULL; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + VOID *TempProtocolPtr; + EFI_STATUS SecurityStatus=EFI_NOT_FOUND; + BOOLEAN RaidDriverBlocked=FALSE; + + PROGRESS_CODE(DXE_IDE_BEGIN); + +#if defined CORE_COMBINED_VERSION && (CORE_COMBINED_VERSION > 0x4028E) + if(AmiBlkWriteProtection == NULL) { + Status = pBS->LocateProtocol(&gAmiBlockIoWriteProtectionProtocolGuid, NULL, &AmiBlkWriteProtection); + if(EFI_ERROR(Status)) { + AmiBlkWriteProtection = NULL; + } + } +#endif + + // Open IDE_CONTROLLER_PROTOCOL. If success or Already opened, It is OK to proceed. + Status = pBS->OpenProtocol( Controller, + &gEfiIdeControllerInitProtocolGuid, + (VOID **)&IdeControllerInterface, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER ); + + if ( !(Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED)) return EFI_DEVICE_ERROR; + + // Get the PciIO interface + Status = pBS->OpenProtocol( Controller, + &gEfiPciIoProtocolGuid, + (VOID **)&PciIO, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR; + + // Check if AHCI_BUS_PROTOCOL installed. + Status = pBS->OpenProtocol( Controller, + &gEfiAhciBusProtocolGuid, + (VOID **)&AhciBusInterface, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER); + + + if ( !(Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED)) { + + Status = pBS->AllocatePool (EfiBootServicesData, + sizeof(AHCI_BUS_PROTOCOL), + (VOID**)&AhciBusInterface + ); + + if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES; //No need to close IDE_CONTROLLER_PROTOCOL + + Status = InstallAhciBusProtocol (Controller, AhciBusInterface, IdeControllerInterface, PciIO); + if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR; //No need to close the protocol. Will be handled in STOP + } + + if (!IdeControllerInterface->EnumAll) { + // Check if sataRemainingDevicePath is valid or not + if (!(SataRemainingDevicePath == NULL)) { + // Check if the SataRemainingDevicePath is valid 8.3.4.1 + if (SataRemainingDevicePath->Header.Type != MESSAGING_DEVICE_PATH || + SataRemainingDevicePath->Header.SubType != MSG_USB_SATA_DP && + NODE_LENGTH(&SataRemainingDevicePath->Header) != SATA_DEVICE_PATH_LENGTH) { + return EFI_DEVICE_ERROR; + } + // Get the Port# that needs to be processed. + PortEnumeration = 1 << SataRemainingDevicePath->PortNumber; //Bit Map + PMPortEnumeration = 1 << SataRemainingDevicePath->MultiplierPortNumber; // Bit Map + CurrentPMPort = (UINT8) SataRemainingDevicePath->MultiplierPortNumber; + } + } + else { + PortEnumeration = AhciBusInterface->HBAPortImplemented; + } + + // + // Get the Ahci Platform Policy Protocol + // + Status=pBS->LocateProtocol(&gAciPlatformPolicyProtocolGuid, NULL, &AhciPlatformPolicy); + if(EFI_ERROR(Status)) { + // + // If the Ahci Platform policy protocol not found, initilize with default value + // + AhciPlatformPolicy=(AHCI_PLATFORM_POLICY_PROTOCOL *)&gDefaultAhciPlatformPolicy; + } + + + TRACE_AHCI((-1,"\nAHCI Driver Detection and Configuratiion starts\n")); + + + //-------------------------------------------------------------------------- + // Detection and Configuration starts + //-------------------------------------------------------------------------- + for ( ; PortEnumeration != 0 ; PortEnumeration >>= 1, CurrentPort++, CurrentPMPort = 0xFF) { + + if(!(PortEnumeration & 1)) { + continue; + } + + // Check if the current port is implemented or not? + Status = CheckPortImplemented(AhciBusInterface, CurrentPort); + if (EFI_ERROR(Status)) { continue;} + + Status = IdeControllerInterface->NotifyPhase (IdeControllerInterface, EfiIdeBeforeChannelEnumeration, CurrentPort); + if (EFI_ERROR(Status)) { continue;} + + Status = IdeControllerInterface->GetChannelInfo(IdeControllerInterface, CurrentPort, &Enabled, &MaxDevices); + if (EFI_ERROR(Status) || !Enabled) { goto NextDevice; } + + Status = DetectAndConfigureDevice(This, Controller, RemainingDevicePath, AhciBusInterface, IdeControllerInterface, CurrentPort, CurrentPMPort); + SataDevInterface = GetSataDevInterface(AhciBusInterface, CurrentPort, CurrentPMPort); + + if(SataDevInterface != NULL && EFI_ERROR(SecurityStatus)) { + // Verify that Security interface has been installed + // on atleast one device + SecurityStatus = pBS->HandleProtocol(SataDevInterface->IdeDeviceHandle, + &gSecurityModeProtocolGuid, + &TempProtocolPtr + ); + } + + // Check whether the device detected is PM. Also check whether PM is supported by the Controller + // and also MaxDevices should be more than 1 if PM is Supported. + if (!EFI_ERROR(Status) && SataDevInterface && SataDevInterface->NumPMPorts && + (SataDevInterface->DeviceType == PMPORT) && MaxDevices > 1){ + + Data8 = SataDevInterface->NumPMPorts > MaxDevices ? MaxDevices : SataDevInterface->NumPMPorts; + PMPortEnumeration = 1; + for (Data8-- ;Data8; Data8-- ){ + PMPortEnumeration = (PMPortEnumeration << 1) | 1; + } + + // Port Multiplier loop + for (CurrentPMPort = 0; PMPortEnumeration & 1 ; PMPortEnumeration >>= 1, CurrentPMPort++ ){ + DetectAndConfigureDevice(This, Controller, RemainingDevicePath, AhciBusInterface, IdeControllerInterface, CurrentPort, CurrentPMPort); + } + + } + +NextDevice: + IdeControllerInterface->NotifyPhase(IdeControllerInterface, EfiIdeAfterChannelEnumeration, CurrentPort); + + } + + + TRACE_AHCI((-1," AHCI Driver Detection and Configuratiion Ends\n")); + + Status = pBS->LocateProtocol ( + &gAtaPassThruInitProtocolGuid, + NULL, + &AtaPassThruInitProtocol + ); + + if(!EFI_ERROR(Status)) { + if(AtaPassThruInitProtocol != NULL) { + AtaPassThruInitProtocol->InstallAtaPassThru(Controller, TRUE); + } + } + + // SCSIPassThruAtapi install + Status = pBS->LocateProtocol ( + &gScsiPassThruAtapiInitProtocolGuid, + NULL, + &gScsiPassThruAtapiInitProtocol + ); + + + if(!EFI_ERROR(Status)) { + if(gScsiPassThruAtapiInitProtocol != NULL) { + gScsiPassThruAtapiInitProtocol->InstallScsiPassThruAtapi(Controller, TRUE); + } + } + + // Handle the Onboard Raid controller Password Verification + + Status = pBS->HandleProtocol(Controller, + &gHddSecurityEndProtocolGuid, + & TempProtocolPtr + ); + + if(Status == EFI_SUCCESS) { + // + // Protocol already installed on the Controller handle. + // Re-Install the protocol interface to Notify the Password verification + // + Status = pBS->ReinstallProtocolInterface( + &Controller, + &gHddSecurityEndProtocolGuid, NULL,NULL + ); + } else { + // + // This will notify AMITSE to invoke the HDD password Screen + // + Status = pBS->InstallProtocolInterface( + &Controller, + &gHddSecurityEndProtocolGuid, EFI_NATIVE_INTERFACE,NULL + ); + } + + if(!EFI_ERROR(Status) && !EFI_ERROR(SecurityStatus)) { + + // Handle the Onboard Raid controller Password Verification + + Status = pBS->HandleProtocol(Controller, + &gOnboardRaidControllerGuid, + &TempProtocolPtr + ); + if(!EFI_ERROR(Status)) { + + + // Check the Hdd Password verification done. If the password + // Verification done, proceed for RAID driver launch. Otherwise + // Hold the Raid driver until Password verification finished. + + Status = pBS->HandleProtocol(Controller, + &gHddPasswordVerifiedGuid, + &TempProtocolPtr + ); + + if(EFI_ERROR(Status)) { + + // Don't launch the Raid Option rom until password verified + + Status = pBS->OpenProtocol ( + Controller, + &gDevicePathProtocolGuid, + (VOID *) &DevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if(Status == EFI_SUCCESS) { + RaidDriverBlocked=TRUE; + Status = pRS->SetVariable(L"RaidDriverBlockingStatus", + &gAmiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(RaidDriverBlocked), + &RaidDriverBlocked ); + } + } + } + } + + return EFI_SUCCESS; +} + + +//********************************************************************** +// +// +// Procedure: DetectAndConfigureDevice +// +// Description: Detects and Configures Sata Device +// +// Input: +// IN EFI_DRIVER_BINDING_PROTOCOL *This, +// IN EFI_HANDLE Controller +// IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, +// AHCI_BUS_PROTOCOL *AhciBusInterface, +// EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, +// UINT8 Port, +// UINT8 PMPort +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AhciDetectDevice ConfigureDevice InitSataBlockIO InitSataDiskInfo +// +// Notes: +// 1. Detect whether device is connected to the port. If no device exit. +// 2. Install SataDevInterface. If PMPort, Configure PMPort and Exit. +// 3. Configure the SATA device and the controller. +// 4. Install DevicePath, BlockIO and DiskInfo protocol. +// +// +//********************************************************************** +EFI_STATUS +DetectAndConfigureDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, + AHCI_BUS_PROTOCOL *AhciBusInterface, + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, + UINT8 Port, + UINT8 PMPort +) +{ + + EFI_STATUS Status; + SATA_DEVICE_INTERFACE *SataDevInterface = NULL; + EFI_ATA_COLLECTIVE_MODE *SupportedModes = NULL; + UINT16 SecurityStatus = 0; + + SataDevInterface = GetSataDevInterface(AhciBusInterface, Port, PMPort); + + if (SataDevInterface && ((SataDevInterface->DeviceState == DEVICE_DETECTION_FAILED)|| + (SataDevInterface->DeviceState == DEVICE_CONFIGURED_SUCCESSFULLY))){ + return EFI_SUCCESS; + } + + Status = AhciDetectDevice(AhciBusInterface, IdeControllerInterface, Port, PMPort); + SataDevInterface = GetSataDevInterface(AhciBusInterface, Port, PMPort); + if (EFI_ERROR(Status)) { + if (SataDevInterface) SataDevInterface->DeviceState = DEVICE_DETECTION_FAILED; + return EFI_DEVICE_ERROR; + } + + if (!SataDevInterface) { + return EFI_DEVICE_ERROR; + } + + SataDevInterface->DeviceState = DEVICE_DETECTED_SUCCESSFULLY; + + // + // if this is a Port Multiplier skip the rest + // + if (SataDevInterface->DeviceType == PMPORT) { + SataDevInterface->DeviceState = DEVICE_CONFIGURED_SUCCESSFULLY; + + // + //Update Port Multiplier Data + // + Status = ConfigurePMPort(SataDevInterface); + if (!EFI_ERROR(Status)) { + TRACE_AHCI((-1,"AHCI: SATA Device type %x detected at Port Number : %x, PM Port Number : %x\n", + SataDevInterface->DeviceType, SataDevInterface->PortNumber, SataDevInterface->PMPortNumber)); + } + return Status; + } + + Status = ConfigureDevice(SataDevInterface, &SupportedModes); + if (EFI_ERROR(Status)) { + ERROR_CODE(DXE_IDE_DEVICE_FAILURE, EFI_ERROR_MAJOR); + SataDevInterface->DeviceState = DEVICE_DETECTION_FAILED; + return EFI_DEVICE_ERROR; + } + + Status = ConfigureController(SataDevInterface, SupportedModes); + if (EFI_ERROR(Status)) { + ERROR_CODE(DXE_IDE_DEVICE_FAILURE, EFI_ERROR_MAJOR); + SataDevInterface->DeviceState = DEVICE_DETECTION_FAILED; + return EFI_DEVICE_ERROR; + } + + SataDevInterface->DeviceState = DEVICE_CONFIGURED_SUCCESSFULLY; + + Status = ConfigureSataPort(SataDevInterface); + + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Create the Devicepath + // + Status = CreateSataDevicePath (This, Controller, SataDevInterface, RemainingDevicePath); + if (EFI_ERROR(Status)) { return EFI_DEVICE_ERROR; } + + // + // Initialize Block_IO Protocol + // + Status = InitSataBlockIO (SataDevInterface); + if (EFI_ERROR(Status)){ + return EFI_DEVICE_ERROR; + } + + // + // Initialize IDE EFI_DISK_INFO_PROTOCOL + // + Status = InitSataDiskInfo (SataDevInterface); + if (EFI_ERROR(Status)){ + return EFI_DEVICE_ERROR; + } + + // + // Install Devicepath + // + Status = pBS->InstallMultipleProtocolInterfaces ( + &(SataDevInterface->IdeDeviceHandle), + &gDevicePathProtocolGuid, SataDevInterface->DevicePathProtocol, + NULL); + + if(EFI_ERROR(Status)) { + SataDevInterface->DeviceState = DEVICE_DETECTION_FAILED; + if (EFI_ERROR(Status)){ + return EFI_DEVICE_ERROR; + } + } + + // + // Open IdeControllerProtocol + // + Status = pBS->OpenProtocol(Controller, + &gEfiIdeControllerInitProtocolGuid, + (VOID **)&IdeControllerInterface, + This->DriverBindingHandle, + SataDevInterface->IdeDeviceHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER); + + Status = pBS->LocateProtocol ( + &gHddSecurityInitProtocolGuid, + NULL, + &HddSecurityInitProtocol + ); + + if(!EFI_ERROR(Status)) { + if(HddSecurityInitProtocol != NULL) { + HddSecurityInitProtocol->InstallSecurityInterface(SataDevInterface, TRUE); + } + } else { + + // + // If Security Feature support is not enabled, always freeze + // lock the security feature + // + if (SataDevInterface->IdentifyData.Command_Set_Supported_82 & 0x2) { + COMMAND_STRUCTURE CommandStructure; + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Command = SECURITY_FREEZE_LOCK; + Status = ExecuteNonDataCommand (SataDevInterface, CommandStructure); + // + // if Device Configuration Overlay feature set supported then issue the + // Dev config Free lock command. + // + if (SataDevInterface->IdentifyData.Command_Set_Supported_83 & 0x800) { + CommandStructure.Command = DEV_CONFIG_FREEZE_LOCK; + CommandStructure.Features = DEV_CONFIG_FREEZE_LOCK_FEATURES; + Status = ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } + // + // Update the Identify device buffer + // + Status = GetIdentifyData(SataDevInterface); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + } + } + + Status = pBS->LocateProtocol ( + &gOpalSecInitProtocolGuid, + NULL, + &OpalSecInitProtocol + ); + + if(!EFI_ERROR(Status)) { + if(OpalSecInitProtocol != NULL) { + OpalSecInitProtocol->InstallOpalSecurityInterface(SataDevInterface, TRUE); + } + } + + Status = pBS->LocateProtocol ( + &gHddSmartInitProtocolGuid, + NULL, + &HddSmartInitProtocol + ); + + if(!EFI_ERROR(Status)) { + if(HddSmartInitProtocol != NULL) { + HddSmartInitProtocol->InitSMARTSupport(SataDevInterface, TRUE); + // + // Update the Idendify Data. + // + Status = GetIdentifyData(SataDevInterface); + if(HddSmartInitProtocol->SmartDiagonasticFlag) { + HddSmartInitProtocol->InstallSMARTInterface(SataDevInterface, TRUE); + } + } + } + + // + // Check BlockIO has been installed or not. + // + Status = pBS->OpenProtocol( SataDevInterface->IdeDeviceHandle, + &gEfiBlockIoProtocolGuid, + NULL, + This->DriverBindingHandle, + SataDevInterface->IdeDeviceHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + + if (EFI_ERROR(Status)) { + // + // BLOCKIO not installed and device has been configured successfully + // + Status = EFI_UNSUPPORTED; + SecurityStatus = 0; + } + + if ((Status == EFI_UNSUPPORTED) || (!(SecurityStatus & 4))){ + // + // Either the device doesn't support Security Mode OR Device is not locked + // + Status = pBS->InstallMultipleProtocolInterfaces ( + &(SataDevInterface->IdeDeviceHandle), + &gEfiDiskInfoProtocolGuid, + (EFI_DISK_INFO_PROTOCOL *)(SataDevInterface->SataDiskInfo), + NULL); + +#if HDD_PASSWORD_SUPPORT_UNDER_RAIDMODE + if (!(!(AhciBusInterface->AHCIRAIDMODE) && (SataDevInterface->DeviceType == ATA))) { +#endif + + // + // If it's Raid mode and AHCIBUS handles the ATAPI devices, install the BlockIo + // for the ATAPI devices. BlockIo Will be installed for all the ATA and ATAPI device under AHCI mode + // + if (!(!(AhciBusInterface->AHCIRAIDMODE) && (AhciPlatformPolicy->AhciBusAtapiSupport == FALSE ))) { + + // + // Either the device doesn't support Security Mode OR Device is not locked + // + Status = pBS->InstallMultipleProtocolInterfaces ( + &(SataDevInterface->IdeDeviceHandle), + &gEfiBlockIoProtocolGuid, + (EFI_BLOCK_IO_PROTOCOL *)(SataDevInterface->SataBlkIo), + NULL); + } + +#if HDD_PASSWORD_SUPPORT_UNDER_RAIDMODE + } +#endif + + } // Install BLOCKIO + + TRACE_AHCI((-1,"AHCI: SATA Device type %x detected at Port Number : %x, PM Port Number : %x\n", + SataDevInterface->DeviceType, SataDevInterface->PortNumber, SataDevInterface->PMPortNumber)); + + return EFI_SUCCESS; +} + +//********************************************************************** +// +// +// Procedure: AhciBusStop +// +// Description: Uninstall all devices installed in start procedure. +// +// Input: +// IN EFI_DRIVER_BINDING_PROTOCOL *This, +// IN EFI_HANDLE Controller, +// IN UINTN NumberOfChildren, +// IN EFI_HANDLE *ChildHandleBuffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: OpenProtocol CloseProtocol +// +// Notes: +// 1. Check whether "gEfiAhciBusProtocolGuid" is installed on this +// controller. If not exit with error. +// 2. If "NumberOfChildren" is zero, check wether all child devices +// have been stopped. If not exit with error.If all child devices +// have been stopped, then close "gEfiAhciBusProtocolGuid" and +// "gEfiIdeControllerInitProtocolGuid",uninstall +// "gEfiIdeControllerInitProtocolGuid" and then exit with success. +// 3. If "NumberOfChildren" is non-zero, close +// "gEfiIdeControllerInitProtocolGuid" opened by the child device +// in start function.Uninstall all protocols installed on this +// child device in start function,free up all resources allocated +// in start function. Repeat step 3 for all child devices and +// return success at the end. +// +// +//********************************************************************** +EFI_STATUS +AhciBusStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + AHCI_BUS_PROTOCOL *AhciBusInterface; + SATA_DEVICE_INTERFACE *SataDeviceInterface; + EFI_STATUS Status; + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface; + UINT16 Index = 0; + UINT16 Port=0; + UINT16 PMPort=0; + BOOLEAN Flag = TRUE; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + DLINK *dlink; + + // + // Check if AHCI_BUS_PROTOCOL is installed on the Controller. + // + Status = pBS->OpenProtocol( Controller, + &gEfiAhciBusProtocolGuid, + (VOID **)&AhciBusInterface, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Check if ChildHandleBuffer is valid + // + if (NumberOfChildren) { + while (NumberOfChildren) { + + + Status = pBS->CloseProtocol ( Controller, + &gEfiIdeControllerInitProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index]); + + Status = pBS->OpenProtocol( + ChildHandleBuffer[Index], + &gDevicePathProtocolGuid, + (VOID **)&DevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + // + // Lookout for SATA device path ACPI_DEVICE path, PCI + // Device path and then ATAPI device path will be the sequence + // + do { + if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_USB_SATA_DP)) { + Port = ((SATA_DEVICE_PATH *)DevicePath)->PortNumber; + PMPort = ((SATA_DEVICE_PATH *)DevicePath)->MultiplierPortNumber; + break; + } + else { + DevicePath = NEXT_NODE(DevicePath); + } + } while (DevicePath->Type != END_DEVICE_PATH); + + if(DevicePath->Type == END_DEVICE_PATH) { + //Unable to find the Messaging device path node. + ASSERT(FALSE); + return EFI_DEVICE_ERROR; + } + + SataDeviceInterface = GetSataDevInterface(AhciBusInterface, (UINT8)Port, (UINT8)PMPort); + if (!SataDeviceInterface) return EFI_DEVICE_ERROR; + + // + // Before uninstalling DiskInfo check whether it is installed or not + // + Status = pBS->OpenProtocol( ChildHandleBuffer[Index], + &gEfiDiskInfoProtocolGuid, + NULL, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + + if (Status == EFI_SUCCESS) { + Status = pBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiDiskInfoProtocolGuid, + (EFI_DISK_INFO_PROTOCOL *)(SataDeviceInterface->SataDiskInfo), + NULL); + } + + // + // Before uninstalling BLOCKIO check whether it is installed or not + // + Status = pBS->OpenProtocol( ChildHandleBuffer[Index], + &gEfiBlockIoProtocolGuid, + NULL, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + + if (Status == EFI_SUCCESS) { + Status = pBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiBlockIoProtocolGuid, + (EFI_BLOCK_IO_PROTOCOL *)(SataDeviceInterface->SataBlkIo), + NULL); + } + + Status = pBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gDevicePathProtocolGuid, + SataDeviceInterface->DevicePathProtocol, + NULL); + + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } else { + + // + // Now free up all resources allocated. + // + if (SataDeviceInterface->AtapiDevice != NULL){ + pBS->FreePool(SataDeviceInterface->AtapiDevice->PacketBuffer); + pBS->FreePool(SataDeviceInterface->AtapiDevice->InquiryData); + pBS->FreePool(SataDeviceInterface->AtapiDevice); + } + + // + // Freeup resources allocated for component names + // + if (SataDeviceInterface->UDeviceName != NULL) { + pBS->FreePool(SataDeviceInterface->UDeviceName->Language); + pBS->FreePool(SataDeviceInterface->UDeviceName->UnicodeString); + pBS->FreePool(SataDeviceInterface->UDeviceName); + } + + // + // Before uninstalling HDD security check whether it is installed or not + // + Status = pBS->OpenProtocol( ChildHandleBuffer[Index], + &gSecurityModeProtocolGuid, + NULL, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + + if (Status == EFI_SUCCESS) { + if(HddSecurityInitProtocol != NULL) { + HddSecurityInitProtocol->StopSecurityModeSupport(SataDeviceInterface, TRUE); + } + } + + // + // Before uninstalling Hdd Smart check whether it is installed or not + // + Status = pBS->OpenProtocol( ChildHandleBuffer[Index], + &gSMARTProtocolGuid, + NULL, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + + if (Status == EFI_SUCCESS) { + if(HddSmartInitProtocol != NULL) { + if(HddSmartInitProtocol->SmartDiagonasticFlag) { + HddSmartInitProtocol->UnInstallSMARTInterface(SataDeviceInterface, TRUE); + } + } + } + + // + // Before uninstalling OPAL security interface check whether it is installed or not. + // + Status = pBS->OpenProtocol( ChildHandleBuffer[Index], + &gStorageSecurityProtocolGuid, + NULL, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + + if (Status == EFI_SUCCESS) { + if(OpalSecInitProtocol != NULL) { + OpalSecInitProtocol->UnInstallOpalSecurityInterface(SataDeviceInterface, TRUE); + } + } + + pBS->FreePool(SataDeviceInterface->SataBlkIo->BlkIo.Media); + pBS->FreePool(SataDeviceInterface->SataBlkIo); + pBS->FreePool(SataDeviceInterface->SataDiskInfo); + pBS->FreePool (SataDeviceInterface->DevicePathProtocol); + DListDelete(&(AhciBusInterface->SataDeviceList), &(SataDeviceInterface->SataDeviceLink)); + pBS->FreePool (SataDeviceInterface); + } + NumberOfChildren--; + Index++; + } + } else { + + // + // Check if AHCI_BUS_PROTOCOL can be removed. No device other + // than Port Multiplier can be present. + // + dlink = AhciBusInterface->SataDeviceList.pHead; + Status = EFI_SUCCESS; + if (dlink){ + do { + SataDeviceInterface = OUTTER(dlink, SataDeviceLink, SATA_DEVICE_INTERFACE); + if (SataDeviceInterface->DeviceType != PMPORT || + SataDeviceInterface->DeviceState == DEVICE_CONFIGURED_SUCCESSFULLY) { + Status = EFI_DEVICE_ERROR; + break; + } + dlink = dlink-> pNext; + }while (dlink); + } + + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Free PM resources + // + dlink = AhciBusInterface->SataDeviceList.pHead; + Status = EFI_SUCCESS; + if (dlink){ + do { + SataDeviceInterface = OUTTER(dlink, SataDeviceLink, SATA_DEVICE_INTERFACE); + // + // Now free up all resources allocated. + // + if (SataDeviceInterface->AtapiDevice != NULL){ + pBS->FreePool(SataDeviceInterface->AtapiDevice->PacketBuffer); + pBS->FreePool(SataDeviceInterface->AtapiDevice->InquiryData); + pBS->FreePool(SataDeviceInterface->AtapiDevice); + } + + // + // Freeup resources allocated for component names + // + if (SataDeviceInterface->UDeviceName != NULL) { + pBS->FreePool(SataDeviceInterface->UDeviceName->Language); + pBS->FreePool(SataDeviceInterface->UDeviceName->UnicodeString); + pBS->FreePool(SataDeviceInterface->UDeviceName); + } + DListDelete(&(AhciBusInterface->SataDeviceList), &(SataDeviceInterface->SataDeviceLink)); + dlink = dlink-> pNext; + pBS->FreePool (SataDeviceInterface); + }while (dlink); + } + + // + // Close all the protocols opened in Start Function + // + Status = pBS->CloseProtocol ( Controller, + &gEfiIdeControllerInitProtocolGuid, + This->DriverBindingHandle, + Controller); + // + // AtaPass Thru uninstall + // + Status = pBS->LocateProtocol ( + &gAtaPassThruInitProtocolGuid, + NULL, + &AtaPassThruInitProtocol + ); + + if(!EFI_ERROR(Status)) { + if(AtaPassThruInitProtocol != NULL) { + AtaPassThruInitProtocol->StopAtaPassThruSupport(Controller, TRUE); + } + } + + // + // SCSIPassThruAtapi uninstall + // + Status = pBS->LocateProtocol ( + &gScsiPassThruAtapiInitProtocolGuid, + NULL, + &gScsiPassThruAtapiInitProtocol + ); + + if(!EFI_ERROR(Status)) { + if(gScsiPassThruAtapiInitProtocol != NULL) { + gScsiPassThruAtapiInitProtocol->StopScsiPassThruAtapiSupport(Controller, TRUE); + } + } + + Status = pBS->CloseProtocol( Controller, + &gEfiAhciBusProtocolGuid, + This->DriverBindingHandle, + Controller); + + Status = pBS->UninstallProtocolInterface ( Controller, + &gEfiAhciBusProtocolGuid, + AhciBusInterface); + + if (EFI_ERROR(Status)) { + + Status = pBS->OpenProtocol( Controller, + &gEfiAhciBusProtocolGuid, + (VOID **)&AhciBusInterface, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER); + + Status = pBS->OpenProtocol( Controller, + &gEfiIdeControllerInitProtocolGuid, + (VOID **)&IdeControllerInterface, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER ); + + return EFI_DEVICE_ERROR; + } + + // Free the Pages allocated for the FIS and Command List + if (AhciBusInterface->Address1) { + pBS->FreePages(AhciBusInterface->Address1, + EFI_SIZE_TO_PAGES(AhciBusInterface->NumberofPortsImplemented * RECEIVED_FIS_SIZE + 0x100 )); + } + + if (AhciBusInterface->Address2) { + pBS->FreePages((AhciBusInterface->Address2),EFI_SIZE_TO_PAGES(COMMAND_LIST_SIZE_PORT * 2)); + } + + } + + return EFI_SUCCESS; + +} + +//********************************************************************** +// +// +// Procedure: InstallAhciBusProtocol +// +// Description: Installs BUS Init Protocol on the IDE controller Handle +// +// Input: +// IN EFI_HANDLE Controller, +// IDE_BUS_INIT_PROTOCOL *IdeBusInitInterface, +// IDE_CONTROLLER_PROTOCOL *IdeControllerInterface, +// EFI_PCI_IO_PROTOCOL *PciIO +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AllocatePool, InstallProtocolInterface, AhciInitController +// +// Notes: +// 1. Call AhciInitController +// 2. Install gEfiAhciBusProtocolGuid protocol +// +// +//********************************************************************** +EFI_STATUS +InstallAhciBusProtocol ( + IN EFI_HANDLE Controller, + IN OUT AHCI_BUS_PROTOCOL *AhciBusInterface, + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, + IN EFI_PCI_IO_PROTOCOL *PciIO + ) +{ + + EFI_STATUS Status; + UINT8 PciConfig[16]; +#if SBIDE_SUPPORT + IDE_SETUP_PROTOCOL *gIdeSetupProtocol; +#endif + + // + // Initialize the default Values + // + ZeroMemory (AhciBusInterface, sizeof(AHCI_BUS_PROTOCOL)); + + AhciBusInterface->ControllerHandle = Controller; + AhciBusInterface->IdeControllerInterface = IdeControllerInterface; + AhciBusInterface->PciIO = PciIO; + DListInit(&(AhciBusInterface->SataDeviceList)); + + AhciBusInterface->SataReadWritePio = SataReadWritePio; + AhciBusInterface->SataPioDataOut = SataPioDataOut; + AhciBusInterface->ExecutePioDataCommand = ExecutePioDataCommand; + AhciBusInterface->ExecuteNonDataCommand = ExecuteNonDataCommand; + AhciBusInterface->WaitforCommandComplete = WaitforCommandComplete; + AhciBusInterface->GeneratePortReset = GeneratePortReset; + AhciBusInterface->ExecutePacketCommand = ExecutePacketCommand; + AhciBusInterface->AHCIRAIDMODE = TRUE; // Set TRUE when in AHCI mode + + Status = PciIO->Pci.Read ( PciIO, + EfiPciIoWidthUint8, + 0, + sizeof (PciConfig), + PciConfig + ); + + if (PciConfig [IDE_SUB_CLASS_CODE]== SCC_RAID_CONTROLLER ){ + AhciBusInterface->AHCIRAIDMODE = FALSE; + } + + // + // Using setup question if needed, set Bit 0 to enable/Disable + // Acoustic Power Management. + // Set bit1 only if HDD Losses power in S3 state. HDD freeze lock + // command will be issued during S3 resume when this bit is set + // and also if Password is enabled for HDD, it will be unlocked + // during S3 resume. + // + + AhciBusInterface->Acoustic_Enable = 0; // ACOUSTIC_SUPPORT_DISABLE + +#if SBIDE_SUPPORT + Status = pBS->LocateProtocol(&gIdeSetupProtocolguid, NULL, &gIdeSetupProtocol); + + #if ACOUSTIC_MANAGEMENT_SUPPORT + if (!EFI_ERROR(Status)) { + AhciBusInterface->Acoustic_Enable = gIdeSetupProtocol->AcousticPwrMgmt; + AhciBusInterface->Acoustic_Management_Level = gIdeSetupProtocol->AcousticLevel; + } else { + AhciBusInterface->Acoustic_Enable = ACOUSTIC_SUPPORT_DISABLE; + AhciBusInterface->Acoustic_Management_Level = ACOUSTIC_LEVEL_BYPASS; + } + #endif //End of ACOUSTIC_MANAGEMENT_SUPPORT +#endif // end of if SBIDE_SUPPORT + + + // Initialize PrevPortNum and PrevPortMultiplierPortNum for AtaPassThru to 0xFFFF + + AhciBusInterface->PrevPortNum = 0xffff; + AhciBusInterface->PrevPortMultiplierPortNum = 0xffff; + + // + // Init AHCI Controller + // + Status = AhciInitController(AhciBusInterface); + if (EFI_ERROR(Status)) return Status; + + Status = pBS->InstallProtocolInterface( + &Controller, + &gEfiAhciBusProtocolGuid, + EFI_NATIVE_INTERFACE, + AhciBusInterface); + + return Status; +} + +//********************************************************************** +// +// +// Procedure: AhciInitController +// +// Description: Initializes AHCI Controller +// +// Input: +// IN OUT AHCI_BUS_PROTOCOL *AhciBusInterface +// +// Output: +// EFI_STATUS +// +// +// Notes: +// 1. Update internal Data area about the AHCI controller Capabilities. +// 2. Allocate memory for FIS and CommandList +// 3. Enable AHCI mode +// 3. Disable all the ports +// +// +//********************************************************************** +EFI_STATUS +AhciInitController ( + IN OUT AHCI_BUS_PROTOCOL *AhciBusInterface +) +{ + EFI_STATUS Status; + UINT8 PciConfig[40]; + UINT32 PortsImplemented; + UINT8 i, PortNumber; + UINT32 AhciBaseAddr; + UINTN AllocatePageSize = 0; + UINT32 Data32; + + + // + // Make sure AHCI Base address is programmed Properly + // + Status = AhciBusInterface->PciIO->Pci.Read ( + AhciBusInterface->PciIO, + EfiPciIoWidthUint8, + 0, + sizeof (PciConfig), + PciConfig + ); + + if (EFI_ERROR(Status)) { return Status;} + + AhciBusInterface->AhciBaseAddress = *(UINT32 *)(PciConfig + PCI_ABAR); + if (!AhciBusInterface->AhciBaseAddress) return EFI_DEVICE_ERROR; + + AhciBaseAddr = (UINT32) (AhciBusInterface->AhciBaseAddress); + +#if INDEX_DATA_PORT_ACCESS + Status = InitilizeIndexDataPortAddress (AhciBusInterface->PciIO); +#endif + + // + // Get AHCI Capability + // + AhciBusInterface->HBACapability = HBA_REG32(AhciBaseAddr, HBA_CAP); + if (AhciBusInterface->HBACapability == 0xFFFFFFFF) return EFI_DEVICE_ERROR; // Not decoded properly + + // + // Get # of Ports Implemented (bit map) + // + AhciBusInterface->HBAPortImplemented = HBA_REG32(AhciBaseAddr, HBA_PI); + if (!AhciBusInterface->HBAPortImplemented) return EFI_DEVICE_ERROR; + + // + // Cross check whether # of Ports implemented is less or equal to + // Max. # of ports supported by the silicon + // + PortsImplemented = AhciBusInterface->HBAPortImplemented; + AhciBusInterface->NumberofPortsImplemented = 0; + for ( ;PortsImplemented; PortsImplemented >>= 1){ + if (PortsImplemented & 1) AhciBusInterface->NumberofPortsImplemented++; + } + if (((AhciBusInterface->HBACapability & HBA_CAP_NP_MASK) + 1) < AhciBusInterface->NumberofPortsImplemented) + { return EFI_DEVICE_ERROR; } + + // + // Get the HBA version # + // + AhciBusInterface->AhciVersion = HBA_REG32(AhciBaseAddr, HBA_VS); + + // + // Set AE bit + // + HBA_REG32_OR(AhciBaseAddr, HBA_GHC, HBA_GHC_AE); + + // + // Allocate memory for FIS. Should be aligned on 256 Bytes. Each + // Port will have it own FIS data area. + // + + AhciBusInterface->PortFISBaseAddr=0xFFFFFFFF; + AllocatePageSize = AhciBusInterface->NumberofPortsImplemented * RECEIVED_FIS_SIZE + 0x100; + + Status = pBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + EFI_SIZE_TO_PAGES(AllocatePageSize), // Bytes->4KiloBytes conversion + (EFI_PHYSICAL_ADDRESS*)&(AhciBusInterface->PortFISBaseAddr)); + + ZeroMemory ((VOID *) AhciBusInterface->PortFISBaseAddr, + AhciBusInterface->NumberofPortsImplemented * RECEIVED_FIS_SIZE + 0x100); + AhciBusInterface->PortFISBaseAddrEnd = AhciBusInterface->PortFISBaseAddr + + AhciBusInterface->NumberofPortsImplemented * RECEIVED_FIS_SIZE; + AhciBusInterface->Address1 = AhciBusInterface->PortFISBaseAddr; // Will be used to free the memory later + AhciBusInterface->PortFISBaseAddr = (AhciBusInterface->PortFISBaseAddr & (~0xFF))+ 0x100; + + // + // Allocate memory for Command List (1KB aligned) and Command Table (128KB aligned). + // All the ports in the controller will share Command List and Command table data Area. + // + + AhciBusInterface->PortCommandListBaseAddr=0xFFFFFFFF; + AllocatePageSize = COMMAND_LIST_SIZE_PORT * 2; + + Status = pBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + EFI_SIZE_TO_PAGES(AllocatePageSize), // Bytes->4KiloBytes conversion + (EFI_PHYSICAL_ADDRESS*)&(AhciBusInterface->PortCommandListBaseAddr)); + + ZeroMemory ((VOID *)AhciBusInterface->PortCommandListBaseAddr, COMMAND_LIST_SIZE_PORT * 2); + AhciBusInterface->Address2 = AhciBusInterface->PortCommandListBaseAddr; + + AhciBusInterface->PortCommandListBaseAddr = (AhciBusInterface->PortCommandListBaseAddr & (~0x3FF)) + 0x400; + AhciBusInterface->PortCommandListLength = 0x20; + AhciBusInterface->PortCommandTableBaseAddr = AhciBusInterface->PortCommandListBaseAddr + 0x80; + AhciBusInterface->PortCommandTableLength = COMMAND_LIST_SIZE_PORT - 0x80; + + // + // Make sure controller is not running + // + PortsImplemented = AhciBusInterface->HBAPortImplemented; + PortNumber = 0; + for (i=0; PortsImplemented; PortsImplemented>>=1, PortNumber++){ + if (PortsImplemented & 1) { + + // + // Program PxCLB and PxFB + // + HBA_PORT_WRITE_REG32 (AhciBaseAddr, PortNumber, HBA_PORTS_CLB,AhciBusInterface->PortCommandListBaseAddr); + + HBA_PORT_WRITE_REG32 (AhciBaseAddr, PortNumber, 0x0008, AhciBusInterface->PortFISBaseAddr +(i * RECEIVED_FIS_SIZE)); + + // + // Clear Start + // + HBA_PORT_REG32_AND(AhciBaseAddr, PortNumber, HBA_PORTS_CMD, ~(HBA_PORTS_CMD_ST)); + + // + // Make sure CR is 0 with in 500msec + // + Status = WaitForMemClear(AhciBaseAddr, PortNumber, HBA_PORTS_CMD, + HBA_PORTS_CMD_CR, + HBA_CR_CLEAR_TIMEOUT + ); + + if (EFI_ERROR(Status)) { + // Get the Port Speed allowed and Interface Power Management Transitions Allowed + // Pass the values for PortReset. + Data32 = HBA_PORT_REG32 ((UINT32)(AhciBusInterface->AhciBaseAddress), PortNumber, HBA_PORTS_SCTL); + Data32 &= 0xFF0; + + Status = GeneratePortReset(AhciBusInterface, NULL, PortNumber, 0xFF, + (UINT8)((Data32 & 0xF0) >> 4), (UINT8)(Data32 >> 8)); + } + + if (EFI_ERROR(Status)) { + HostReset(AhciBusInterface); + } + + // + // Clear FIS receive enable. + // + HBA_PORT_REG32_AND (AhciBaseAddr, PortNumber, + HBA_PORTS_CMD, ~(HBA_PORTS_CMD_FRE)); + // + // Make sure FR is 0 with in 500msec + // + Status = WaitForMemClear(AhciBaseAddr, PortNumber, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + if (EFI_ERROR(Status)) { + continue; + } + + HBA_PORT_REG32_OR (AhciBaseAddr, PortNumber, + HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); // Clear Status register + + i++; + } + } + return EFI_SUCCESS; +} + + +// +//---------------------------------------------------------------------------- +// Procedure: CheckPortImplemented +// +// Description: Check if the port is implemented in the AHCI Controller +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN UINT8 Port +// +// Output: +// EFI_STATUS +// +// Notes: +// 1. Check Port Implemented register whether the PORT is +// implemented in the Controller or not. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +CheckPortImplemented ( + IN AHCI_BUS_PROTOCOL *AhciBusInterface, + IN UINT8 Port +) +{ + + if (AhciBusInterface->HBAPortImplemented & (1<< Port)) return EFI_SUCCESS; + + return EFI_NOT_FOUND; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: AhciDetectDevice +// +// Description: Detects a SATA device connected to given Port and PMPort +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, +// IN UINT8 Port, +// IN UINT8 PMPort +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: CheckDevicePresence CheckPMDevicePresence GenerateSoftReset +// +// Notes: +// 1. if CheckDevicePresence fails exit. +// 2. If Controller supports PM, issue Softreset +// 3. Check the Device Signature. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +AhciDetectDevice ( + IN AHCI_BUS_PROTOCOL *AhciBusInterface, + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, + IN UINT8 Port, + IN UINT8 PMPort +) +{ + + EFI_STATUS Status; + UINT32 AhciBaseAddr = (UINT32)(AhciBusInterface->AhciBaseAddress); + SATA_DEVICE_INTERFACE *SataDevInterface = NULL; + + PROGRESS_CODE(DXE_IDE_DETECT); + + IdeControllerInterface->NotifyPhase (IdeControllerInterface, EfiIdeBusBeforeDevicePresenceDetection, Port); + + SataDevInterface = GetSataDevInterface(AhciBusInterface, Port, PMPort); + + if (!SataDevInterface){ + + // + // A device is present. + // + Status = pBS->AllocatePool (EfiBootServicesData, + sizeof(SATA_DEVICE_INTERFACE), + (VOID**)&SataDevInterface); + if (EFI_ERROR(Status)) return Status; + + ZeroMemory (SataDevInterface, sizeof(SATA_DEVICE_INTERFACE)); + + SataDevInterface->PortNumber = Port; + SataDevInterface->PMPortNumber = PMPort; + SataDevInterface->AhciBusInterface = AhciBusInterface; + SataDevInterface->DeviceState = DEVICE_IN_RESET_STATE; + + // + // Update Base addresses + // + SataDevInterface->PortCommandListBaseAddr = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_CLB); + SataDevInterface->PortFISBaseAddr = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_FB); + + // + // Add to the AhciBusInterface + // + DListAdd(&(AhciBusInterface->SataDeviceList), &(SataDevInterface->SataDeviceLink)); + + + } + + if (PMPort == 0xFF) { + Status = CheckDevicePresence (SataDevInterface, IdeControllerInterface, Port, PMPort); + } + else { + Status = CheckPMDevicePresence (SataDevInterface, IdeControllerInterface, Port, PMPort); + } + + if (EFI_ERROR(Status)) { + IdeControllerInterface->NotifyPhase (IdeControllerInterface, EfiIdeBusAfterDevicePresenceDetection, Port); + if (SataDevInterface->DeviceState == DEVICE_IN_RESET_STATE) { + DListDelete(&(AhciBusInterface->SataDeviceList), &(SataDevInterface->SataDeviceLink)); + pBS->FreePool(SataDevInterface); + } + return EFI_DEVICE_ERROR; + } + + #if PORT_MULTIPLIER_SUPPORT + // + // Check if PM support is present + // + if (AhciBusInterface->HBACapability & HBA_CAP_SPM) { + Status = GenerateSoftReset(SataDevInterface, PMPort == 0xFF ? CONTROL_PORT : PMPort); + if (EFI_ERROR(Status)) { + + // + // We know link has been established, meaning device is + // present. Maybe we need delay before giving a Soft reset. + // + Status = ReadytoAcceptCmd(SataDevInterface); + if (!EFI_ERROR(Status)){ + pBS->Stall(3000000); // 3sec delay + Status = GenerateSoftReset(SataDevInterface, PMPort == 0xFF ? CONTROL_PORT : PMPort); + } + } + + if (EFI_ERROR(Status)) { + IdeControllerInterface->NotifyPhase (IdeControllerInterface, EfiIdeBusAfterDevicePresenceDetection, Port); + if (SataDevInterface->DeviceState == DEVICE_IN_RESET_STATE) { + DListDelete(&(AhciBusInterface->SataDeviceList), &(SataDevInterface->SataDeviceLink)); + pBS->FreePool(SataDevInterface); + } + return EFI_DEVICE_ERROR; + } + } + #endif + + if (!(SataDevInterface->PortCommandListBaseAddr) || !(SataDevInterface->PortFISBaseAddr)) { + ASSERT_EFI_ERROR(EFI_DEVICE_ERROR); + } + + // + // Save the Signature + // + SataDevInterface->Signature = HBA_PORT_REG32(AhciBaseAddr, Port, HBA_PORTS_SIG); + switch (SataDevInterface->Signature) { + case ATA_SIGNATURE_32: + SataDevInterface->DeviceType = ATA; + break; + case ATAPI_SIGNATURE_32: + SataDevInterface->DeviceType = ATAPI; + break; + case PMPORT_SIGNATURE: + SataDevInterface->DeviceType = PMPORT; + // 1 sec Delay needed for the next device to be discovered from PM. + pBS->Stall(1000000); + break; + default: + Status = EFI_DEVICE_ERROR; + } + +#if !HDD_PASSWORD_SUPPORT_UNDER_RAIDMODE + if ((!AhciBusInterface->AHCIRAIDMODE) && (SataDevInterface->DeviceType == ATA)) { + DListDelete(&(AhciBusInterface->SataDeviceList), &(SataDevInterface->SataDeviceLink)); + pBS->FreePool(SataDevInterface); + Status = EFI_DEVICE_ERROR; + } +#endif + +#if !SUPPORT_ATAPI_IN_RAID_MODE + + // + // If the Atapi devices are handled by Raid option rom, then + // don't configure the Atapi devices. + // + if ((!AhciBusInterface->AHCIRAIDMODE) && (SataDevInterface->DeviceType == ATAPI)) { + DListDelete(&(AhciBusInterface->SataDeviceList), &(SataDevInterface->SataDeviceLink)); + pBS->FreePool(SataDevInterface); + Status = EFI_DEVICE_ERROR; + } +#endif + IdeControllerInterface->NotifyPhase (IdeControllerInterface, EfiIdeBusAfterDevicePresenceDetection, Port); + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: CheckDevicePresence +// +// Description: Check if any device is connected to the port +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, +// IN UINT8 Port, +// IN UINT8 PMPort +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: HandlePortComReset CheckValidDevice GeneratePortReset +// +// Notes: +// 1. If Staggered spin-up is supported, power-up the device. +// 2. Call CheckValidDevice if success exit. Else generate Softreset. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +CheckDevicePresence ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, + IN UINT8 Port, + IN UINT8 PMPort +) +{ + + EFI_STATUS Status; + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + UINT32 AhciBaseAddr = (UINT32)(AhciBusInterface->AhciBaseAddress); + UINT8 CapIss; + UINT8 PortSpeed=0; + UINT8 CurrentPortSpeed=0; + UINT32 Data32; + + // + // PM disabled + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SCTL, HBA_PORTS_SCTL_IPM_PSD_SSD); + + // + // Clear Status register + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + // + // Get the Interface Speed Support( Maximum Speed supported) + // + CapIss = (UINT8)((HBA_REG32(AhciBaseAddr, HBA_CAP) & HBA_CAP_ISS_MASK)>>20); + + // + // Get the Speed Allowed (SPD) for the Port. Maximum speed allowed for the Port + // + PortSpeed = (UINT8)((HBA_PORT_REG32(AhciBaseAddr, Port, HBA_PORTS_SCTL) + & HBA_PORTS_SCTL_SPD_MASK)>>4); + + // + // If the Maximum speed allowed is programmed for the port, use the Port Speed allowed value + // + if(PortSpeed != 0 ) { + if(PortSpeed > CapIss) { + // + // Port Speed allowed can't be more than Interface Speed. So limit Port speed to Interface Speed + // + PortSpeed = CapIss; + } + } else { + // + // If there is no Maximum speed allowed for the port, use the Interface Speed + // + PortSpeed = CapIss; + } + + // + // Check if Link is already established + // + if ((HBA_PORT_REG32 (AhciBusInterface->AhciBaseAddress, Port, HBA_PORTS_SSTS) + & HBA_PORTS_SSTS_DET_MASK) == HBA_PORTS_SSTS_DET_PCE) { + + // + // As the Link is already established, get the negotiated interface + // communication speed + // + CurrentPortSpeed = (UINT8)((HBA_PORT_REG32(AhciBaseAddr, Port, HBA_PORTS_SSTS) + & HBA_PORTS_SSTS_SPD_MASK)>>4); + + // + // Check the Current Interface Speed with Speed Allowed. If current inerface speed is more than + // Speed allowed set, then set the port speed according to the speed allowed + // + if( CurrentPortSpeed > PortSpeed) { + + Status = GeneratePortReset(AhciBusInterface, SataDevInterface, Port, PMPort, + PortSpeed, HBA_PORTS_SCTL_IPM_PSSD); + } + } else { + // + // Link Not Established. Set SPD by PortSpeed + // + CapIss = (UINT8)((HBA_REG32(AhciBaseAddr, HBA_CAP) & HBA_CAP_ISS_MASK)>>20); + HBA_PORT_REG32_AND_OR (AhciBaseAddr, Port, HBA_PORTS_SCTL, ~HBA_PORTS_SCTL_SPD_MASK,PortSpeed<<4 ); + } + + // + // Check if Staggered Spinup is supported + // + if (HBA_REG32 (AhciBaseAddr, HBA_CAP) & HBA_CAP_SSS) { + + // + // Check if Link is already established, if yes dodn't expect a COMRESET + // + if ((HBA_PORT_REG32 (AhciBusInterface->AhciBaseAddress, Port, HBA_PORTS_SSTS) + & HBA_PORTS_SSTS_DET_MASK) != HBA_PORTS_SSTS_DET_PCE) { + // + // Enable FIS Receive Enable + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_FRE); + + // + // Wait till FIS is running + // + WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_SUD); // Spin up the device + + // + // Todo Todo delay necessary here after power up? + // + Status = HandlePortComReset(AhciBusInterface, NULL, Port, 0xFF); + + // + // Disable FIS Receive Enable + // + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_CMD, ~HBA_PORTS_CMD_FRE); + + IdeControllerInterface->NotifyPhase (IdeControllerInterface, EfiIdeBusAfterDevicePresenceDetection, Port); + } + else { + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_SUD); // Spin up the device + } + } + + // + // Check if Device detected. And check if Cold Presence logic + // is enabled. If yes enable POD + // + if (((HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_SSTS) & HBA_PORTS_SSTS_DET_MASK) == HBA_PORTS_SSTS_DET_PCE) && + (HBA_PORT_REG32(AhciBaseAddr, Port, HBA_PORTS_CMD) & HBA_PORTS_CMD_CPD)) { + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_POD); + } + + Status = CheckValidDevice(AhciBusInterface, Port, PMPort); + +#if PORT_MULTIPLIER_SUPPORT + // If PORT Multiplier support is enabled, SoftReset generated later will get the signature. + // No need for this additional Port Reset here + if ((HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_SSTS) & HBA_PORTS_SSTS_DET_MASK) == HBA_PORTS_SSTS_DET_PCE) { + return EFI_SUCCESS; + } +#else + if (EFI_ERROR(Status)) { + IdeControllerInterface->NotifyPhase ( + IdeControllerInterface, + EfiIdeBeforeChannelReset, + (UINT8)Port + ); + + // Get the Port Speed allowed and Interface Power Management Transitions Allowed + // Pass the values for PortReset. + Data32 = HBA_PORT_REG32 ((UINT32)(AhciBusInterface->AhciBaseAddress), Port, HBA_PORTS_SCTL); + Data32 &= 0xFF0; + + Status = GeneratePortReset( + AhciBusInterface, + SataDevInterface, + Port, + PMPort, + (UINT8)((Data32 & 0xF0) >> 4), + (UINT8)(Data32 >> 8) + ); + + IdeControllerInterface->NotifyPhase ( + IdeControllerInterface, + EfiIdeAfterChannelReset, + (UINT8)Port + ); + } +#endif + return Status; +} + +// +//---------------------------------------------------------------------------- +// Procedure: CheckPMDevicePresence +// +// Description: Checks for the presence device behind a Port Multiplier. +// +// Input: +// SATA_DEVICE_INTERFACE *SataDevInterface, +// EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, +// UINT8 Port, +// UINT8 PMPort +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ReadWritePMPort GeneratePortReset +// +// Notes: +// 1. Check whether communication is established? +// 2. If yes exit else issues Port Reset +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +CheckPMDevicePresence ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, + IN UINT8 Port, + IN UINT8 PMPort +) +{ + + EFI_STATUS Status = EFI_DEVICE_ERROR; + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + UINT32 AhciBaseAddr = (UINT32)(AhciBusInterface->AhciBaseAddress); + UINT32 Data32 = 0, Init_SStatus = 0; + + ReadWritePMPort (SataDevInterface, PMPort, PSCR_0_SSTATUS, &Init_SStatus, FALSE); + + SataDevInterface->SControl = HBA_PORTS_SCTL_IPM_PSD_SSD; + if ((Init_SStatus & HBA_PORTS_SSTS_DET_MASK) == HBA_PORTS_SSTS_DET_PCE) { + Data32 = HBA_PORTS_SCTL_IPM_PSD_SSD; + ReadWritePMPort (SataDevInterface, PMPort, PSCR_2_SCONTROL, &Data32, TRUE); + } else { + + // + // Perform Port Reset to bring the communication back + // + IdeControllerInterface->NotifyPhase ( + IdeControllerInterface, + EfiIdeBeforeChannelReset, + (UINT8)Port + ); + + // Get the Port Speed allowed and Interface Power Management Transitions Allowed + // Pass the values for PortReset. + Data32 = HBA_PORT_REG32 ((UINT32)(AhciBusInterface->AhciBaseAddress), Port, HBA_PORTS_SCTL); + Data32 &= 0xFF0; + + Status = GeneratePortReset( + AhciBusInterface, + SataDevInterface, + Port, + PMPort, + (UINT8)((Data32 & 0xF0) >> 4), + (UINT8)(Data32 >> 8) + ); + + IdeControllerInterface->NotifyPhase ( + IdeControllerInterface, + EfiIdeAfterChannelReset, + (UINT8)Port + ); + + // Giving a Softreset immediatly after Port Reset doesn't help to detect the + // devices behind PM quickly. Add a delay here before Softreset is generated. + // Add 1Sec delay + pBS->Stall(1000000); + } + + // + // Clear Status register + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + Data32 = HBA_PORTS_ERR_CLEAR; + ReadWritePMPort (SataDevInterface, PMPort, PSCR_1_SERROR, &Data32, TRUE); + + Data32 = 0; + ReadWritePMPort (SataDevInterface, PMPort, PSCR_0_SSTATUS, &Data32, FALSE); + + if ((Data32 & HBA_PORTS_SSTS_DET_MASK) == HBA_PORTS_SSTS_DET_PCE) Status = EFI_SUCCESS; + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: ConfigureSataPort +// +// Description: Configure Sata Port settings +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// +// Output: +// EFI_SUCCESS +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ConfigureSataPort ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +) +{ + + // Check for the ATAPI device + if (SataDevInterface->DeviceType == ATAPI) { + // + // Set Device is ATAPI Bit in CMD register + // + HBA_PORT_REG32_OR ( + SataDevInterface->AhciBusInterface->AhciBaseAddress, + SataDevInterface->PortNumber, + HBA_PORTS_CMD, + HBA_PORTS_CMD_ATAPI + ); + } + + // Check the AHCI platform policy protocol to set the + // Drive LED on ATAPI Enable (DLAE) bit + + if(AhciPlatformPolicy->DriverLedOnAtapiEnable) { + // + // Set Drive LED on ATAPI Enable (DLAE) Bit in CMD register + // + HBA_PORT_REG32_OR ( + SataDevInterface->AhciBusInterface->AhciBaseAddress, + SataDevInterface->PortNumber, + HBA_PORTS_CMD, + HBA_PORTS_CMD_DLAE + ); + } + + return EFI_SUCCESS; +} + + +// +//---------------------------------------------------------------------------- +// Procedure: ConfigurePMPort +// +// Description: Configure Port Multiplier +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// +// Output: +// +// Modified: +// +// Referrals: ReadWritePMPort +// +// Notes: +// 1. Read the number of Ports implemented in the Port Multiplier +// 2. Update PM attached bit in the AHCI controller. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ConfigurePMPort ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +) +{ + EFI_STATUS Status; + UINT32 Data; + + // + // Read the number of Ports preset in PM + // + Status = ReadWritePMPort (SataDevInterface, CONTROL_PORT, GSCR_2, &Data, FALSE); + SataDevInterface->NumPMPorts = ((UINT8)Data) - 1; + + // + // Set PM Attched bit in CMD register + // + HBA_PORT_REG32_OR ( + SataDevInterface->AhciBusInterface->AhciBaseAddress, + SataDevInterface->PortNumber, + HBA_PORTS_CMD, + HBA_PORTS_CMD_PMA + ); + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: ConfigureDevice +// +// Description: Configure the SATA device +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// IN OUT EFI_ATA_COLLECTIVE_MODE **SupportedModes - +// Modes collection supported by the device +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: GetIdentifyData, GeneratePortReset, ExecuteNonDataCommand, InitAcousticSupport +// +// Notes: +// 1. Get the Identify data command. +// 2. From the IdeControllerInit protocol, get the DMA & PIO supported +// 3. Issue Set feature command to set PIO, DMA and multiple mode +// 4. Initialize Acoustic, SMART, Power Management features. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ConfigureDevice ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT EFI_ATA_COLLECTIVE_MODE **SupportedModes +) +{ + + EFI_STATUS Status; + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface = AhciBusInterface->IdeControllerInterface; + UINT8 Port = SataDevInterface->PortNumber; + UINT8 PMPort = SataDevInterface->PMPortNumber; + COMMAND_STRUCTURE CommandStructure; + UINT8 Data8; + UINT32 Data32; + UINT8 Index; + UINT16 DeviceName[41]; + CHAR8 Language[] = "Eng"; + EFI_UNICODE_STRING_TABLE *tempUnicodeTable; + + + if (SataDevInterface->DeviceType == PMPORT) return EFI_SUCCESS; // This is a Port Multiplier + + Status = GetIdentifyData(SataDevInterface); + if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR; + +#if !DISABLE_SOFT_SET_PREV +#if FORCE_HDD_PASSWORD_PROMPT + if ((SataDevInterface->DeviceType == ATA) && + (SataDevInterface->IdentifyData.Reserved_76_79[0] != 0xFFFF )&& + (SataDevInterface->IdentifyData.Reserved_76_79[2] & 0x0040)&& // Software Preservation support + (SataDevInterface->IdentifyData.Reserved_76_79[3] & 0x0040)){ // Software Preservation Enabled + + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + + CommandStructure.Features = DISABLE_SATA2_SOFTPREV; // Disable Software Preservation + CommandStructure.SectorCount = 6; + CommandStructure.Command = SET_FEATURE_COMMAND; + ExecuteNonDataCommand (SataDevInterface, CommandStructure); + + // Get the Port Speed allowed and Interface Power Management Transitions Allowed + // Pass the values for PortReset. + Data32 = HBA_PORT_REG32 ((UINT32)(AhciBusInterface->AhciBaseAddress), Port, HBA_PORTS_SCTL); + Data32 &= 0xFF0; + + GeneratePortReset(AhciBusInterface, + SataDevInterface, + Port, + PMPort, + (UINT8)((Data32 & 0xF0) >> 4), + (UINT8)(Data32 >> 8) + ); + + CommandStructure.Features = 0x10; // Enable Software Preservation + CommandStructure.SectorCount = 6; + CommandStructure.Command = SET_FEATURE_COMMAND; + ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } +#endif +#endif + + // + // Check if Device need spin-up + // + if ((SataDevInterface->IdentifyData.General_Config_0 & 4) && + (SataDevInterface->IdentifyData.Special_Config_2 == SPIN_UP_REQUIRED1 || + SataDevInterface->IdentifyData.Special_Config_2 == SPIN_UP_REQUIRED2 )){ + + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Features = SET_DEVICE_SPINUP; + CommandStructure.Command = SET_FEATURE_COMMAND; + Status = ExecuteNonDataCommand (SataDevInterface, CommandStructure); + + // + // Get the Identify Command once more + // + Status = GetIdentifyData(SataDevInterface); + if (EFI_ERROR(Status)){ + return EFI_DEVICE_ERROR; + } + } + + Status = IdeControllerInterface->SubmitData(IdeControllerInterface, + Port, + PMPort == 0xFF ? 0 : PMPort, + (EFI_IDENTIFY_DATA *) &(SataDevInterface->IdentifyData)); + if (EFI_ERROR(Status)) + return Status; + + Status = IdeControllerInterface->CalculateMode(IdeControllerInterface, + Port, + PMPort == 0xFF ? 0 : PMPort, + SupportedModes); + + if (EFI_ERROR(Status) || (*SupportedModes == NULL) ) + return EFI_INVALID_PARAMETER; + + // + // Check ExtMode + // + if ((*SupportedModes)->ExtMode[0].TransferProtocol) { // Not Auto speed + Status = GeneratePortReset(AhciBusInterface, SataDevInterface, Port, PMPort, + (*SupportedModes)->ExtMode[0].TransferProtocol, HBA_PORTS_SCTL_IPM_PSSD); + if (PMPort != 0xFF) { + Data32 = HBA_PORTS_ERR_CLEAR; + ReadWritePMPort (SataDevInterface, PMPort, PSCR_1_SERROR, &Data32, TRUE); + } + } + + Status = IdeControllerInterface->SetTiming(IdeControllerInterface, + Port, + PMPort == 0xFF ? 0 : PMPort, + (*SupportedModes)); + if (EFI_ERROR(Status)) return Status; + + SataDevInterface->PIOMode = 0xff; + SataDevInterface->SWDma = 0xff; + SataDevInterface->MWDma = 0xff; + SataDevInterface->UDma = 0xff; + + if ((*SupportedModes)->PioMode.Valid) + SataDevInterface->PIOMode = (*SupportedModes)->PioMode.Mode; + + if ((*SupportedModes)->SingleWordDmaMode.Valid) + SataDevInterface->SWDma = (*SupportedModes)->SingleWordDmaMode.Mode; + + if ((*SupportedModes)->MultiWordDmaMode.Valid) + SataDevInterface->MWDma = (*SupportedModes)->MultiWordDmaMode.Mode; + + if ((*SupportedModes)->UdmaMode.Valid) + SataDevInterface->UDma = (*SupportedModes)->UdmaMode.Mode; + + SataDevInterface->IORdy = ((EFI_IDENTIFY_DATA *)&(SataDevInterface->IdentifyData))->AtaData.capabilities & 0x800; + + if ((SataDevInterface->IdentifyData.Valid_Bits_53 & 0x2) && ((*SupportedModes)->PioMode.Valid)){ + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Features = SET_TRANSFER_MODE; + CommandStructure.Command = SET_FEATURE_COMMAND; + CommandStructure.SectorCount = PIO_FLOW_CONTROL | SataDevInterface->PIOMode; + Status = ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } + + if (EFI_ERROR(Status)) + return EFI_DEVICE_ERROR; + + // + // Issue Set Multiple Mode Command only for ATA device + // + if (SataDevInterface->DeviceType == ATA){ + Data8 = SataDevInterface->IdentifyData.Maximum_Sector_Multiple_Command_47 & 0xff; + if (Data8 & 0x2) Data8 = 2; + if (Data8 & 0x4) Data8 = 0x4; + if (Data8 & 0x8) Data8 = 0x8; + if (Data8 & 0x10) Data8 = 0x10; + if (Data8 & 0x20) Data8 = 0x20; + if (Data8 & 0x40) Data8 = 0x40; + if (Data8 & 0x80) Data8 = 0x80; + + if (Data8 > 1) { + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Command = SET_MULTIPLE_MODE; + CommandStructure.SectorCount = Data8; + Status = ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } + } + + // + // Check if UDMA is supported + // + if (SataDevInterface->UDma != 0xff){ + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Features = SET_TRANSFER_MODE; + CommandStructure.Command = SET_FEATURE_COMMAND; + CommandStructure.SectorCount = UDMA_MODE | SataDevInterface->UDma; + Status = ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } + else { + if (SataDevInterface->MWDma != 0xff){ + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Features = SET_TRANSFER_MODE; + CommandStructure.Command = SET_FEATURE_COMMAND; + CommandStructure.SectorCount = MWDMA_MODE | SataDevInterface->MWDma; + Status = ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } + } + + // + // Convert the Device string from Engligh to Unicode + // + SataDevInterface->UDeviceName = NULL; + for (Index = 0; Index < 40; Index += 2) { + DeviceName[Index] = ((UINT8 *)SataDevInterface->IdentifyData.Model_Number_27)[Index + 1]; + DeviceName[Index + 1] = ((UINT8 *)SataDevInterface->IdentifyData.Model_Number_27)[Index]; + } + DeviceName[40] = 0; // Word + + tempUnicodeTable = MallocZ(sizeof (EFI_UNICODE_STRING_TABLE) * 2); + Status = pBS->AllocatePool (EfiBootServicesData, + sizeof (Language), + (VOID**)&tempUnicodeTable[0].Language + ); + + Status = pBS->AllocatePool (EfiBootServicesData, + sizeof (DeviceName), + (VOID**)&tempUnicodeTable[0].UnicodeString + ); + + pBS->CopyMem(tempUnicodeTable[0].Language, &Language, sizeof(Language)); + pBS->CopyMem(tempUnicodeTable[0].UnicodeString, DeviceName, sizeof (DeviceName)); + tempUnicodeTable[1].Language = NULL; + tempUnicodeTable[1].UnicodeString = NULL; + SataDevInterface->UDeviceName = tempUnicodeTable; + + #if SBIDE_SUPPORT + InitMiscConfig(SataDevInterface); + #endif + + + if( AhciPlatformPolicy->DipmSupport) { + // Initialize and Enable Device initiated Power management + InitializeDipm(SataDevInterface); + } + + if( AhciPlatformPolicy->DeviceSleepSupport) { + // Initialize and Enable Device Sleep Support + InitializeDeviceSleep(SataDevInterface); + } + + + ConfigurePowerUpInStandby(SataDevInterface); + + Status = GetIdentifyData(SataDevInterface); + if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: ConfigureController +// +// Description: Configure the AHCI Controller +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// IN EFI_ATA_COLLECTIVE_MODE *SupportedModes - +// Modes collection supported by the device +// +// Output: +// EFI_STATUS +// +// +// Notes: +// 1. Issue IdeControllerInterface->SetTiming for setting uDMA +// and PIO mode timings in the controller. +// 2. Update the Read/Write command for the device +// 3. Update the Device name used in Component Name protocol +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ConfigureController ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN EFI_ATA_COLLECTIVE_MODE *SupportedModes +) +{ + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface = AhciBusInterface->IdeControllerInterface; + UINT8 Port = SataDevInterface->PortNumber; + UINT8 PMPort = SataDevInterface->PMPortNumber; + + // + // Check if UDMA and MWDMA are programmed successfully + // + if (SataDevInterface->UDma != 0xff) { + if (!(ReturnMSBset((SataDevInterface->IdentifyData.UDMA_Mode_88 >> 8)) == SataDevInterface->UDma)) { + SataDevInterface->UDma = ReturnMSBset((SataDevInterface->IdentifyData.UDMA_Mode_88 >> 8)); + SupportedModes->UdmaMode.Mode = SataDevInterface->UDma; + IdeControllerInterface->SetTiming (IdeControllerInterface, Port, + PMPort == 0xFF ? 0 : PMPort, SupportedModes); + } + } + else { + if (SataDevInterface->MWDma != 0xff) { + if (!(ReturnMSBset(SataDevInterface->IdentifyData.MultiWord_DMA_63 >> 8) == SataDevInterface->MWDma)) { + SataDevInterface->MWDma = ReturnMSBset((SataDevInterface->IdentifyData.MultiWord_DMA_63 >> 8)); + SupportedModes->MultiWordDmaMode.Mode = SataDevInterface->MWDma; + IdeControllerInterface->SetTiming (IdeControllerInterface, Port, + PMPort == 0xFF ? 0 : PMPort, SupportedModes); + } + } + } + + // + // Check for ATA + // + if (SataDevInterface->DeviceType == ATA) { + + // + // Update IDE Read/Write Command + // + if ((SataDevInterface->IdentifyData.Valid_Bits_59 & 0x100) && + (SataDevInterface->IdentifyData.Valid_Bits_59 & 0xff)) { // Check if Multiple Read/Write + if (SataDevInterface->IdentifyData.Command_Set_Supported_83 & 0x400) { + + // + // 48Bit LBA supported + // + SataDevInterface->ReadCommand = READ_MULTIPLE_EXT; + SataDevInterface->WriteCommand = WRITE_MULTIPLE_EXT; + } + else { + SataDevInterface->ReadCommand = READ_MULTIPLE; + SataDevInterface->WriteCommand = WRITE_MULTIPLE; + } + } // End of Multiple + else { // 1 Block = 1 Sector + if (SataDevInterface->IdentifyData.Command_Set_Supported_83 & 0x400) { + + // + // 48Bit LBA supported + // + SataDevInterface->ReadCommand = READ_SECTORS_EXT; + SataDevInterface->WriteCommand = WRITE_SECTORS_EXT; + } + else { + SataDevInterface->ReadCommand = READ_SECTORS; + SataDevInterface->WriteCommand = WRITE_SECTORS; + } + } + if (DMACapable(SataDevInterface)) { + #if IDEBUSMASTER_SUPPORT + SataDevInterface->ReadCommand = READ_DMA; + SataDevInterface->WriteCommand = WRITE_DMA; + if (SataDevInterface->IdentifyData.Command_Set_Supported_83 & 0x400) { + + // + // 48Bit LBA supported + // + SataDevInterface->ReadCommand = READ_DMA_EXT; + SataDevInterface->WriteCommand = WRITE_DMA_EXT; + } + #endif + } + } // end of ATA + +#if DISABLE_SOFT_SET_PREV + + // + // Software settings preserved + // + if ((SataDevInterface->DeviceType == ATA) && + (SataDevInterface->IdentifyData.Reserved_76_79[0] != 0xFFFF )&& + (SataDevInterface->IdentifyData.Reserved_76_79[2] & 0x0040)) { + + COMMAND_STRUCTURE CommandStructure; + EFI_STATUS Status; + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Command = SET_FEATURE_COMMAND; + CommandStructure.Features = DISABLE_SATA2_SOFTPREV; + CommandStructure.SectorCount = 6; + ExecuteNonDataCommand (SataDevInterface, CommandStructure); + + // + // Update the Identify device buffer + // + Status = GetIdentifyData(SataDevInterface); + if (EFI_ERROR(Status)){ + return EFI_DEVICE_ERROR; + } + } +#endif + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: InitializeDipm +// +// Description: Initialize Dipm in the device and controller +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// VOID +// +// +// Notes: +// +//---------------------------------------------------------------------------- +// +VOID +InitializeDipm ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +) +{ + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + COMMAND_STRUCTURE CommandStructure; + + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Command = SET_FEATURE_COMMAND; + CommandStructure.SectorCount = DiPM_SUB_COMMAND; // 0x03 : DiPM + + // Check Host Supports Aggressive Link Power Management + // and Check DiPM supported by device + + if((SataDevInterface->AhciBusInterface->HBACapability & HBA_CAP_SALP) && + (SataDevInterface->IdentifyData.Reserved_76_79[0] & IDENTIFY_DiPM_HIIPM_REQUESTS_CAPABLE) && + (SataDevInterface->IdentifyData.Reserved_76_79[2] & IDENTIFY_DiPM__SUPPORT)){ + + // Check DiPM needs to be enabled from Platform Policy + if(AhciPlatformPolicy->DipmEnable) { + // Check DiPM is already enabled via Identify Data Word. + if (!(SataDevInterface->IdentifyData.Reserved_76_79[3] & IDENTIFY_DiPM_ENABLED)) { + // Enable DiPM and Issue Set Feature command. + CommandStructure.Features = DiPM_ENABLE; + ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } + } else { + if (SataDevInterface->IdentifyData.Reserved_76_79[3] & IDENTIFY_DiPM_ENABLED) { + + // Disable DiPM and Issue Set Feature command only if it is enabled already. + CommandStructure.Features = DiPM_DISABLE; + ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } + } + } + return; +} + + + +// +//---------------------------------------------------------------------------- +// Procedure: InitializeDeviceSleep +// +// Description: Initialize Device Sleep in the device and controller +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// VOID +// +// +// Notes: +// +//---------------------------------------------------------------------------- +// + +VOID +InitializeDeviceSleep ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +) +{ + + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + UINT32 AhciBaseAddr = (UINT32)(AhciBusInterface->AhciBaseAddress); + UINT8 PortNumber = SataDevInterface->PortNumber; + COMMAND_STRUCTURE CommandStructure; + EFI_STATUS Status; + UINT8 DevSleep_Exit_TimeOut = DEVSLEEP_EXIT_TIMEOUT; + UINT8 Minimum_DevSleep_Assertion_Time = MINIMUM_DEVSLP_ASSERTION_TIME; + UINT8 DITO_Multiplier = 0xF; + UINT8 *Buffer = NULL; + UINT32 PxDevSlp; + UINT8 SectorCount = 1; + + // If Aggressive DelSlp is supported then DevSlp also supported. Also check if the port supports DevSlp or not + if ((HBA_REG32(AhciBaseAddr, HBA_CAP2) & HBA_CAP2_SADM) && + (HBA_PORT_REG32(AhciBaseAddr, PortNumber, HBA_PORTS_PxDEVSLP) & HBA_PORTS_PxDEVSLP_DSP)) { + + //Clear ADSE + HBA_PORT_REG32_AND (AhciBaseAddr, PortNumber, HBA_PORTS_PxDEVSLP, ~(HBA_PORTS_PxDEVSLP_ADSE)); + + // Check Word 78 Bit8 and Word 77 Bit7 of Identify Data. + if ((SataDevInterface->IdentifyData.Reserved_76_79[2] & IDENTIFY_DEVSLEEP_SUPPORT) && + (SataDevInterface->IdentifyData.Reserved_76_79[1] & IDENTIFY_DEVSLP_TO_REDUCED_PWRSTATE_CAPABLE)) { + + if(AhciPlatformPolicy->DeviceSleepEnable) { + + // DevSlp not enabled in device. Issue Set Feature command. + if (!(SataDevInterface->IdentifyData.Reserved_76_79[3] & IDENTIFY_DEVSLEEP_ENABLED)) { + + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Command = SET_FEATURE_COMMAND; + CommandStructure.SectorCount = DEVSLEEP_SUB_COMMAND; + CommandStructure.Features = DEVSLEEP_ENABLE; + ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } + + // Allocate Memory for Identify Device Data + pBS->AllocatePool(EfiBootServicesData, ATA_SECTOR_BYTES, (VOID**)&Buffer); + ZeroMemory(Buffer, ATA_SECTOR_BYTES); + + // Get Identify Device Data Log (log 30h Page 8) + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Command = READ_LOG_EXT; + CommandStructure.SectorCount = SectorCount; + CommandStructure.LBAMid = SERIAL_ATA_SETTINGS_PAGE; + CommandStructure.LBALow = IDENTIFY_DEVICE_DATA_LOG; + CommandStructure.ByteCount = SectorCount * ATA_SECTOR_BYTES;; + CommandStructure.Buffer = Buffer; + + Status = ExecutePioDataCommand (SataDevInterface, &CommandStructure, FALSE); + if (!EFI_ERROR(Status)){ + + // Update the Time out values + ///BYTE 30h..37h DEVSLP Timing Variables (Qword) of Identify Device Data log (log 30h page 08h) + ///63 Valid + ///62:16 Reserved + ///15:8 DevSleep Exit Timeout, in ms (DETO) + ///5:7 Reserved + ///4:0 Minimum DEVSLP Assertion Time, in ms (MDAT) + + DevSleep_Exit_TimeOut = Buffer[DEVSLP_TIMING_VARIABLES_OFFSET + 1] ? Buffer[DEVSLP_TIMING_VARIABLES_OFFSET + 1] : DEVSLEEP_EXIT_TIMEOUT; + Minimum_DevSleep_Assertion_Time = (Buffer[DEVSLP_TIMING_VARIABLES_OFFSET] & 0x1F) ? (Buffer[DEVSLP_TIMING_VARIABLES_OFFSET] & 0x1F) : MINIMUM_DEVSLP_ASSERTION_TIME; + } + + // Program the Timeouts and Multiplier value in PxDEVSLP Registers + PxDevSlp = HBA_PORT_REG32 (AhciBaseAddr, PortNumber, HBA_PORTS_PxDEVSLP); + PxDevSlp &= ~(HBA_PORTS_PxDEVSLP_DETO_MASK | HBA_PORTS_PxDEVSLP_DMDAT_MASK | HBA_PORTS_PxDEVSLP_DM_MASK); + PxDevSlp |= ((DevSleep_Exit_TimeOut << 2) + (Minimum_DevSleep_Assertion_Time << 10) + (DITO_Multiplier << 25)); + HBA_PORT_REG32_OR (AhciBaseAddr, PortNumber, HBA_PORTS_PxDEVSLP, PxDevSlp); + + // Enable PxDEVSLP.ADSE + HBA_PORT_REG32_OR (AhciBaseAddr, PortNumber, HBA_PORTS_PxDEVSLP, HBA_PORTS_PxDEVSLP_ADSE); + pBS->FreePool(Buffer); + } else { + if (SataDevInterface->IdentifyData.Reserved_76_79[3] & IDENTIFY_DEVSLEEP_ENABLED) { + + // Disable Device Sleep and Issue Set Feature command only if it is enabled already. + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Command = SET_FEATURE_COMMAND; + CommandStructure.SectorCount = DEVSLEEP_SUB_COMMAND; + CommandStructure.Features = DEVSLEEP_DISABLE; + ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } + } + } + } + + return; +} + +// +//---------------------------------------------------------------------------- +// Procedure: GetSataDevInterface +// +// Description: +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN UINT8 Port, +// IN UINT8 PMPort, +// +// Output: +// SATA_DEVICE_INTERFACE* +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Return the Pointer to the SATA_DEVICE_INTERFACE for the given +// Port and PM Port +// +//---------------------------------------------------------------------------- +// +SATA_DEVICE_INTERFACE * +GetSataDevInterface( + IN AHCI_BUS_PROTOCOL *AhciBusInterface, + IN UINT8 Port, + IN UINT8 PMPort +) +{ + + DLINK *dlink = AhciBusInterface->SataDeviceList.pHead; + SATA_DEVICE_INTERFACE *SataDevInterface = NULL; + + if (!dlink) return NULL; + do { + SataDevInterface = OUTTER(dlink, SataDeviceLink, SATA_DEVICE_INTERFACE); + if (SataDevInterface->PortNumber == Port && + SataDevInterface->PMPortNumber == PMPort ) break; + dlink = dlink-> pNext; + SataDevInterface = NULL; + }while (dlink); + + return SataDevInterface; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: WaitForMemSet +// +// Description: Wait for memory to be set to the test value. +// +// Input: MemTestAddr - The memory address to test +// MaskValue - The mask value of memory +// TestValue - The test value of memory +// WaitTimeInMs - The time out value for wait memory set +// +// Output: EFI_SUCCESS - HBA reset successfully. +// EFI_DEVICE_ERROR - HBA failed to complete hardware reset. +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +WaitForMemSet ( + IN UINT32 BaseAddr, + IN UINT8 Port, + IN UINT8 Register, + IN UINT32 AndMask, + IN UINT32 TestValue, + IN UINT32 WaitTimeInMs +) +{ + UINT8 Delay; + while(WaitTimeInMs!=0){ + for ( Delay = 10; Delay > 0; Delay--) { + + if(((HBA_PORT_REG32(BaseAddr, Port, Register)) & AndMask) == TestValue){ + return EFI_SUCCESS; + } + + pBS->Stall (100); // 100 usec * 10 = 1Msec + } + WaitTimeInMs--; + } + return EFI_DEVICE_ERROR; +} + +// +//---------------------------------------------------------------------------- +// Procedure: WaitForMemClear +// +// Description: Wait for memory to be set to the test value. +// +// Input: MemTestAddr - The memory address to test +// MaskValue - The mask value of memory +// WaitTimeInMs - The time out value for wait memory set +// +// Output: EFI_SUCCESS - HBA reset successfully. +// EFI_DEVICE_ERROR - HBA failed to complete hardware reset. +// +// Modified: +// +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +WaitForMemClear ( + IN UINT32 BaseAddr, + IN UINT8 Port, + IN UINT8 Register, + IN UINT32 AndMask, + IN UINT32 WaitTimeInMs +) +{ + UINT8 Delay; + while(WaitTimeInMs!=0){ + for ( Delay = 10; Delay > 0; Delay--) { + + if(!((HBA_PORT_REG32(BaseAddr, Port, Register)) & AndMask)){ + return EFI_SUCCESS; + } + + pBS->Stall (100); // 100 usec * 10 = 1Msec + } + WaitTimeInMs--; + } + return EFI_DEVICE_ERROR; +} + +//********************************************************************** +// +// +// Procedure: ReturnMSBset +// +// Description: Returns the MOST significant Bit set. +// +// Input: +// IN UINT32 Data +// +// Output: +// UINT8 +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +// +//********************************************************************** +UINT8 +ReturnMSBset( + IN UINT32 Data + ) +{ + UINT8 Index; + UINT8 Value = 0xFF; + + for (Index = 0; Index < 32; Index++) { + if ( Data & 1) { + Value = Index; + } + Data >>= 1; + } + + return Value; +} + +//********************************************************************** +// +// +// Procedure: InitSataBlockIO +// +// Description: Initializes SATA Block IO interface +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AllocatePool, OpenProtocol, DetectAtapiMedia, AtapiInquiryData +// +// Notes: +// Here is the control flow of this function: +// 1. Initialize EFI_BLOCK_IO_PROTOCOL Protocol. +// 2. In case of Removable devices, detect Media presence. +// +// +//********************************************************************** +EFI_STATUS +InitSataBlockIO ( + IN SATA_DEVICE_INTERFACE *SataDevInterface + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + SATA_BLOCK_IO *SataBlkIo; + EFI_BLOCK_IO_MEDIA *BlkMedia; + ATAPI_DEVICE *AtapiDevice; + UINT8 *Data, *InquiryData; + UINT16 InquiryDataSize; + UINT16 OddType=0; + UINT8 OddLoadingType=0xFF; + UINT32 SectorSize = ATA_SECTOR_BYTES; + + Status = pBS->AllocatePool (EfiBootServicesData, + sizeof(SATA_BLOCK_IO), + (VOID**)&SataBlkIo); + if (EFI_ERROR(Status)) return Status; + + BlkMedia = MallocZ(sizeof(EFI_BLOCK_IO_MEDIA)); + if (!BlkMedia) { + pBS->FreePool (SataBlkIo); + return EFI_OUT_OF_RESOURCES; + } + + // + // Initialize the IdeBlkIo pointer in IDE_BUS_PROTOCOL (IdeBusInterface) + // + SataDevInterface->SataBlkIo = SataBlkIo; + + // + // Initialize the fields in IdeBlkIo (SATA_BLOCK_IO) + // + SataBlkIo->SataDevInterface = SataDevInterface; + + if (SataDevInterface->DeviceType == ATA){ + // ATA + BlkIo = &(SataBlkIo->BlkIo); + +#if defined CORE_COMBINED_VERSION && CORE_COMBINED_VERSION > 0x4028a + if(pST->Hdr.Revision >= 0x0002001F) { + BlkIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3; + } else { + BlkIo->Revision = BLKIO_REVISION; + } +#else + BlkIo->Revision = BLKIO_REVISION; +#endif + BlkIo->Media = BlkMedia; + BlkIo->Reset = SataReset; + BlkIo->ReadBlocks = SataBlkRead; + BlkIo->WriteBlocks = SataBlkWrite; + BlkIo->FlushBlocks = SataBlkFlush; + + BlkMedia->MediaId = 0; + BlkMedia->RemovableMedia = (SataDevInterface->IdentifyData.General_Config_0 & 0x80) == 0x80 ? TRUE : FALSE; + + BlkMedia->MediaPresent = TRUE; + BlkMedia->LogicalPartition = FALSE; + BlkMedia->ReadOnly = FALSE; + BlkMedia->WriteCaching = FALSE; + + if((SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT14) && // WORD 106 valid? - BIT 14 - 1 + (!(SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT15)) && // WORD 106 valid? - BIT 15 - 0 + (SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT12)) { // WORD 106 bit 12 - Sectorsize > 256 words + // The sector size is in words 117-118. + SectorSize = (UINT32)(SataDevInterface->IdentifyData.Reserved_104_126[13] + \ + (SataDevInterface->IdentifyData.Reserved_104_126[14] << 16)) * 2; + } + + BlkMedia->BlockSize = SectorSize; + BlkMedia->IoAlign = 4; + + if (SataDevInterface->IdentifyData.Command_Set_Supported_83 & 0x400) { + BlkMedia->LastBlock = SataDevInterface->IdentifyData.LBA_48 - 1; + } + else { + BlkMedia->LastBlock = SataDevInterface->IdentifyData.Addressable_Sector_60 - 1; + } + +#if defined CORE_COMBINED_VERSION && CORE_COMBINED_VERSION > 0x4028a + if(pST->Hdr.Revision >= 0x0002001F) { + + BlkMedia->OptimalTransferLengthGranularity=BlkMedia->BlockSize; + // + // bit 14 of word 106 is set to one and bit 15 of word 106 is cleared to zero, + // then the contents of word 106 contain valid information . + // Otherwise, information is not valid in this word. + // + if ( (SataDevInterface->IdentifyData.Reserved_104_126[2] & 0xC000) == 0x4000 ) { + // + // If bit 13 of word 106 is set to one, then the device has more than one + // logical sector per physical sector and bits (3:0) of word 106 are valid + // + if ( SataDevInterface->IdentifyData.Reserved_104_126[2] & 0x2000 ) { + + BlkMedia->LogicalBlocksPerPhysicalBlock = 1 << + (SataDevInterface->IdentifyData.Reserved_104_126[2] & 0xF); + + // + // Bits 13:0 of word 209 indicate the Logical sector offset within the first physical + // sector where the first logical sector is placed + // + BlkMedia->LowestAlignedLba =SataDevInterface->IdentifyData.Reserved_206_254[3] & 0x3FFF; + + } else { + // + // Default set the 1 logical blocks per PhysicalBlock + // + BlkMedia->LogicalBlocksPerPhysicalBlock=1; + + // + // Default value set to 0 for Lowest Aligned LBA + // + BlkMedia->LowestAlignedLba=0; + } + } else { + // + // Default set the 1 logical blocks per PhysicalBlock + // + BlkMedia->LogicalBlocksPerPhysicalBlock=1; + // + // Default value set to 0 for Lowest Aligned LBA + // + BlkMedia->LowestAlignedLba=0; + } + } +#endif + + } else { + + // + // If it is an ATAPI device, check whether it is a CDROM or not. + // Currently only CDROM/Direct access Devices are supported. + // + if ((SataDevInterface->IdentifyData.General_Config_0 & 0x1f00) == (CDROM_DEVICE << 8) || + (SataDevInterface->IdentifyData.General_Config_0 & 0x1f00) == (DIRECT_ACCESS_DEVICE << 8) || + (SataDevInterface->IdentifyData.General_Config_0 & 0x1f00) == (OPTICAL_MEMORY_DEVICE << 8)){ + + AtapiDevice = MallocZ(sizeof (ATAPI_DEVICE)); + + if (!AtapiDevice) return EFI_OUT_OF_RESOURCES; + + SataDevInterface->AtapiDevice = AtapiDevice; + + Status = pBS->AllocatePool (EfiBootServicesData, + 16, + (VOID**)&Data + ); + + if (EFI_ERROR(Status)) return Status; + + AtapiDevice->PacketBuffer = Data; + AtapiDevice->DeviceType = (SataDevInterface->IdentifyData.General_Config_0 & 0x1f00) >> 8; + AtapiDevice->PacketSize = (SataDevInterface->IdentifyData.General_Config_0 & 3) == 1 ? 16 : 12; + + BlkIo = &(SataBlkIo->BlkIo); +#if defined CORE_COMBINED_VERSION && CORE_COMBINED_VERSION > 0x4028a + if(pST->Hdr.Revision >= 0x0002001F) { + BlkIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3; + } else { + BlkIo->Revision = BLKIO_REVISION; + } +#else + BlkIo->Revision = BLKIO_REVISION; +#endif + BlkIo->Media = BlkMedia; + BlkIo->Reset = SataReset; + BlkIo->ReadBlocks = SataAtapiBlkRead; + BlkIo->WriteBlocks = SataAtapiBlkWrite; + BlkIo->FlushBlocks = SataBlkFlush; + BlkMedia->BlockSize = CDROM_BLOCK_SIZE; + + // + // Update Inquiry Data + // + Status = pBS->AllocatePool (EfiBootServicesData, + INQUIRY_DATA_LENGTH, + (VOID**)&InquiryData); + if (EFI_ERROR(Status)) return Status; + InquiryDataSize = INQUIRY_DATA_LENGTH; + SataAtapiInquiryData(SataDevInterface, InquiryData, &InquiryDataSize); + AtapiDevice->InquiryData = InquiryData; + AtapiDevice->InquiryDataSize = InquiryDataSize; + + // + // Get the ATAPI drive type information and save it ATAPI_DEVICE + // + Status=SataGetOddType(SataDevInterface, &OddType); + if(!EFI_ERROR(Status)) { + AtapiDevice->OddType=GetEnumOddType(OddType); + } + + // + // Get the ATAPI drive Loading information and save it ATAPI_DEVICE + // + Status=SataGetOddLoadingType(SataDevInterface, &OddLoadingType); + + if ( !EFI_ERROR( Status )) { + AtapiDevice->OddLoadingType = (ODD_LOADING_TYPE)OddLoadingType; + } else { + AtapiDevice->OddLoadingType = (ODD_LOADING_TYPE)0xFF; + } + + BlkMedia->RemovableMedia = (SataDevInterface->IdentifyData.General_Config_0 & 0x80) == 0x80 ? TRUE : FALSE; + BlkMedia->LogicalPartition = FALSE; + BlkMedia->WriteCaching = FALSE; + BlkMedia->IoAlign = 4; +#if defined CORE_COMBINED_VERSION && CORE_COMBINED_VERSION > 0x4028a + if(pST->Hdr.Revision >= 0x0002001F) { + // + // For Atapi Devices, Default set the 1 for logical blocks per PhysicalBlock + // + BlkMedia->LogicalBlocksPerPhysicalBlock=1; + + // + // For Atapi Devices, Default value set to 0 for Lowest Aligned LBA + // + BlkMedia->LowestAlignedLba=0; + + BlkMedia->OptimalTransferLengthGranularity=BlkMedia->BlockSize; + } +#endif + } + } + + return EFI_SUCCESS; + +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: GetEnumOddType +// +// Description: Get the Enum value for ODD type found on profile +// +// Input: +// +// UINT16 Oddtype +// Output: +// ODD_TYPE EnumValue +// +// Modified: +// +// Referrals: +// +// Notes: +// +//--------------------------------------------------------------------------- +// +ODD_TYPE GetEnumOddType( + UINT16 OddType +) +{ + + switch(OddType) { + case 1: + case 3: + case 4: + case 5: + return Obsolete; + + case 2: + return Removabledisk; + + case 8: + return CDROM; + + case 9: + return CDR; + + case 0xa: + return CDRW; + + case 0x10: + return DVDROM; + + case 0x11: + return DVDRSequentialrecording; + + case 0x12: + return DVDRAM; + + case 0x13: + return DVDRWRestrictedOverwrite; + + case 0x15: + return DVDRWSequentialrecording; + + case 0x16: + return DVDRDualLayerJumprecording; + + case 0x17: + return DVDRWDualLayer; + + case 0x18: + return DVDDownloaddiscrecording; + + case 0x1a: + return DVDRW; + + case 0x1b: + return DVDR; + + case 0x40: + return BDROM; + + case 0x41: + return BDRSequentialRecording; + + case 0x42: + return BDRRandomRecordingMode; + + case 0x43: + return BDRE; + + case 0x50: + return HDDVDROM; + + case 0x51: + return HDDVDR; + + case 0x52: + return HDDVDRAM; + + case 0x53: + return HDDVDRW; + + case 0x58: + return HDDVDRDualLayer; + + case 0x5a: + return HDDVDRWDualLayer; + + default: + return UnknownType; + } + +} + +//********************************************************************** +// +// +// Procedure: InitSataDiskInfo +// +// Description: Initializes SATA DiskInfo Interface +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AllocatePool +// +// Notes: +// +// +//********************************************************************** +EFI_STATUS +InitSataDiskInfo ( + IN SATA_DEVICE_INTERFACE *SataDevInterface + ) +{ + EFI_STATUS Status; + SATA_DISK_INFO *SataDiskInfo; + + Status = pBS->AllocatePool (EfiBootServicesData, + sizeof(SATA_DISK_INFO), + (VOID**)&SataDiskInfo); + if (EFI_ERROR(Status)){ + return Status; + } + + // + // Initialize the SataBlkIo pointer in SATA_DEVICE_INTERFACE + // + SataDevInterface->SataDiskInfo = SataDiskInfo; + + // Initialize the fields in SataDiskInfo (SATA_DISK_INFO) + SataDiskInfo->SataDevInterface = SataDevInterface; + + pBS->CopyMem (&(SataDiskInfo->DiskInfo.Interface), &gEfiAhciDiskInfoProtocolGuid, sizeof (EFI_GUID)); + SataDiskInfo->DiskInfo.Inquiry = DiskInfoInquiry; + SataDiskInfo->DiskInfo.Identify = DiskInfoIdentify; + SataDiskInfo->DiskInfo.SenseData = DiskInfoSenseData; + SataDiskInfo->DiskInfo.WhichIde = DiskInfoWhichIDE; + return EFI_SUCCESS; + +} + +//********************************************************************** +// +// +// Procedure: CreateSataDevicePath +// +// Description: Creates a SATA device devicepath and adds it to SataDevInterface +// +// Input: +// IN EFI_DRIVER_BINDING_PROTOCOL *This, +// IN EFI_HANDLE Controller, +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// IN OUT EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AllocatePool, OpenProtocol, IdeBusStart +// +// Notes: +// Here is the control flow of this function: +// 1. If Remaining Devicepath is not NULL, we have already verified that it is a +// valid Atapi device path in IdeBusStart. So nothing to do. Just exit. +// 2. Build a Atapi devicepath and a End devce path. +// 3. Get the Devicepath for the IDE controller. +// 4. Append Atapi devicepath to IDE controller devicepath. +// +// +//********************************************************************** +EFI_STATUS +CreateSataDevicePath ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + + EFI_STATUS Status = EFI_SUCCESS; + SATA_DEVICE_PATH NewDevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + NewDevicePath.Header.Type = MESSAGING_DEVICE_PATH; + NewDevicePath.Header.SubType = MSG_USB_SATA_DP; + SET_NODE_LENGTH(&NewDevicePath.Header,SATA_DEVICE_PATH_LENGTH); + NewDevicePath.PortNumber = SataDevInterface->PortNumber; + NewDevicePath.MultiplierPortNumber = SataDevInterface->PMPortNumber == 0xFF ? 0xFFFF : SataDevInterface->PMPortNumber; + NewDevicePath.LogicalUnitNumber = 0; + + // + // Append the Device Path + // + Status = pBS->OpenProtocol( Controller, + &gDevicePathProtocolGuid, + (VOID **)&TempDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + SataDevInterface->DevicePathProtocol = DPAddNode(TempDevicePath, &NewDevicePath.Header); + return Status; + +} + +#if SBIDE_SUPPORT +//********************************************************************** +// +// +// Procedure: InitMiscConfig +// +// Description: Initialize misc IDE configurations. +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// None +// +// +//********************************************************************** +VOID InitMiscConfig ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +) +{ + IDE_SETUP_PROTOCOL *gIdeSetupProtocol; + COMMAND_STRUCTURE CommandStructure; + EFI_STATUS Status = EFI_SUCCESS; + + Status = pBS->LocateProtocol(&gIdeSetupProtocolguid, NULL, &gIdeSetupProtocol); + if(EFI_ERROR(Status)){ + return; + } + + #if ACOUSTIC_MANAGEMENT_SUPPORT + InitAcousticSupport (SataDevInterface); + #endif + +} +#endif + +//********************************************************************** +// +// +// Procedure: ConfigurePowerUpInStandby +// +// Description: Configure PowerUpInStandby +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ExecuteNonDataCommand +// +// Notes: +// 1. Check if the device support PowerUp In Standby. +// 2. Check the desired state Vs the current state. +// 3. If both are equal nothing to do, exit else program the desired level +// +// +//********************************************************************** +EFI_STATUS +ConfigurePowerUpInStandby ( + IN SATA_DEVICE_INTERFACE *SataDevInterface + ) +{ + COMMAND_STRUCTURE CommandStructure; + EFI_STATUS Status = EFI_SUCCESS; + + if(AhciPlatformPolicy->PowerUpInStandbySupport) { + // + // Check if the device supports PowerUpInStandby feature + // + if (SataDevInterface->IdentifyData.Command_Set_Supported_83 & 0x20){ + // + //Check if the desired state is already present or not + // + if (!((SataDevInterface->IdentifyData.Command_Set_Enabled_86 & 0x20) == + (AhciPlatformPolicy->PowerUpInStandbyMode))){ + + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Command = SET_FEATURE_COMMAND; + CommandStructure.Features = (AhciPlatformPolicy->PowerUpInStandbyMode) == 0 ? DISABLE_POWERUP_IN_STANDBY : ENABLE_POWERUP_IN_STANDBY; + Status = ExecuteNonDataCommand (SataDevInterface, CommandStructure); + + } + } + } + + return Status; +} + +#if ACOUSTIC_MANAGEMENT_SUPPORT +//********************************************************************** +// +// +// Procedure: InitAcousticSupport +// +// Description: Initialize Acoustic functionality +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ExecuteNonDataCommand +// +// Notes: +// 1. Check if the device support Acoustic management. +// 2. Check the desired state Vs the current state. +// 3. If both are equal nothing to do, exit else program the desired level +// +// +//********************************************************************** +EFI_STATUS +InitAcousticSupport ( + IN SATA_DEVICE_INTERFACE *SataDevInterface + ) +{ + + UINT8 Data8; + COMMAND_STRUCTURE CommandStructure; + EFI_STATUS Status; + + ZeroMemory(&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Command = SET_FEATURE_COMMAND; + + // + // Check if the device supports Acoustic Management + // + if (SataDevInterface->IdentifyData.Command_Set_Supported_83 & 0x200){ + + // + // Check if Acoustic Level need to be enabled or Disabled + // + if (SataDevInterface->AhciBusInterface->Acoustic_Enable & ACOUSTIC_SUPPORT_ENABLE) { + Data8 = SataDevInterface->AhciBusInterface->Acoustic_Management_Level; + + // + // Do we need to program the recommended value + // + if (Data8 == ACOUSTIC_LEVEL_BYPASS) { + + // + // Get the rcommended value + // + Data8 = (UINT8)(SataDevInterface->IdentifyData.Acoustic_Level_94 >> 8); + } + + CommandStructure.Features = ACOUSTIC_MANAGEMENT_ENABLE; + CommandStructure.SectorCount = Data8; + Status = ExecuteNonDataCommand (SataDevInterface, CommandStructure); + + } else { + + // + // If already disabled, nothing to do + // + if (SataDevInterface->IdentifyData.Command_Set_Enabled_86 & 0x200) { + CommandStructure.Features = ACOUSTIC_MANAGEMENT_DISABLE; + CommandStructure.SectorCount = 0; + Status = ExecuteNonDataCommand (SataDevInterface, CommandStructure); + } + } + } + return EFI_SUCCESS; +} + +#endif // ACOUSTIC_MANAGEMENT_SUPPORT ends + +//********************************************************************** +// +// +// Procedure: DMACapable +// +// Description: Check if DMA is supported +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// TRUE : DMA Capable +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Check the Identify Data to check if device supports DMA +// +// +//********************************************************************** +BOOLEAN +DMACapable( + IN SATA_DEVICE_INTERFACE *SataDevInterface +) +{ + + if (SataDevInterface->DeviceType == ATAPI){ + //For Atapi Devices check Bit 8 in Word 49 = DMA Supported or not + if((SataDevInterface->IdentifyData.Capabilities_49 & 0x100) == 0) return FALSE; + } + + if ( (SataDevInterface->UDma != 0xff) || + (SataDevInterface->MWDma != 0xff)) + return TRUE; + else + return FALSE; + +} + +//********************************************************************** +// +// +// Procedure: DiskInfoInquiry +// +// Description: Return ATAPI Inquiry data +// +// Input: +// IN EFI_DISK_INFO_PROTOCOL *This, +// IN OUT VOID *InquiryData, +// IN OUT UINT32 *InquiryDataSize +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitSataDiskInfo +// +// Notes: +// 1. Check for Atapi Device. If not exit +// 2. COpy the Inquiry Data from AtapiDevice->InquiryData to the input pointer. +// +// +// +//********************************************************************** +EFI_STATUS +DiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *InquiryDataSize +) +{ + + SATA_DEVICE_INTERFACE *SataDevInterface = ((SATA_BLOCK_IO *)This)->SataDevInterface; + ATAPI_DEVICE *AtapiDevice = SataDevInterface->AtapiDevice; + + // + // Check for ATAPI device. If not return EFI_NOT_FOUND + // + if (SataDevInterface->DeviceType == ATA){ + return EFI_NOT_FOUND; // ATA device + } + else { + if (*InquiryDataSize < AtapiDevice->InquiryDataSize) { + *InquiryDataSize = AtapiDevice->InquiryDataSize; + return EFI_BUFFER_TOO_SMALL; + } + if (AtapiDevice->InquiryData != NULL) { + pBS->CopyMem (InquiryData, AtapiDevice->InquiryData, AtapiDevice->InquiryDataSize); + *InquiryDataSize = AtapiDevice->InquiryDataSize; + return EFI_SUCCESS; + } + else return EFI_NOT_FOUND; + } +} + + +//********************************************************************** +// +// +// Procedure: DiskInfoIdentify +// +// Description: Return Identify Data +// +// Input: +// EFI_DISK_INFO_PROTOCOL *This, +// IN OUT VOID *IdentifyData, +// IN OUT UINT32 *IdentifyDataSize +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitSataDiskInfo +// +// Notes: +// 1. Return the Identify command data. +// +// +// +//********************************************************************** +EFI_STATUS +DiskInfoIdentify ( + EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize + ) +{ + + SATA_DEVICE_INTERFACE *SataDevInterface = ((SATA_BLOCK_IO *)This)->SataDevInterface; + + if (*IdentifyDataSize < sizeof (IDENTIFY_DATA)) { + *IdentifyDataSize = sizeof (IDENTIFY_DATA); + return EFI_BUFFER_TOO_SMALL; + } + + // + // ATA devices identify data might be changed because of the SetFeature command, + // So read the data from the device again by sending identify command. + // + if(SataDevInterface->DeviceType == ATA){ + GetIdentifyData(SataDevInterface); + } + + pBS->CopyMem (IdentifyData, &(SataDevInterface->IdentifyData), sizeof (IDENTIFY_DATA)); + *IdentifyDataSize = sizeof (IDENTIFY_DATA); + return EFI_SUCCESS; + +} + + +//********************************************************************** +// +// +// Procedure: DiskInfoSenseData +// +// Description: Return InfoSenseData. +// +// Input: +// EFI_DISK_INFO_PROTOCOL *This, +// VOID *SenseData, +// UINT32 *SenseDataSize, +// UINT8 *SenseDataNumber +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitSataDiskInfo +// +// Notes: +// 1. Return the Sense data for the Atapi device. +// +// +// +//********************************************************************** +EFI_STATUS +DiskInfoSenseData( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT VOID *SenseData, + OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber + ) + +{ + + return EFI_NOT_FOUND; + +} + + +//********************************************************************** +// +// +// Procedure: DiskInfoWhichIDE +// +// Description: Returns info about where the device is connected. +// +// Input: +// IN EFI_DISK_INFO_PROTOCOL *This, +// OUT UINT32 *IdeChannel, +// OUT UINT32 *IdeDevice +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitSataDiskInfo +// +// Notes: +// 1. Return Port and PMPort +// +// +//********************************************************************** +EFI_STATUS +DiskInfoWhichIDE +( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice + ) +{ + + SATA_DEVICE_INTERFACE *SataDevInterface = ((SATA_BLOCK_IO *)This)->SataDevInterface; + + *IdeChannel = SataDevInterface->PortNumber; + *IdeDevice = SataDevInterface->PMPortNumber == 0xFF ? 0 : SataDevInterface->PMPortNumber; + return EFI_SUCCESS; + +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AhciBus.h b/Core/EM/Ahci/AhciBus.h new file mode 100644 index 0000000..c557262 --- /dev/null +++ b/Core/EM/Ahci/AhciBus.h @@ -0,0 +1,919 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2013, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/AhciBus.h 18 6/25/14 10:04a Anandakrishnanl $ +// +// $Revision: 18 $ +// +// $Date: 6/25/14 10:04a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/AHCI/AhciBus.h $ +// +// 18 6/25/14 10:04a Anandakrishnanl +// [TAG] EIP170118 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] MDAT can't program correctly in AHCI module +// [RootCause] Identify Data Word 76_79 Offset for DiPM Support/Enabled +// is incorrect for validation +// [Solution] Changed separating DiPM and Device Sleep into two routines +// and also modified the tokens to disable both support by default . +// Corrected Identify data validations. +// [Files] AhciBus.c +// AhciBus.h +// AhciSrc.sdl +// PAhciBus.h +// PIDEBus.h +// +// 17 1/27/14 4:56a Rameshr +// [TAG] EIP148180 +// [Category] Improvement +// [Description] change from EFI_MBR_WRITE_PROTECTION_PROTOCOL to +// AMI_BLOCKIO_WRITE_PROTECTION_PROTOCOL +// [Files] Ahcibus.c, Ahcibus.h, AhciComponentName.c, AhciController.c +// +// 16 12/18/13 3:21a Srikantakumarp +// [TAG] EIP127356 +// [Category] Improvement +// [Description] Flash NVRAM seems to cause HDD can't be unlocked when +// S3 resume. +// [Files] IdeSecurity.c, IDESMM.c, HddPassword.c, AhciBus.c, AhciBus.h +// +// 15 8/27/13 4:18a Rameshr +// [TAG] EIP125560 +// [Category] Improvement +// [Description] MbrWriteProtectionProtocol file name changesd to +// AmiMbrWriteProtectionProtocol.h +// [Files] AhciController.c, AhciBus.h, Ahcibus.c +// +// 14 7/23/13 11:54p Srikantakumarp +// [TAG] EIP129989 +// [Category] Improvement +// [Description] Added DIPM support in Aptio 4.x AHCIBUS driver. +// [Files] AhciBus.c, AhciBus.h, AhciController.h, AhciSrc.sdl, +// PAhciBus.h +// +// 13 7/22/13 2:07a Rameshr +// [TAG] EIP129028 +// [Category] Improvement +// [Description] Implement the POWERUP_IN_STANDBY_MODE support in +// AHCIBUS driver +// [Files] Ahcibus.c, Ahcibus.h, Pahcibus.h +// +// 12 7/18/13 4:22a Rameshr +// [TAG] EIP127919 +// [Category] Improvement +// [Description] "Device is Atapi" bit of PxCMD will be set if the ATAPI +// device connected on the Port and "Drive LED on ATAPI" Enabled by AHCI +// platform policy +// [Files] Pahcibus.h, Ahcibus.c, Ahcibus.h +// +// 11 7/20/12 6:10a Anandakrishnanl +// [TAG] EIP88683 +// [Category] New Feature +// [Description] EFI_ATA_PASS_THRU_PROTOCOL Support for Aptio IDE +// [Files] AhciBus.c +// AhciBus.h +// AInt13.h +// IdeBus.c +// IdeBus.h +// PIDEBus.h +// PAhciBus.h +// AtaPassThru.sdl +// AtaPassThru.mak +// AtaPassThru.c +// AtaPassThruSupport.h +// AtaPassThru.chm +// +// 10 9/27/11 3:02a Rajeshms +// [TAG] EIP69295 +// [Category] Improvement +// [Description] The Timeout values used by IDE and AHCI drivers are +// made as SDL tokens, so that the timeout values can be varied. +// [Files] IdeBusBoard.c, CORE_DXE.sdl, AhciSmm.h, AhciBus.h, IDESMM.h, +// Ata.c, Atapi.c, IdeBus.c, IdeBus.h, IdeBusMaster.c, IdeBusBoard.h +// +// 9 9/19/11 3:05a Lavanyap +// [TAG] EIP69398 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Function ConfigureController() has a runtime error (NULL +// pointer dereference) +// [RootCause] variable SupportedModes has been initialized again in +// ConfigureController(). +// [Solution] variable SupportedModes is passed as an input parameter +// for ConfigureController() and ConfigureDevice(). +// [Files] AhciBus.c, AhciBus.h +// +// 8 2/11/11 4:23a Rameshr +// [TAG] EIP53730 +// [Category] Improvement +// [Description] Add Odd Loading type information into ATAPI_DEVICE +// structure in AHCI mode +// [Files] AhciBus.c +// AhciController.c +// AhciBus.h +// +// 7 2/10/11 10:35a Rameshr +// [TAG] EIP53704 +// [Category] Improvement +// [Description] AMI headers update for Alaska Ahci Driver +// [Files] AhciSrc.mak +// AhciBus.c +// AhciController.c +// AhciComponentName.c +// AhciBus.h +// AhciController.h +// +// 6 12/23/10 3:59a Lavanyap +// [TAG] - EIP41445 +// [Category] - NEW FEATURE +// [Description] - Created SataPioDataOut and AtaPioDataOut protocol +// function that can accept additional input parameters. +// [Files] - AhciBus.h, AhciBus.c, AhciController.c, Ata.c, IdeBus.c, +// IdeBus.h, IdeBusMaster.c,PAhciBus.h, PIdeBus.h +// +// 5 5/07/10 11:45a Krishnakumarg +// Coding standard update +// +// 4 6/22/09 11:34a Rameshr +// Odd Type information Saved in Atapi Device Structure. +// EIP:21548 +// +// 3 4/28/09 3:58p Rameshr +// +// HDD password support in RAID mode +// EIP:20421 +// +// 2 5/28/08 9:39a Rameshraju +// Based on the SDL token index/data or MMIO method used to access the +// AHCI configuration space. +// +// 1 28/02/08 6:03p Anandakrishnanl +// AHCI Bus Driver initial check-in. +// +//********************************************************************** +// +// +// Name: AhciBus.h +// +// Description: +// +// +//********************************************************************** + +#ifndef _AhciBus_ +#define _AhciBus_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include "Protocol\PciIo.h" +#include "Protocol\DevicePath.h" +#include "protocol\DriverBinding.h" +#include "protocol\BlockIo.h" +#include "Protocol\PDiskInfo.h" +#include "Protocol\PIDEController.h" +#include "Protocol\PIDEBus.h" +#include +#include +#include +#include +#include +#include "AhciController.h" + +#if defined CORE_COMBINED_VERSION && (CORE_COMBINED_VERSION > 0x4028E) +#include +#endif + +#define TRACE_AHCI_LEVEL2 +#define TRACE_AHCI TRACE + +#ifdef Debug_Level_1 +VOID EfiDebugPrint (IN UINTN ErrorLevel,IN CHAR8 *Format,...); +#endif + +#define AHCI_BUS_DRIVER_VERSION 0x01 +#define ONE_MILLISECOND 1000 + +#define COMMAND_LIST_SIZE_PORT 0x800 + +#ifndef ATAPI_BUSY_CLEAR_TIMEOUT +#define ATAPI_BUSY_CLEAR_TIMEOUT 16000 // 16sec +#endif + +#ifndef S3_BUSY_CLEAR_TIMEOUT +#define S3_BUSY_CLEAR_TIMEOUT 10000 // 10Sec +#endif + +#define BUSY_CLEAR_TIMEOUT 1000 // 1Sec +#define DRDY_TIMEOUT 1000 // 1Sec +#define DRQ_TIMEOUT 10 // 10msec +#define DRQ_CLEAR_TIMEOUT 1000 // 1sec +#define DRQ_SET_TIMEOUT 10 // 10msec +#define HP_COMMAND_COMPLETE_TIMEOUT 2000 // 2Sec +#define COMMAND_COMPLETE_TIMEOUT 5000 // 5Sec + +#ifndef DMA_ATA_COMMAND_COMPLETE_TIMEOUT +#define DMA_ATA_COMMAND_COMPLETE_TIMEOUT 5000 // 5Sec +#endif + +#ifndef DMA_ATAPI_COMMAND_COMPLETE_TIMEOUT +#define DMA_ATAPI_COMMAND_COMPLETE_TIMEOUT 16000 // 16Sec +#endif + +#ifndef ATAPI_RESET_COMMAND_TIMEOUT +#define ATAPI_RESET_COMMAND_TIMEOUT 5000 +#endif + +#ifndef POWERON_BUSY_CLEAR_TIMEOUT +#define POWERON_BUSY_CLEAR_TIMEOUT 10000 // 10 Sec +#endif + +#define TIMEOUT_1SEC 1000 // 1sec Serial ATA 1.0 Sec 5.2 + + + +#define BLKIO_REVISION 1 + +#define DEVICE_DISABLED 0 +#define DEVICE_IN_RESET_STATE 1 +#define DEVICE_DETECTION_FAILED 2 +#define DEVICE_DETECTED_SUCCESSFULLY 3 +#define DEVICE_CONFIGURED_SUCCESSFULLY 4 +#define DEVICE_REMOVED 5 +#define CONTROLLER_NOT_PRESENT 0xff + +#define ENUMERATE_ALL 0xff +#define ENUMERATE_PRIMARY_MASTER 0x0 +#define ENUMERATE_PRIMARY_SLAVE 0x1 +#define ENUMERATE_SECONDARY_MASTER 0x2 +#define ENUMERATE_SECONDARY_SLAVE 0x3 +#define INQUIRY_DATA_LENGTH 0x96 +#define READ_CAPACITY_DATA_LENGTH 0x08 + +// PCI Config Space equates +#define PROGRAMMING_INTERFACE_OFFSET 0x09 +#define IDE_SUB_CLASS_CODE 0x0A + #define SCC_IDE_CONTROLLER 0x01 + #define SCC_AHCI_CONTROLLER 0x06 + #define SCC_RAID_CONTROLLER 0x04 +#define IDE_BASE_CLASS_CODE 0x0B + #define BASE_CODE_IDE_CONTROLLER 0x01 +#define PRIMARY_COMMAND_BLOCK_OFFSET 0x10 +#define PRIMARY_CONTROL_BLOCK_OFFSET 0x14 +#define SECONDARY_COMMAND_BLOCK_OFFSET 0x18 +#define SECONDARY_CONTROL_BLOCK_OFFSET 0x1C +#define LEGACY_BUS_MASTER_OFFSET 0x20 + +#define EFI_SUCCESS_ACTIVE_SET 0x80000000 + + +EFI_STATUS +CreateIdeDevicePath ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IDE_BUS_INIT_PROTOCOL *IdeBusInitInterface, + IDE_BUS_PROTOCOL *IdeBusInterface, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, + UINT8 Current_Channel, + UINT8 Current_Device +); + +EFI_STATUS +InitIdeBlockIO ( + IDE_BUS_PROTOCOL *IdeBusInterface +); + +EFI_STATUS +InitIdeDiskInfo ( + IDE_BUS_PROTOCOL *IdeBusInterface +); + +EFI_STATUS +InstallAhciBusProtocol ( + IN EFI_HANDLE Controller, + AHCI_BUS_PROTOCOL *IdeBusInitInterface, + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, + EFI_PCI_IO_PROTOCOL *PciIO +); + +EFI_STATUS +AhciInitController ( + AHCI_BUS_PROTOCOL *AhciBusInterface +); + +EFI_STATUS +CheckPortImplemented ( + AHCI_BUS_PROTOCOL *AhciBusInterface, + UINT8 Port +); + +EFI_STATUS +AhciDetectDevice ( + AHCI_BUS_PROTOCOL *AhciBusInterface, + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, + UINT8 Port, + UINT8 PMPortNumber +); + +EFI_STATUS +CheckDevicePresence ( + SATA_DEVICE_INTERFACE *SataDevInterface, + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, + UINT8 Port, + UINT8 PMPort +); + +EFI_STATUS +CheckPMDevicePresence ( + SATA_DEVICE_INTERFACE *SataDevInterface, + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, + UINT8 Port, + UINT8 PMPort +); + +EFI_STATUS +ConfigureDevice ( + SATA_DEVICE_INTERFACE *SataDevInterface, + EFI_ATA_COLLECTIVE_MODE **SupportedModes +); + +EFI_STATUS +ConfigureController ( + SATA_DEVICE_INTERFACE *SataDevInterface, + EFI_ATA_COLLECTIVE_MODE *SupportedModes +); + +VOID +InitializeDipm( + SATA_DEVICE_INTERFACE *SataDevInterface +); + +VOID +InitializeDeviceSleep ( + SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +HostReset ( + AHCI_BUS_PROTOCOL *AhciBusInterface +); + + +EFI_STATUS +GeneratePortReset ( + AHCI_BUS_PROTOCOL *AhciBusInterface, + SATA_DEVICE_INTERFACE *SataDevInterface, + UINT8 Port, + UINT8 PMPort, + UINT8 Speed, + UINT8 PowerManagement +); + +EFI_STATUS +GenerateSoftReset ( + SATA_DEVICE_INTERFACE *SataDevInterface, + UINT8 PMPort +); + +EFI_STATUS +GetIdentifyData ( + SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +HandlePortComReset( + AHCI_BUS_PROTOCOL *AhciBusInterface, + SATA_DEVICE_INTERFACE *SataDevInterface, + UINT8 Port, + UINT8 PMPort +); + +EFI_STATUS +CheckValidDevice ( + AHCI_BUS_PROTOCOL *AhciBusInterface, + UINT8 Port, + UINT8 PMPort +); + +SATA_DEVICE_INTERFACE* +GetSataDevInterface( + AHCI_BUS_PROTOCOL *AhciBusInterface, + UINT8 Port, + UINT8 PMPort +); + +EFI_STATUS +ExecuteNonDataCommand ( + SATA_DEVICE_INTERFACE *SataDevInterface, + COMMAND_STRUCTURE CommandStructure +); + +EFI_STATUS +ExecutePioDataCommand ( + SATA_DEVICE_INTERFACE *SataDevInterface, + COMMAND_STRUCTURE *CommandStructure, + BOOLEAN READWRITE +); + +EFI_STATUS +ExecuteDmaDataCommand ( + SATA_DEVICE_INTERFACE *SataDevInterface, + COMMAND_STRUCTURE *CommandStructure, + BOOLEAN READWRITE +); + +EFI_STATUS +SataReadWritePio( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT VOID *Buffer, + IN UINTN ByteCount, + IN UINT64 LBA, + IN UINT8 ReadWriteCommand, + IN BOOLEAN READWRITE +) ; + +EFI_STATUS +SataPioDataOut ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT VOID *Buffer, + IN UINTN ByteCount, + IN UINT8 Features, + IN UINT8 LBALow, + IN UINT8 LBALowExp, + IN UINT8 LBAMid, + IN UINT8 LBAMidExp, + IN UINT8 LBAHigh, + IN UINT8 LBAHighExp, + IN UINT8 Command, + IN BOOLEAN READWRITE +) ; + +EFI_STATUS +WaitforCommandComplete ( + SATA_DEVICE_INTERFACE *SataDevInterface, + COMMAND_TYPE CommandType, + UINTN TimeOut +); + +UINT8 +ReturnMSBset( + UINT32 Data +); + +EFI_STATUS +StartController ( + AHCI_BUS_PROTOCOL *AhciBusInterface, + SATA_DEVICE_INTERFACE *SataDevInterface, + UINT32 CIBitMask +); + +EFI_STATUS +ReadytoAcceptCmd ( + SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +StopController( + AHCI_BUS_PROTOCOL *AhciBusInterface, + SATA_DEVICE_INTERFACE *SataDevInterface, + BOOLEAN StartOrStop +) ; + +EFI_STATUS +DetectAndConfigureDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, + AHCI_BUS_PROTOCOL *AhciBusInterface, + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeControllerInterface, + UINT8 Port, + UINT8 PMPort +); + +EFI_STATUS +ConfigurePMPort ( + SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +ReadWritePMPort ( + SATA_DEVICE_INTERFACE *SataDevInterface, + UINT8 Port, + UINT8 RegNum, + UINT32 *Data, + BOOLEAN READWRITE +); + +UINT32 +ReadSCRRegister ( + AHCI_BUS_PROTOCOL *AhciBusInterface, + SATA_DEVICE_INTERFACE *SataDevInterface, + UINT8 Port, + UINT8 PMPort, + UINT8 Register +); + +EFI_STATUS +WriteSCRRegister ( + AHCI_BUS_PROTOCOL *AhciBusInterface, + SATA_DEVICE_INTERFACE *SataDevInterface, + UINT8 Port, + UINT8 PMPort, + UINT8 Register, + UINT32 Data32 +); + +EFI_STATUS +WritePMPort ( + SATA_DEVICE_INTERFACE *SataDevInterface, + UINT8 Port, + UINT8 RegNum, + UINT32 Data +); + +EFI_STATUS +BuildCommandList ( + SATA_DEVICE_INTERFACE *SataDevInterface, + AHCI_COMMAND_LIST *CommandList, + UINT32 CommandTableBaseAddr +); + +EFI_STATUS +BuildCommandFIS ( + SATA_DEVICE_INTERFACE *SataDevInterface, + COMMAND_STRUCTURE CommandStructure, + AHCI_COMMAND_LIST *CommandList, + AHCI_COMMAND_TABLE *Commandtable +); + +EFI_STATUS +BuildAtapiCMD( + SATA_DEVICE_INTERFACE *SataDevInterface, + COMMAND_STRUCTURE CommandStructure, + AHCI_COMMAND_LIST *CommandList, + AHCI_COMMAND_TABLE *Commandtable +); + +EFI_STATUS +BuildPRDT +( + SATA_DEVICE_INTERFACE *SataDevInterface, + COMMAND_STRUCTURE CommandStructure, + AHCI_COMMAND_LIST *CommandList, + AHCI_COMMAND_TABLE *Commandtable +); + +EFI_STATUS +WaitForMemSet ( + IN UINT32 BaseAddr, + IN UINT8 Port, + IN UINT8 Register, + IN UINT32 AndMask, + IN UINT32 TestValue, + IN UINT32 WaitTimeInMs +); + +EFI_STATUS +WaitforPMMemSet ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN UINT8 PMPort, + IN UINT8 Register, + IN UINT32 AndMask, + IN UINT32 TestValue, + IN UINT32 WaitTimeInMs +); + +EFI_STATUS +WaitForMemClear ( + IN UINT32 BaseAddr, + IN UINT8 Port, + IN UINT8 Register, + IN UINT32 AndMask, + IN UINT32 WaitTimeInMs +); + +EFI_STATUS +CreateSataDevicePath ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +); + +EFI_STATUS +InitSataBlockIO ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +InitSataDiskInfo ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +InitAcousticSupport ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +InitSMARTSupport ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +SMARTReturnStatusWrapper( + IN SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +ConfigurePowerUpInStandby ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +AhciBusSupported( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +); + +EFI_STATUS +AhciBusStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +); + +EFI_STATUS +AhciBusStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer +); + + +EFI_STATUS +DiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *InquiryDataSize +); + +EFI_STATUS +DiskInfoIdentify ( + EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize +); + +EFI_STATUS +DiskInfoSenseData( + EFI_DISK_INFO_PROTOCOL *This, + VOID *SenseData, + UINT32 *SenseDataSize, + UINT8 *SenseDataNumber +); + +EFI_STATUS +DiskInfoWhichIDE +( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice +); + +#define ZeroMemory(Buffer,Size) pBS->SetMem(Buffer,Size,0) + + +BOOLEAN +DMACapable( + SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +SataBlkRead( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer +); + +EFI_STATUS +SataBlkWrite( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer +); + +EFI_STATUS +SataAtaBlkReadWrite ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer, + BOOLEAN READWRITE +); + +EFI_STATUS +SataAtapiBlkRead( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer +); + +EFI_STATUS +SataAtapiBlkWrite( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer +); + +EFI_STATUS +SataReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification +); + +EFI_STATUS +SataBlkFlush( + IN EFI_BLOCK_IO_PROTOCOL *This +); + +EFI_STATUS +SataReadWriteBusMaster( + SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT VOID *Buffer, + IN UINTN ByteCount, + IN UINT64 LBA, + IN UINT8 ReadWriteCommand, + IN BOOLEAN READWRITE +); + +EFI_STATUS +SataAtapiInquiryData ( + SATA_DEVICE_INTERFACE *SataDevInterface, + UINT8 *InquiryData, + UINT16 *InquiryDataSize +); + +EFI_STATUS +DetectAtapiMedia( + SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +TestUnitReady( + SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +ExecutePacketCommand ( + SATA_DEVICE_INTERFACE *SataDevInterface, + COMMAND_STRUCTURE *CommandStructure, + BOOLEAN READWRITE +); + +EFI_STATUS +SataAtapiBlkReadWrite( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer, + BOOLEAN READWRITE +); + +EFI_STATUS +HandleAtapiError ( + SATA_DEVICE_INTERFACE *SataDevInterface +); + +BOOLEAN +Check48BitCommand ( + IN UINT8 Command +); + +EFI_STATUS +InitSMARTSupport ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +SMARTReturnStatusWrapper( + IN SATA_DEVICE_INTERFACE *SataDevInterface +); + +EFI_STATUS +SataGetOddType ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT UINT16 *OddType +); + +EFI_STATUS +SataGetOddLoadingType ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT UINT8 *OddLoadingType +); + +ODD_TYPE +GetEnumOddType( + IN UINT16 OddType +); + +EFI_STATUS +ConfigureSataPort ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +); + + +#if INDEX_DATA_PORT_ACCESS +UINT32 +ReadDataDword( + IN UINTN BaseAddr, + IN UINTN Index +); + +UINT16 +ReadDataWord( + IN UINTN BaseAddr, + IN UINTN Index +); + +UINT8 +ReadDataByte( + IN UINTN BaseAddr, + IN UINTN Index +); + +VOID +WriteDataDword( + IN UINTN BaseAddr, + IN UINTN Index, + IN UINTN Data +); + +VOID +WriteDataWord( + IN UINTN BaseAddr, + IN UINTN Index, + IN UINTN Data +); + +VOID +WriteDataByte( + IN UINTN BaseAddr, + IN UINTN Index, + IN UINTN Data +); +#endif + +/****** DO NOT WRITE BELOW THIS LINE *******/ +#ifdef __cplusplus +} +#endif + +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2013, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AhciComponentName.c b/Core/EM/Ahci/AhciComponentName.c new file mode 100644 index 0000000..1d68ea5 --- /dev/null +++ b/Core/EM/Ahci/AhciComponentName.c @@ -0,0 +1,314 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/AhciComponentName.c 7 1/27/14 4:57a Rameshr $ +// +// $Revision: 7 $ +// +// $Date: 1/27/14 4:57a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/AHCI/AhciComponentName.c $ +// +// 7 1/27/14 4:57a Rameshr +// [TAG] EIP148180 +// [Category] Improvement +// [Description] Change from EFI_MBR_WRITE_PROTECTION_PROTOCOL to +// AMI_BLOCKIO_WRITE_PROTECTION_PROTOCOL +// [Files] Ahcibus.c, Ahcibus.h, AhciComponentName.c, AhciController.c +// +// 6 2/10/11 10:35a Rameshr +// [TAG] EIP53704 +// [Category] Improvement +// [Description] AMI headers update for Alaska Ahci Driver +// [Files] AhciSrc.mak +// AhciBus.c +// AhciController.c +// AhciComponentName.c +// AhciBus.h +// AhciController.h +// +// 5 5/07/10 11:45a Krishnakumarg +// Coding standard update +// +// 4 3/26/10 5:37p Krishnakumarg +// UEFI2.1 compliance change EIP#34744. +// +// 3 4/28/09 3:57p Rameshr +// +// HDD password support in RAID mode +// EIP:20421 +// +// 2 5/28/08 9:39a Rameshraju +// +// 1 28/02/08 6:03p Anandakrishnanl +// AHCI Bus Driver initial check-in. +// +// +// +//********************************************************************** + +#include "AhciBus.h" + +extern EFI_GUID gSecurityModeProtocolGuid; +static EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID; +extern EFI_DRIVER_BINDING_PROTOCOL gAhciBusDriverBinding; + +#ifndef EFI_COMPONENT_NAME2_PROTOCOL_GUID //old Core +#define LANGUAGE_CODE_ENGLISH "eng" +#define EFI_COMPONENT_NAME2_PROTOCOL EFI_COMPONENT_NAME_PROTOCOL +#endif + +EFI_STATUS AhciBusCtlDriverName( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName +); + +EFI_STATUS +AhciBusCtlGetControllerName( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName +); + + +CHAR16 *gAhciBusDriverName = L"AMI AHCI BUS Driver"; +CHAR16 *gAhciBusControllerName = L"AHCI Mass Storage Controller"; + +//================================================================================== +EFI_COMPONENT_NAME2_PROTOCOL gAhciBusControllerDriverName = { + AhciBusCtlDriverName, + AhciBusCtlGetControllerName, + LANGUAGE_CODE_ENGLISH +}; + +static BOOLEAN LanguageCodesEqual( + CONST CHAR8* LangCode1, CONST CHAR8* LangCode2 +){ + return LangCode1[0]==LangCode2[0] + && LangCode1[1]==LangCode2[1] + && LangCode1[2]==LangCode2[2]; +} + +// +//--------------------------------------------------------------------------- +// +// FUNCTION: AhciBusCtlDriverName +// +// DESCRIPTION: Retrieves a Unicode string that is the user readable name of +// the EFI Driver. +// +// +// PARAMETERS: +// This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. +// Language - A pointer to a three character ISO 639-2 language identifier. +// This is the language of the driver name that that the caller +// is requesting, and it must match one of the languages specified +// in SupportedLanguages. The number of languages supported by a +// driver is up to the driver writer. +// DriverName - A pointer to the Unicode string to return. This Unicode string +// is the name of the driver specified by This in the language +// specified by Language. +// +// RETURN: +// EFI_SUCCES - The Unicode string for the Driver specified by This +// and the language specified by Language was returned +// in DriverName. +// EFI_INVALID_PARAMETER - Language is NULL. +// EFI_INVALID_PARAMETER - DriverName is NULL. +// EFI_UNSUPPORTED - The driver specified by This does not support the +// language specified by Language. +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +AhciBusCtlDriverName( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName +) +{ + // + //Supports only English + // + if(!Language || !DriverName) return EFI_INVALID_PARAMETER; + if (!LanguageCodesEqual( Language, LANGUAGE_CODE_ENGLISH)) return EFI_UNSUPPORTED; + *DriverName = gAhciBusDriverName; + return EFI_SUCCESS; +} + + + +//--------------------------------------------------------------------------- +// +// +// FUNCTION: AhciBusCtlGetControllerName +// +// DESCRIPTION: Retrieves a Unicode string that is the user readable name of +// the controller that is being managed by an EFI Driver. +// +// PARAMETERS: +// This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. +// ControllerHandle - The handle of a controller that the driver specified by +// This is managing. This handle specifies the controller +// whose name is to be returned. +// ChildHandle - The handle of the child controller to retrieve the name +// of. This is an optional parameter that may be NULL. It +// will be NULL for device drivers. It will also be NULL +// for a bus drivers that wish to retrieve the name of the +// bus controller. It will not be NULL for a bus driver +// that wishes to retrieve the name of a child controller. +// Language - A pointer to a three character ISO 639-2 language +// identifier. This is the language of the controller name +// that that the caller is requesting, and it must match one +// of the languages specified in SupportedLanguages. The +// number of languages supported by a driver is up to the +// driver writer. +// ControllerName - A pointer to the Unicode string to return. This Unicode +// string is the name of the controller specified by +// ControllerHandle and ChildHandle in the language +// specified by Language from the point of view of the +// driver specified by This. +// +// RETURNS: +// EFI_SUCCESS - The Unicode string for the user readable name in the +// language specified by Language for the driver +// specified by This was returned in DriverName. +// EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. +// EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid +// EFI_HANDLE. +// EFI_INVALID_PARAMETER - Language is NULL. +// EFI_INVALID_PARAMETER - ControllerName is NULL. +// EFI_UNSUPPORTED - The driver specified by This is not currently +// managing the controller specified by +// ControllerHandle and ChildHandle. +// EFI_UNSUPPORTED - The driver specified by This does not support the +// language specified by Language. +// +// +//--------------------------------------------------------------------------- + + +EFI_STATUS +AhciBusCtlGetControllerName( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName +) +{ + + EFI_STATUS Status; + SATA_DEVICE_INTERFACE *SataDevInterface; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + SECURITY_PROTOCOL *AhciSecurityInterface; + UINTN j, InfoCount; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *pInfo; + + Status = pBS->OpenProtocol( Controller, + &gEfiIdeControllerInitProtocolGuid, + NULL, + gAhciBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + + if (Status != EFI_SUCCESS && Status != EFI_ALREADY_STARTED) { + return EFI_UNSUPPORTED; + } + + // + //Supports only "eng" + // + if(!Language || !ControllerName) return EFI_INVALID_PARAMETER; + if (!LanguageCodesEqual( Language, LANGUAGE_CODE_ENGLISH)) return EFI_UNSUPPORTED; + + if (ChildHandle == NULL) { + *ControllerName = gAhciBusControllerName; + return EFI_SUCCESS; + } + else { + Status = pBS->OpenProtocolInformation( + Controller, + &gEfiIdeControllerInitProtocolGuid, + &pInfo,&InfoCount + ); + if (EFI_ERROR(Status)) return EFI_UNSUPPORTED; + for(j=0; jFreePool(pInfo); + if (j >= InfoCount) return EFI_UNSUPPORTED; + + // + // Open the BLOCK_IO protocol installed on the child device. + // + Status = pBS->OpenProtocol ( ChildHandle, + &gEfiBlockIoProtocolGuid, + (VOID **)&BlkIo, + gAhciBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + + if (EFI_ERROR(Status)) { + // + // If BLKIO protocol is not installed, maybe Securitymode + // protocol is installed. + // + Status = pBS->OpenProtocol ( ChildHandle, + &gSecurityModeProtocolGuid, + (VOID **)&AhciSecurityInterface, + gAhciBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + // + // Return Error. + // + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + SataDevInterface = AhciSecurityInterface->BusInterface; + }else { + SataDevInterface = ((SATA_BLOCK_IO *)BlkIo)->SataDevInterface; + } + if (SataDevInterface->IdeDeviceHandle != ChildHandle) return EFI_UNSUPPORTED; + + *ControllerName = SataDevInterface->UDeviceName->UnicodeString; + return EFI_SUCCESS; + } + +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AhciController.c b/Core/EM/Ahci/AhciController.c new file mode 100644 index 0000000..73d6c31 --- /dev/null +++ b/Core/EM/Ahci/AhciController.c @@ -0,0 +1,3403 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/AhciController.c 41 1/27/14 4:57a Rameshr $ +// +// $Revision: 41 $ +// +// $Date: 1/27/14 4:57a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/AHCI/AhciController.c $ +// +// 41 1/27/14 4:57a Rameshr +// [TAG] EIP148180 +// [Category] Improvement +// [Description] Change from EFI_MBR_WRITE_PROTECTION_PROTOCOL to +// AMI_BLOCKIO_WRITE_PROTECTION_PROTOCOL +// [Files] Ahcibus.c, Ahcibus.h, AhciComponentName.c, AhciController.c +// +// 40 12/20/13 4:06a Rameshr +// [TAG] EIP126640 +// [Category] Improvement +// [Description] AHCIBUS driver need to preserve the port settings in +// GeneratePortReset +// [Files] Ahcibus.c, AhciController.c +// +// 39 8/27/13 4:16a Rameshr +// [TAG] EIP125560 +// [Category] Improvement +// [Description] MbrWriteProtectionProtocol file name changesd to +// AmiMbrWriteProtectionProtocol.h +// [Files] AhciController.c, AhciBus.h, Ahcibus.c +// +// 38 7/01/13 5:32a Kapilporwal +// [TAG] EIP125560 +// [Category] Improvement +// [Description] Please support Boot Sector Virus Protection for CSM +// Disabled Mode +// [Files] VirusProtect.c, VirusProtect.dxs, AhciBus.c, +// AhciController.c, CsmBlockIo.c, CsmInt13.c, Ata.c, IdeBus.c, +// SdioBlkIo.c, SdioDriver.c, efiusbmass.c +// +// 37 11/18/12 11:45p Rameshr +// [TAG] EIP102518 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] SCT failure for ATAPI BlockIO +// [RootCause] BufferSize and IOAllign checking not added for Atapi +// BlockIO protocol functions +// [Solution] Added BufferSize and IOAllign checking for Atapi BlockIO +// protocol functions +// [Files] AhciController.c +// +// 36 9/17/12 12:52a Rameshr +// [TAG] EIP100335 +// [Category] Improvement +// [Description] Port Multiplier spend long time to connect device. +// [Files] Ahcibus.c , AhciController.c +// +// 35 9/17/12 12:43a Anandakrishnanl +// [TAG] EIP100847 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] System hangs when Memory allocation >4Gb in AHCI Mode +// [RootCause] DBAU not programmed for AhciController +// [Solution] Fixed by Programming DBAU in PRDT Table +// [Files] AhciController.c +// +// 34 8/21/12 2:28a Rameshr +// [TAG] EIP98526 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] FIS and CommandList Base address store and restore wont +// work incase of recursive call +// [RootCause] FIS and CommandList Base address store and restore wont +// work incase of recursive call +// [Solution] FIS and Command List base Address save and restore done +// properly when the function called recursively. +// [Files] Ahcicontroller.c +// +// 33 8/17/12 3:10a Srikantakumarp +// [TAG] EIP95863 +// [Category] Bug Fix +// [Symptom] AhciSmm doesnt save and restore the upper 32bits of FBU and +// CLBU +// [RootCause] As Windows uses the 64bit address for FIS Base Address +// and Command List Base Address, and AHCISMM driver doesn't take care of +// the upper 32bit value of those which cause the failure in AhciSMM +// driver. +// [Solution] Save and Restore the upper 32bits of FBU and CLBU in +// AhciSmm Driver. +// [Files] AhciController.c, AhciSmm.c +// +// 32 8/16/12 3:06a Rajeshms +// [TAG] EIP97048 +// [Category] New Feature +// [Description] ATAPI PassThru Support using +// EFI_EXT_SCSI_PASS_THRU_PROTOCOL. +// [Files] AhciBus.c, AhciController.c, IdeBus.c, Atapi.c, PIDEBus.h, +// PAhciBus.h, ScsiPassThruAtapi.sdl, ScsiPassThruAtapi.mak, +// ScsiPassThruAtapi.c, ScsiPassThruAtapiSupport.h, ScsiPassThruAtapi.chm, +// ScsiPassThruExt.h +// +// 31 2/03/12 3:23a Rameshr +// [TAG] EIP82275 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] SataReadWritePio doesn't work if the ReadSector count is +// more than 256 sectors +// [RootCause] Buffer Address not incremented for the next Read +// [Solution] Handled the buffer address properly for the next Pio Read +// [Files] AhciController.c +// +// 30 11/08/11 5:19a Deepthins +// [TAG] EIP74607 +// [Category] Improvement +// [Description] Block IO Read/Write function, the alignment should be +// proper. IoAlign value is 0 or 1 means that the buffer can be placed +// anywhere in memory. Otherwise, IoAlign must be a power of 2, and the +// requirement is that the start address of a buffer must be evenly +// divisible by IoAlign with no remainder. +// [Files] Ata.c, Atapi.c and AhciController.c +// +// 29 11/07/11 4:31a Deepthins +// [TAG] EIP74607 +// [Category] Improvement +// [Description] IoAlign value is 0 or 1 means that the buffer can be +// placed anywhere in memory. Otherwise, IoAlign must be a power of 2, and +// the requirement is that the start address of a buffer must be +// evenlydivisible by 2 to the power of IoAlign with no remainder. +// [Files] AhciController.c +// +// 28 11/07/11 2:30a Deepthins +// [TAG] EIP73941 +// [Category] Improvement +// [Description] BufferSize is 0, ReadBlock function should return +// EFI_SUCCESS without actual reading. +// [Files] AhciController.c +// +// 27 5/09/11 6:29a Anandv +// [TAG] - EIP59552 +// [Category] - BUG FIX +// [Severity] - Normal +// [Symptom] -AhciController.c file in Ahci driver needs modification to +// Support Index/Data Port access method for getting the FIS Address. +// [RootCause] - FISAddress was Obtained using MMIO method irrespective of +// "INDEX_DATA_PORT_ACCESS" SDL token. +// [Solution] - FISAddress is now obtained using Port I/O or MMIO method +// depending on +// "INDEX_DATA_PORT_ACCESS" SDL token. +// [Files] - AhciController.c +// +// 26 3/29/11 1:03a Lavanyap +// [TAG] - EIP53849 +// [Category] - BUG FIX +// [Severity] - Normal +// [Symptom] - Ide Bus Sources cannot build in IA32 DEBUG mode. +// [RootCause] - It happened because of usage of << and * with UINT64 +// values in AtaPioDataOut() and SataPioDataOut(). +// [Solution] - Shl64 and Mul64 functions have been implemented to operate +// UINT64 values. +// [Files] - Ata.c, AhciController.c +// +// 25 2/21/11 3:38a Rameshr +// Helpbuilder Issue Resolved +// +// 24 2/18/11 5:06a Rameshr +// [TAG]- EIP 37975 +// [Category]-IMPROVEMENT +// [Description]- Klocwork Issues II - IDE/Ahci module +// [Files]- AhciBus.c, AhciController.c +// +// 23 2/11/11 4:22a Rameshr +// [TAG] EIP53730 +// [Category] Improvement +// [Description] Add Odd Loading type information into ATAPI_DEVICE +// structure in AHCI mode +// [Files] AhciBus.c +// AhciController.c +// AhciBus.h +// +// 22 2/10/11 10:35a Rameshr +// [TAG] EIP53704 +// [Category] Improvement +// [Description] AMI headers update for Alaska Ahci Driver +// [Files] AhciSrc.mak +// AhciBus.c +// AhciController.c +// AhciComponentName.c +// AhciBus.h +// AhciController.h +// +// 21 12/23/10 3:59a Lavanyap +// [TAG] - EIP41445 +// [Category] - NEW FEATURE +// [Description] - Created SataPioDataOut and AtaPioDataOut protocol +// function that can accept additional input parameters. +// [Files] - AhciBus.h, AhciBus.c, AhciController.c, Ata.c, IdeBus.c, +// IdeBus.h, IdeBusMaster.c,PAhciBus.h, PIdeBus.h +// +// 20 4/16/10 4:15p Pats +// EIP 30719: Support for the HDD with sector size more than 512bytes. +// +// 19 9/22/09 10:53a Krishnakumarg +// Code modified to update SataDevInterface->identifydata in +// GetIdentifyData function instead of returning in global variable - +// EIP26411 +// +// 18 9/21/09 12:34p Krishnakumarg +// It takes a long time to detect large size HDD(eg. 500GB, 1TB size) +// under AHCI mode-EIP26499. +// Replaced TAB with spaces for AMI code standard +// +// 17 8/12/09 5:07p Davidd +// Corrected command parameter error in all PACKET_COMMAND - EIP 24817 +// +// 16 6/22/09 11:35a Rameshr +// Odd Type information Saved in Atapi Device Structure. +// EIP:21548 +// +// 15 6/18/09 4:27p Rameshr +// if the Erase command timeout value is 0 or 255, wait for the Erase +// command completion without timeout value +// EIP:20630 +// +// 14 4/29/09 10:54a Rameshr +// +// 13 4/28/09 3:51p Rameshr +// +// HDD password support in RAID mode +// EIP:20421 +// +// 12 3/29/09 11:08a Rameshr +// Security Erase command timeout value should be from the Identify packet +// command word 89 +// EIP 20630 +// +// 11 12/11/08 1:55p Srinin +// After COMRESET, wait for shadow status register to get synced up with +// D2H FIS +// +// 10 26/09/08 12:32p Anandakrishnanl +// Fixed Ahci Block Write Issue Which Exceeds 4MB. Added the Proper Offset +// of Descriptor and Fixed Valid PRDT_I Bit. +// +// 9 13/08/08 2:24p Anandakrishnanl +// Fixed the Minor error that occured in Previous Checkin for EfiDiag NO +// Media Issue +// +// 8 12/08/08 11:26a Anandakrishnanl +// Fixed the error reported by EFI Diag r(CD/DVD test) to return +// EFI_NO_MEDIA. +// +// 7 5/28/08 9:38a Rameshraju +// Based on the SDL token index/data or MMIO method used to access the +// AHCI configuration space. +// +// 6 5/09/08 10:05a Rameshraju +// Default status initilized. +// +// 5 4/10/08 12:52p Srinin +// PMPort field in Command header and in FIS is set to zero instead of 0xF +// when PORT 0 is accessed. +// +// 4 4/03/08 4:40p Srinin +// In ReadytoAcceptCmd Status was not initialized. Fixed it. +// +// 3 3/24/08 6:19p Fasihm +// Fixed issue that few HDDs not detected because of PhyRdy Change bit. +// +// 2 7/03/08 5:31p Anandakrishnanl +// Added Smart Support as a seperate Driver and Corresponding changes to +// invoke Smart Protocols and removed SDL-Token +// +// 1 28/02/08 6:03p Anandakrishnanl +// AHCI Bus Driver initial check-in. +// +// +// +//********************************************************************** +// +// +// Name: AhciController.c +// +// Description: Provides Access to AHCI Controller +// +// +//********************************************************************** + +#include "AhciBus.h" + +#if defined CORE_COMBINED_VERSION && (CORE_COMBINED_VERSION > 0x4028E) +extern AMI_BLOCKIO_WRITE_PROTECTION_PROTOCOL *AmiBlkWriteProtection; +#endif + +BOOLEAN gPortReset = FALSE; // Avoid Re-entry +BOOLEAN gSoftReset = FALSE; // Avoid Re-entry +UINT32 gCommandListBaseAddress = 0; +UINT32 gFisBaseAddress; +UINT32 gCommandListBaseAddress2; +UINT32 gFisBaseAddress2; + +// +//--------------------------------------------------------------------------- +// +// Procedure: SataBlkRead +// +// Description: Read from the Sata ATA Device +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: SataAtaBlkReadWrite +// +// Notes: +// +// +//--------------------------------------------------------------------------- +// +EFI_STATUS +SataBlkRead( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + + EFI_STATUS Status; + + Status = SataAtaBlkReadWrite(This, MediaId, LBA, BufferSize, Buffer, 0); + + TRACE((TRACE_ALWAYS,"AHCI Read: LBA : %lx ByteCount : %lx\n", LBA, BufferSize)); + + return Status; +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: SataBlkWrite +// +// Description: Write to Sata ATA Device +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: SataAtaBlkReadWrite +// +// Notes: +// +// +//--------------------------------------------------------------------------- +// +EFI_STATUS +SataBlkWrite( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + + EFI_STATUS Status; + +#if defined CORE_COMBINED_VERSION && (CORE_COMBINED_VERSION > 0x4028E) + if(AmiBlkWriteProtection != NULL) { + // Get user input + Status = AmiBlkWriteProtection->BlockIoWriteProtectionCheck( + AmiBlkWriteProtection, + This, + LBA, + BufferSize + ); + // Abort operation if denied + if(Status == EFI_ACCESS_DENIED) { + return Status; + } + } +#endif + + Status = SataAtaBlkReadWrite(This, MediaId, LBA, BufferSize, Buffer, 1); + + TRACE((TRACE_ALWAYS,"AHCI Write: LBA : %lx ByteCount : %lx\n", LBA, BufferSize)); + + return Status; + +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: SataAtaBlkReadWrite +// +// Description: Read/Write to/from Sata ATA Device +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer, +// BOOLEAN READWRITE +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: SataReadWriteBusMaster, SataReadWritePio +// +// Notes: +// 1. Check for validity of the input +// 2. Issue DMA or PIO Read/Write call. +// +//--------------------------------------------------------------------------- +// +EFI_STATUS +SataAtaBlkReadWrite ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer, + BOOLEAN READWRITE +) +{ + + EFI_STATUS Status = EFI_DEVICE_ERROR; + SATA_DEVICE_INTERFACE *SataDevInterface = ((SATA_BLOCK_IO *)This)->SataDevInterface; + EFI_BLOCK_IO_MEDIA *BlkMedia = This->Media; + UINTN DataN; + UINTN BufferAddress; + + // Check if Media ID matches + if (BlkMedia->MediaId != MediaId) return EFI_MEDIA_CHANGED; + + if (BufferSize == 0) return EFI_SUCCESS; + + // + // If IoAlign values is 0 or 1, means that the buffer can be placed + // anywhere in memory or else IoAlign value should be power of 2. To be + // properly aligned the buffer address should be divisible by IoAlign + // with no remainder. + // + (VOID *)BufferAddress = Buffer; + if((BlkMedia->IoAlign > 1 ) && (BufferAddress % BlkMedia->IoAlign)) { + return EFI_INVALID_PARAMETER; + } + + // Check whether the block size is multiple of BlkMedia->BlockSize + DataN = BufferSize % BlkMedia->BlockSize; + if (DataN) return EFI_BAD_BUFFER_SIZE; + + // Check for Valid start LBA # + if (LBA > BlkMedia->LastBlock) return EFI_INVALID_PARAMETER; + + // Check for Valid End LBA # + DataN = BufferSize / BlkMedia->BlockSize; + if (LBA + DataN > BlkMedia->LastBlock + 1) return EFI_INVALID_PARAMETER; + + #if IDEBUSMASTER_SUPPORT + if (DMACapable(SataDevInterface)) { + Status = SataReadWriteBusMaster (SataDevInterface, Buffer, BufferSize, LBA, + READWRITE ? SataDevInterface->WriteCommand : SataDevInterface->ReadCommand, + READWRITE); + return Status; + } + #endif + + Status = SataReadWritePio (SataDevInterface, Buffer, BufferSize, LBA, + READWRITE ? SataDevInterface->WriteCommand : SataDevInterface->ReadCommand, + READWRITE); + + return Status; + +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: SataAtapiBlkRead +// +// Description: Read from the Sata ATAPI Device +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: SataAtapiBlkReadWrite +// +// Notes: +// +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +SataAtapiBlkRead( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + + EFI_STATUS Status; + + Status = SataAtapiBlkReadWrite(This, MediaId, LBA, BufferSize, Buffer, 0); + + TRACE((TRACE_ALWAYS,"AHCI ATAPI Read: LBA : %lx ByteCount : %lx\n", LBA, BufferSize)); + + return Status; + + + +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: SataAtapiBlkWrite +// +// Description: Write to Sata ATAPI Device +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: SataAtapiBlkReadWrite +// +// Notes: +// +// +//--------------------------------------------------------------------------- +// +EFI_STATUS +SataAtapiBlkWrite( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + + EFI_STATUS Status; + + Status = SataAtapiBlkReadWrite(This, MediaId, LBA, BufferSize, Buffer, 1); + + TRACE((TRACE_ALWAYS,"AHCI ATAPI Read: LBA : %lx ByteCount : %lx\n", LBA, BufferSize)); + + return Status; + +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: SataAtapiBlkReadWrite +// +// Description: Read/Write to/from Sata ATAPI Device +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Check for validity of Inputs +// 2. Check whether Media is present or not +// 3. Issue ATAPi Packet command +// +//--------------------------------------------------------------------------- +// +EFI_STATUS +SataAtapiBlkReadWrite( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer, + BOOLEAN READWRITE + ) +{ + + EFI_STATUS Status = EFI_DEVICE_ERROR; + SATA_DEVICE_INTERFACE *SataDevInterface = ((SATA_BLOCK_IO *)This)->SataDevInterface; + EFI_BLOCK_IO_MEDIA *BlkMedia = This->Media; + UINTN DataN; + ATAPI_DEVICE *AtapiDevice = SataDevInterface->AtapiDevice; + COMMAND_STRUCTURE CommandStructure; + INTN TotalNumberofBlocks; + INTN TransferLength; + UINTN BytesRemainingTobeRead; + VOID *TempBuffer = Buffer; + UINTN BufferAddress; + + + // Check if Media Present + + if (BlkMedia->MediaPresent == FALSE) { + Status = DetectAtapiMedia(SataDevInterface); + if (Status == EFI_SUCCESS) return EFI_MEDIA_CHANGED; + if (Status == EFI_NO_MEDIA) return Status; + return EFI_DEVICE_ERROR; + } + + // Check if Media ID matches + + if (BlkMedia->MediaId != MediaId) return EFI_MEDIA_CHANGED; + + if (BufferSize == 0) return EFI_SUCCESS; + + // If IoAlign values is 0 or 1, means that the buffer can be placed + // anywhere in memory or else IoAlign value should be power of 2. To be + // properly aligned the buffer address should be divisible by IoAlign + // with no remainder. + + (VOID *)BufferAddress = Buffer; + if((BlkMedia->IoAlign > 1 ) && (BufferAddress % BlkMedia->IoAlign)) { + return EFI_INVALID_PARAMETER; + } + + // Check whether the block size is multiple of BlkMedia->BlockSize + + DataN = BufferSize % BlkMedia->BlockSize; + if (DataN) return EFI_BAD_BUFFER_SIZE; + + // Check for Valid start LBA # + + if (LBA > BlkMedia->LastBlock) return EFI_INVALID_PARAMETER; + + // Check for Valid End LBA #8 + + DataN = BufferSize / BlkMedia->BlockSize; + if (LBA + DataN > BlkMedia->LastBlock + 1) return EFI_INVALID_PARAMETER; + + + TotalNumberofBlocks = BufferSize / AtapiDevice->BlockSize; + + for (; TotalNumberofBlocks > 0; TotalNumberofBlocks -= TransferLength) { + + ZeroMemory (&CommandStructure, sizeof(CommandStructure)); + + // Calculate # of blocks to be transferred + + if (TotalNumberofBlocks > 0xffff) + TransferLength = 0xffff; + else + TransferLength = TotalNumberofBlocks; + + BytesRemainingTobeRead = TransferLength * AtapiDevice->BlockSize; + + if (READWRITE) CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] = SataDevInterface->WriteCommand; + else CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] = SataDevInterface->ReadCommand; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[1] = AtapiDevice->Lun << 5; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[2] = (UINT8)(((UINT32) LBA) >> 24); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[3] = (UINT8)(((UINT32) LBA) >> 16); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[4] = (UINT8)(((UINT16) LBA) >> 8); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[5] = (UINT8)(((UINT8) LBA) & 0xff); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[7] = (UINT8) (TransferLength >> 8); // MSB + CommandStructure.AtapiCmd.Ahci_Atapi_Command[8] = (UINT8) (TransferLength & 0xff); // LSB + CommandStructure.Buffer = TempBuffer; + CommandStructure.ByteCount = (UINT32)BytesRemainingTobeRead; + + Status = ExecutePacketCommand(SataDevInterface, &CommandStructure, READWRITE); + + if (Status != EFI_SUCCESS) { + + // Some error has occured + // Check if Device is getting ready. If yes, wait till it gets ready + + if (AtapiDevice->Atapi_Status == BECOMING_READY) { + Status = TestUnitReady(SataDevInterface); + } + + if (Status == EFI_MEDIA_CHANGED ) { + Status = DetectAtapiMedia(SataDevInterface); + if (Status == EFI_SUCCESS) return EFI_MEDIA_CHANGED; // Return Media Change + if (Status == EFI_NO_MEDIA) { + SataDevInterface->SataBlkIo->BlkIo.Media->MediaPresent = FALSE; + return Status; + } + } + return Status; + } + + if (CommandStructure.ByteCount != BytesRemainingTobeRead) return EFI_DEVICE_ERROR; + + // Update pointer + + (UINT8 *) TempBuffer += BytesRemainingTobeRead; + LBA += TransferLength; + } + + return Status; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: SataReset +// +// Description: Reset ATA device +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN BOOLEAN ExtendedVerification +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +SataReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + return EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: SataBlkFlush +// +// Description: Flush the cache +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +SataBlkFlush( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} + + +// +//---------------------------------------------------------------------------- +// +// Procedure: SataReadWritePio +// +// Description: Issues Read/Write Command and Read/Write the data from/to the ATA device +// +// Input: +// IN IDE_BUS_PROTOCOL *IdeBusInterface, +// IN OUT VOID *Buffer, +// UINTN ByteCount, +// UINT64 LBA +// IN UINT8 ReadWriteCommand, +// IN BOOLEAN ReadWrite Read/Write = 0/1 +// +// Output: +// *Buffer, EFI_STATUS +// +// Modified: +// +// Referrals: ExecutePioDataCommand +// +// Notes: +// 1. Get the Max. number of sectors that can be Read/written in one Read/Write PIO command +// 2. Update the Command Structure +// 3. Issue ExecutePioDataCommand. +// 4. If all the bytes are read exit else goto step 2 +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +SataReadWritePio( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT VOID *Buffer, + IN UINTN ByteCount, + IN UINT64 LBA, + IN UINT8 ReadWriteCommand, + IN BOOLEAN READWRITE + ) +{ + EFI_STATUS Status; + UINT32 SectorCount; + INT64 MaxSectorCount; + INT64 Total_Number_Of_Sectors; + COMMAND_STRUCTURE CommandStructure; + UINT32 SectorSize = ATA_SECTOR_BYTES; + UINT8 *TempBuffer = Buffer; + if (Check48BitCommand(ReadWriteCommand)) + MaxSectorCount = MAX_SECTOR_COUNT_PIO_48BIT; + else + MaxSectorCount = MAX_SECTOR_COUNT_PIO; + + // + // Calculate Sector Size + // + if((SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT14) && // WORD 106 valid? - BIT 14 - 1 + (!(SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT15)) && // WORD 106 valid? - BIT 15 - 0 + (SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT12)) { // WORD 106 bit 12 - Sectorsize > 256 words + // The sector size is in words 117-118. + SectorSize = (UINT32)(SataDevInterface->IdentifyData.Reserved_104_126[13] + \ + (SataDevInterface->IdentifyData.Reserved_104_126[14] << 16)) * 2; + } + + if (SectorSize > ByteCount) SectorSize = (UINT32)ByteCount; + + // Calculate the total number of Sectors to be transferred + Total_Number_Of_Sectors = ByteCount / SectorSize ; + + for ( ;Total_Number_Of_Sectors > 0; Total_Number_Of_Sectors -= MaxSectorCount) { + + if (Total_Number_Of_Sectors > MaxSectorCount) SectorCount = 0; + else SectorCount = (UINT32) Total_Number_Of_Sectors; + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + + if (Check48BitCommand (ReadWriteCommand)) { + CommandStructure.LBALowExp = (UINT8)Shr64(LBA,24); + CommandStructure.LBAMidExp = (UINT8)Shr64(LBA,32); + CommandStructure.LBAHighExp = (UINT8)Shr64(LBA,40); + CommandStructure.Device = 0x40; // 48Bit LBA + } + else { // 28 Bit LBA + CommandStructure.Device = ((UINT8) ((UINT32) LBA >> 24) & 0x0f) | 0x40; + } + + CommandStructure.SectorCount = (UINT16) SectorCount; + CommandStructure.LBALow = (UINT8)LBA; + CommandStructure.LBAMid = (UINT8)(((UINT32)LBA >>8) & 0xff); + CommandStructure.LBAHigh = (UINT8)(((UINT32)LBA >>16) & 0xff); + CommandStructure.Command = ReadWriteCommand; + + CommandStructure.Buffer = TempBuffer; + CommandStructure.ByteCount = (UINT32)(SectorCount == 0 ? MaxSectorCount : Total_Number_Of_Sectors) * SectorSize ; + + Status = ExecutePioDataCommand (SataDevInterface, &CommandStructure, READWRITE); // Returns # of bytes read + + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + + TempBuffer += CommandStructure.ByteCount; + SectorCount = CommandStructure.ByteCount / SectorSize ; + LBA += SectorCount; + + } + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: SataPioDataOut +// +// Description: Issues Read/Write Command with SubCommand feature +// and Reads/Writes data to the ATA device. +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN OUT VOID *Buffer, +// IN UINTN ByteCount, +// IN UINT8 Features, +// IN UINT16 LBALow, +// IN UINT8 LBALowExp, +// IN UINT8 LBAMid, +// IN UINT8 LBAMidExp, +// IN UINT8 LBAHigh, +// IN UINT8 LBAHighExp, +// IN UINT8 ReadWriteCommand +// IN BOOLEAN READWRITE +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ExecutePioDataCommand +// +// Notes: +// 1. Get the Max. number of sectors that can be transferred in one Read/Write PIO command +// 2. Update the Command Structure +// 3. Issue ExecutePioDataCommand. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS SataPioDataOut ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT VOID *Buffer, + IN UINTN ByteCount, + IN UINT8 Features, + IN UINT8 LBALow, + IN UINT8 LBALowExp, + IN UINT8 LBAMid, + IN UINT8 LBAMidExp, + IN UINT8 LBAHigh, + IN UINT8 LBAHighExp, + IN UINT8 ReadWriteCommand, + IN BOOLEAN READWRITE + ) +{ + EFI_STATUS Status; + UINT32 SectorCount; + INT64 MaxSectorCount; + INT64 Total_Number_Of_Sectors; + COMMAND_STRUCTURE CommandStructure; + UINT32 SectorSize = ATA_SECTOR_BYTES; + UINT64 LBA = 0; + UINT64 LBAHighDword = 0; + + if (Check48BitCommand(ReadWriteCommand)) { + MaxSectorCount = MAX_SECTOR_COUNT_PIO_48BIT; + // + // if 48 Bit LBA form Upper Dword + // + LBAHighDword |= LBAHighExp; + LBAHighDword = ( Shl64(( Shl64( LBAHighDword, 8)| LBAMidExp), 8)| LBALowExp); + } else { + MaxSectorCount = MAX_SECTOR_COUNT_PIO; + } + // + // Complete LBA + // + LBA |= LBAHigh; + LBA = (( Shl64(( Shl64( LBA, 8) | LBAMid ), 8)| LBALow)| Shl64( LBAHighDword, 24 )); + + // + // Calculate Sector Size + // + if((SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT14) && // WORD 106 valid? - BIT 14 - 1 + (!(SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT15)) && // WORD 106 valid? - BIT 15 - 0 + (SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT12)) { // WORD 106 bit 12 - Sectorsize > 256 words + // The sector size is in words 117-118. + SectorSize = (UINT32)(SataDevInterface->IdentifyData.Reserved_104_126[13] + \ + (SataDevInterface->IdentifyData.Reserved_104_126[14] << 16)) * 2; + } + + if (SectorSize > ByteCount) SectorSize = (UINT32)ByteCount; + + // Calculate the total number of Sectors to be transferred + Total_Number_Of_Sectors = ByteCount / SectorSize ; + + for ( ;Total_Number_Of_Sectors > 0; Total_Number_Of_Sectors -= MaxSectorCount) { + + if ( Total_Number_Of_Sectors > MaxSectorCount ) SectorCount = 0; + else SectorCount = (UINT32) Total_Number_Of_Sectors; + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + + if (Check48BitCommand (ReadWriteCommand)) { + // + // If 48Bit LBA then form Upper DWord + // + CommandStructure.LBALowExp = LBALowExp; + CommandStructure.LBAMidExp = LBAMidExp; + CommandStructure.LBAHighExp = LBAHighExp; + CommandStructure.Device = 0x40; + } + else { // 28 Bit LBA + CommandStructure.Device = ((UINT8) LBAHigh & 0x0f) | 0x40; + } + + CommandStructure.Features = Features; // SubCommand + CommandStructure.SectorCount = (UINT16) SectorCount; + CommandStructure.LBALow = LBALow; + CommandStructure.LBAMid = LBAMid; + CommandStructure.LBAHigh = LBAHigh; + CommandStructure.Command = ReadWriteCommand; + + CommandStructure.Buffer = Buffer; + CommandStructure.ByteCount = (UINT32)(SectorCount == 0 ? MaxSectorCount : Total_Number_Of_Sectors) * SectorSize ; + + Status = ExecutePioDataCommand (SataDevInterface, &CommandStructure, READWRITE); // Returns # of bytes read + if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR; + + SectorCount = CommandStructure.ByteCount / SectorSize ; + LBA += SectorCount; + + } + + return EFI_SUCCESS; + +} + +//********************************************************************** +// +// +// Procedure: SataReadWriteBusMaster +// +// Description: Issues Read/Write Command and Read/Write the data from/to the ATA device +// using BusMaster +// +// Input: +// SATA_DEVICE_INTERFACE *SataDevInterface, +// IN OUT VOID *Buffer, +// IN UINTN ByteCount, +// IN UINT64 LBA, +// IN UINT8 ReadWriteCommand, +// IN BOOLEAN READWRITE +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ExecuteDmaDataCommand +// +// Notes: +// 1. Get the Max. number of sectors that can be Read/written in one Read/Write Bus master command +// 2. Update the Command Structure +// 3. Issue ExecutePioDataCommand. +// 4. If all the bytes are read exit else goto step 2 +// +// +//********************************************************************** +EFI_STATUS +SataReadWriteBusMaster( + SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT VOID *Buffer, + IN UINTN ByteCount, + IN UINT64 LBA, + IN UINT8 ReadWriteCommand, + IN BOOLEAN READWRITE + ) +{ + + EFI_STATUS Status; + UINTN Total_Number_Of_Sectors,MaxSectorCount; + UINTN CurrentSectorCount,CurrentByteCount; + UINT8 *TempBuffer = Buffer; + COMMAND_STRUCTURE CommandStructure; + UINT32 SectorSize = ATA_SECTOR_BYTES; + + if (Check48BitCommand(ReadWriteCommand)) + MaxSectorCount = MAX_SECTOR_COUNT_PIO_48BIT; + else + MaxSectorCount = MAX_SECTOR_COUNT_PIO; + + // + // Calculate Sector Size + // + if((SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT14) && // WORD 106 valid? - BIT 14 - 1 + (!(SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT15)) && // WORD 106 valid? - BIT 15 - 0 + (SataDevInterface->IdentifyData.Reserved_104_126[2] & BIT12)) { // WORD 106 bit 12 - Sectorsize > 256 words + // The sector size is in words 117-118. + SectorSize = (UINT32)(SataDevInterface->IdentifyData.Reserved_104_126[13] + \ + (SataDevInterface->IdentifyData.Reserved_104_126[14] << 16)) * 2; + } + if (SectorSize > ByteCount) SectorSize = (UINT32)ByteCount; + + Total_Number_Of_Sectors = ByteCount / SectorSize ; + + do { + if (Total_Number_Of_Sectors > MaxSectorCount) CurrentSectorCount = 0; + else CurrentSectorCount = Total_Number_Of_Sectors; + CurrentByteCount = (CurrentSectorCount == 0 ? MaxSectorCount : CurrentSectorCount) * SectorSize ; + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + + CommandStructure.Buffer = TempBuffer; + CommandStructure.ByteCount = (UINT32)CurrentByteCount; + CommandStructure.Command = ReadWriteCommand; + + if (Check48BitCommand (ReadWriteCommand)) { + // 48 Bit LBA + // Write the Upper LBA DWORD and Upper byte of Sector Count + CommandStructure.LBALowExp = (UINT8)Shr64(LBA,24); + CommandStructure.LBAMidExp = (UINT8) Shr64(LBA,32); + CommandStructure.LBAHighExp = (UINT8) Shr64(LBA,40); + CommandStructure.Device = 0x40; // 48Bit LBA + } + else { // 28 Bit LBA + CommandStructure.Device = ((UINT8) ((UINT32) LBA >> 24) & 0x0f) | 0x40; + } + + CommandStructure.SectorCount = (UINT16) CurrentSectorCount; + CommandStructure.LBALow = (UINT8)LBA; + CommandStructure.LBAMid = (UINT8) (((UINT32)LBA >>8) & 0xff); + CommandStructure.LBAHigh = (UINT8) (((UINT32)LBA >>16) & 0xff); + + Status = ExecuteDmaDataCommand (SataDevInterface, &CommandStructure, READWRITE); // Returns # of bytes read + if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR; + + CurrentByteCount = CommandStructure.ByteCount; + CurrentSectorCount = CurrentByteCount / SectorSize; + + TempBuffer += CurrentByteCount; + Total_Number_Of_Sectors -= (CurrentSectorCount == 0 ? MaxSectorCount : CurrentSectorCount); + LBA += (CurrentSectorCount == 0 ? MaxSectorCount : CurrentSectorCount); + + } while (Total_Number_Of_Sectors); + + return EFI_SUCCESS; + +} + + +// +//---------------------------------------------------------------------------- +// +// Procedure: Check48BitCommand +// +// Description: Checks if the command is for 48-bit LBA +// +// Input: +// IN UINT8 Command +// +// Output: +// TRUE/FLASE +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +BOOLEAN +Check48BitCommand ( + IN UINT8 Command + ) +{ + if ( Command == READ_SECTORS_EXT || + Command == READ_MULTIPLE_EXT || + Command == WRITE_SECTORS_EXT || + Command == WRITE_MULTIPLE_EXT || + Command == READ_DMA_EXT || + Command == WRITE_DMA_EXT ) + return TRUE; + else + return FALSE; +} + +// +//---------------------------------------------------------------------------- +// Procedure: ExecuteNonDataCommand +// +// Description: Issue a Non-Data command to the SATA Device +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_STRUCTURE CommandStructure +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: StopController, ReadytoAcceptCmd, StartController, WaitforCommandComplete +// +// Notes: +// 1. Stop the Controller +// 2. Check if the device is ready to accept a Command. +// 3. Build Command list +// 4. Start the Controller. +// 5. Wait till command completes. Check for errors. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ExecuteNonDataCommand ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN COMMAND_STRUCTURE CommandStructure +) +{ + EFI_STATUS Status; + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *)(UINTN) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)(UINTN)AhciBusInterface->PortCommandTableBaseAddr; + + Status = StopController(AhciBusInterface, SataDevInterface,TRUE); + if (EFI_ERROR(Status)) return Status; + + Status = ReadytoAcceptCmd(SataDevInterface); + if (EFI_ERROR(Status)) { + StopController(AhciBusInterface, SataDevInterface,FALSE); + return Status; + } + + BuildCommandList(SataDevInterface, CommandList, AhciBusInterface->PortCommandTableBaseAddr); + BuildCommandFIS(SataDevInterface, CommandStructure, CommandList, Commandtable); + + // Data-in + CommandList->Ahci_Cmd_W = 0; + + // Update of Command Register + Commandtable->CFis.Ahci_CFis_C = 1; + + StartController(AhciBusInterface, SataDevInterface, BIT00); + + Status = WaitforCommandComplete(SataDevInterface, NON_DATA_CMD, ATAPI_BUSY_CLEAR_TIMEOUT ); + + // Stop Controller + StopController(AhciBusInterface, SataDevInterface,FALSE); + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: ExecutePioDataCommand +// +// Description: Ececute PIO Data In/Out command +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN OUT COMMAND_STRUCTURE *CommandStructure +// IN BOOLEAN READWRITE +// +// Output: +// EFI_STATUS, CommandStructure->ByteCount +// +// Modified: +// +// Referrals: StopController, ReadytoAcceptCmd, BuildCommandList, BuildCommandFIS, BuildAtapiCMD +// BuildPRDT, StartController, WaitforCommandComplete +// +// Notes: +// 1. Stop the Controller +// 2. Check if the device is ready to accept a Command. +// 3. Build Command list +// 4. Start the Controller. +// 5. Wait till command completes. Check for errors. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ExecutePioDataCommand ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT COMMAND_STRUCTURE *CommandStructure, + IN BOOLEAN READWRITE +) +{ + EFI_STATUS Status; + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *)(UINTN) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)(UINTN)AhciBusInterface->PortCommandTableBaseAddr; + + + Status = StopController(AhciBusInterface, SataDevInterface,TRUE); + if (EFI_ERROR(Status)) return Status; + + Status = ReadytoAcceptCmd(SataDevInterface); + if (EFI_ERROR(Status)) { + StopController(AhciBusInterface, SataDevInterface,FALSE); + return Status; + } + BuildCommandList(SataDevInterface, CommandList, AhciBusInterface->PortCommandTableBaseAddr); + BuildCommandFIS(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildAtapiCMD(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildPRDT(SataDevInterface, *CommandStructure, CommandList, Commandtable); + + if (READWRITE) { + CommandList->Ahci_Cmd_W = 1; + } + else { + CommandList->Ahci_Cmd_W = 0; + } + Commandtable->CFis.Ahci_CFis_C = 1; + + StartController(AhciBusInterface, SataDevInterface, BIT00); + + // For Security Erase command the time out value comes from Identify Data. + if(CommandStructure->Command == SECURITY_ERASE_UNIT ) { + UINT32 EraseCommandTimeout; + EraseCommandTimeout= (UINT32)(SataDevInterface->IdentifyData.Time_security_Earse_89); + if(EraseCommandTimeout <= 254) { + EraseCommandTimeout=EraseCommandTimeout * 2 * 1000 * 60; //Value * 2Minitues + } else { + EraseCommandTimeout= 0; // No timeout + } + Status = WaitforCommandComplete(SataDevInterface, PIO_DATA_IN_CMD, EraseCommandTimeout); + } else { + Status = WaitforCommandComplete(SataDevInterface, PIO_DATA_IN_CMD, + SataDevInterface->DeviceType == ATA? DMA_ATA_COMMAND_COMPLETE_TIMEOUT \ + : DMA_ATAPI_COMMAND_COMPLETE_TIMEOUT ); + } + + CommandStructure->ByteCount = CommandList->Ahci_Cmd_PRDBC; + + // Stop Controller + StopController(AhciBusInterface, SataDevInterface,FALSE); + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: ExecuteDmaDataCommand +// +// Description: +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_STRUCTURE *CommandStructure +// IN BOOLEAN READWRITE +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: StopController, ReadytoAcceptCmd, BuildCommandList, BuildCommandFIS, BuildAtapiCMD +// BuildPRDT, StartController, WaitforCommandComplete +// +// Notes: +// 1. Stop the Controller +// 2. Check if the device is ready to accept a Command. +// 3. Build Command list +// 4. Start the Controller. +// 5. Wait till command completes. Check for errors. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ExecuteDmaDataCommand ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN COMMAND_STRUCTURE *CommandStructure, + IN BOOLEAN READWRITE +) +{ + + EFI_STATUS Status; + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *)(UINTN) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)(UINTN)AhciBusInterface->PortCommandTableBaseAddr; + + + Status = StopController(AhciBusInterface, SataDevInterface,TRUE); + if (EFI_ERROR(Status)) return Status; + + Status = ReadytoAcceptCmd(SataDevInterface); + if (EFI_ERROR(Status)) { + StopController(AhciBusInterface, SataDevInterface,FALSE); + return Status; + } + BuildCommandList(SataDevInterface, CommandList, AhciBusInterface->PortCommandTableBaseAddr); + BuildCommandFIS(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildAtapiCMD(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildPRDT(SataDevInterface, *CommandStructure, CommandList, Commandtable); + + // Data-in + if (READWRITE) { + CommandList->Ahci_Cmd_W = 1; + } + else { + CommandList->Ahci_Cmd_W = 0 ; + } + Commandtable->CFis.Ahci_CFis_C = 1; + + StartController(AhciBusInterface, SataDevInterface, BIT00); + + Status = WaitforCommandComplete(SataDevInterface, DMA_DATA_IN_CMD, + SataDevInterface->DeviceType == ATA? DMA_ATA_COMMAND_COMPLETE_TIMEOUT \ + : DMA_ATAPI_COMMAND_COMPLETE_TIMEOUT ); + + if (!EFI_ERROR(Status)){ + //Check if the required BYTES have been received + if (CommandList->Ahci_Cmd_PRDBC != CommandStructure->ByteCount){ + Status = EFI_DEVICE_ERROR; + } + } + // Stop Controller + StopController(AhciBusInterface, SataDevInterface,FALSE); + + CommandStructure->ByteCount = CommandList->Ahci_Cmd_PRDBC; + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: ExecutePacketCommand +// +// Description: Execute a Atapi Packet command +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_STRUCTURE *CommandStructure +// IN BOOLEAN READWRITE +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: StopController, ReadytoAcceptCmd, BuildCommandList, BuildCommandFIS, BuildAtapiCMD +// BuildPRDT, StartController, WaitforCommandComplete +// +// Notes: +// 1. Stop the Controller +// 2. Check if the device is ready to accept a Command. +// 3. Build Command list +// 4. Start the Controller. +// 5. Wait till command completes. Check for errors. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ExecutePacketCommand ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN COMMAND_STRUCTURE *CommandStructure, + IN BOOLEAN READWRITE + ) +{ + + EFI_STATUS Status; + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *)(UINTN) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)(UINTN)AhciBusInterface->PortCommandTableBaseAddr; + UINT32 AhciBaseAddr = (UINT32)AhciBusInterface->AhciBaseAddress; + ATAPI_DEVICE *AtapiDevice = SataDevInterface->AtapiDevice; + UINT8 Port = SataDevInterface->PortNumber; + UINT8 Data8; + + CommandStructure->LBAMid = (UINT8)(CommandStructure->ByteCount); + CommandStructure->LBAHigh = (UINT8)(CommandStructure->ByteCount >> 8); + CommandStructure->Command = PACKET_COMMAND; + + Status = StopController(AhciBusInterface, SataDevInterface,TRUE); + if (EFI_ERROR(Status)) return Status; + + Status = ReadytoAcceptCmd(SataDevInterface); + if (EFI_ERROR(Status)) { + StopController(AhciBusInterface, SataDevInterface,FALSE); + return Status; + } + BuildCommandList(SataDevInterface, CommandList, AhciBusInterface->PortCommandTableBaseAddr); + BuildCommandFIS(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildAtapiCMD(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildPRDT(SataDevInterface, *CommandStructure, CommandList, Commandtable); + + if (READWRITE) { + CommandList->Ahci_Cmd_W = 1; + } + else { + CommandList->Ahci_Cmd_W = 0; + } + Commandtable->CFis.Ahci_CFis_C = 1; + + StartController(AhciBusInterface, SataDevInterface, BIT00); + + Status = WaitforCommandComplete(SataDevInterface, PIO_DATA_IN_CMD, + SataDevInterface->DeviceType == ATA? DMA_ATA_COMMAND_COMPLETE_TIMEOUT \ + : DMA_ATAPI_COMMAND_COMPLETE_TIMEOUT ); + + + // Handle ATAPI device error + if (EFI_ERROR(Status) && SataDevInterface->DeviceType == ATAPI) { + Data8 = HBA_PORT_REG8 (AhciBaseAddr, Port, HBA_PORTS_TFD); + if (Data8 & CHK ){ + return HandleAtapiError(SataDevInterface); + + } + } + AtapiDevice->Atapi_Status = EFI_SUCCESS; + + CommandStructure->ByteCount = CommandList->Ahci_Cmd_PRDBC; + + // Stop Controller + StopController(AhciBusInterface, SataDevInterface,FALSE); + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: HandleAtapiError +// +// Description: Check for ATAPI Errors +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ExecutePacketCommand +// +// Notes: +// 1. Execute ATAPI Request Sense command. +// 2. Check for Device getting ready, Media Change, No Media and other errors. Update AtapiDevice->Atapi_Status +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +HandleAtapiError ( + IN SATA_DEVICE_INTERFACE *SataDevInterface + ) +{ + + EFI_STATUS Status; + UINT8 Data8 = 0; + UINT8 SenseData[256]; + COMMAND_STRUCTURE CommandStructure; + ATAPI_DEVICE *AtapiDevice = SataDevInterface->AtapiDevice; + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + UINT32 AhciBaseAddr = (UINT32)AhciBusInterface->AhciBaseAddress; + UINT8 Port = SataDevInterface->PortNumber; + + AtapiDevice->Atapi_Status = DEVICE_ERROR; + + ZeroMemory (SenseData, 256); + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] = ATAPI_REQUEST_SENSE; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[4] = 0xff; + + CommandStructure.ByteCount = 256; + CommandStructure.Buffer = SenseData; + + Status = ExecutePacketCommand(SataDevInterface, &CommandStructure, 0); + + if (EFI_ERROR(Status)) { + Data8 = HBA_PORT_REG8 (AhciBaseAddr, Port, HBA_PORTS_TFD); + } + + SataDevInterface->AtapiSenseDataLength = 0; + + // Check for DF and CHK + if (Data8 & (DF | CHK)) { + goto exit_HandleAtapiError_with_Reset; + } + + if (!EFI_ERROR(Status)){ + // + // Store the SenseData whcih would be used by ScsiPassThruAtapi PassThru Interface. + // + pBS->CopyMem( SataDevInterface->AtapiSenseData, SenseData, 256); + SataDevInterface->AtapiSenseDataLength = CommandStructure.ByteCount; + + AtapiDevice->Atapi_Status = DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; // Default Value + + if (((SenseData[2] & 0xf) == 2) && (SenseData[12] == 0x3a)) { + Status = EFI_NO_MEDIA; + AtapiDevice->Atapi_Status = MEDIUM_NOT_PRESENT; + } + if (((SenseData[2] & 0xf) == 2) && (SenseData[12] == 0x04) && (SenseData[13] == 0x01)) { + Status = EFI_MEDIA_CHANGED; + AtapiDevice->Atapi_Status = BECOMING_READY; + } + + if (((SenseData[2] & 0xf) == 6) && (SenseData[12] == 0x28)){ + Status = EFI_MEDIA_CHANGED; + AtapiDevice->Atapi_Status = MEDIA_CHANGED; + } + + if (((SenseData[2] & 0xf) == 7) && (SenseData[12] == 0x27)){ + Status = EFI_WRITE_PROTECTED; + AtapiDevice->Atapi_Status = WRITE_PROTECTED_MEDIA; + } + + if (((SenseData[2] & 0xf) == 6) && (SenseData[12] == 0x29)){ + AtapiDevice->Atapi_Status = POWER_ON_OR_DEVICE_RESET; + } + + if (((SenseData[2] & 0xf) == 5) && (SenseData[0] == 0x70)){ + AtapiDevice->Atapi_Status = ILLEGAL_REQUEST; + } + } + +exit_HandleAtapiError_with_Reset: + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: ReadWritePMPort +// +// Description: Read/Write routine to PM ports +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT8 Port, +// IN UINT8 RegNum, +// IN OUT UINT32 *Data +// IN BOOLEAN READWRITE // TRUE for Write +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: StopController, ReadytoAcceptCmd, BuildCommandList, BuildCommandFIS, BuildAtapiCMD +// BuildPRDT, StartController, WaitforCommandComplete +// +// Notes: +// 1. Update Command Structure for READ/Write Port Multiplier command +// 2. Issue command +// 3. Check for errors. +// 4. Read the out data in case of READ. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ReadWritePMPort ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN UINT8 Port, + IN UINT8 RegNum, + IN OUT UINT32 *Data, + IN BOOLEAN READWRITE +) +{ + EFI_STATUS Status; + COMMAND_STRUCTURE CommandStructure; + AHCI_RECEIVED_FIS *PortFISBaseAddr = (AHCI_RECEIVED_FIS *)(UINTN)(SataDevInterface->PortFISBaseAddr); + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *)(UINTN) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)(UINTN)AhciBusInterface->PortCommandTableBaseAddr; + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + + CommandStructure.Command = READ_PORT_MULTIPLIER; + + if (READWRITE) { + CommandStructure.SectorCount = (UINT16) (*Data & 0xFF); + CommandStructure.LBALow = (UINT8) (*Data >> 8); + CommandStructure.LBAMid = (UINT8)(*Data >> 16); + CommandStructure.LBAHigh = (UINT8)(*Data >> 24); + CommandStructure.Command = WRITE_PORT_MULTIPLIER; + } + + CommandStructure.Device = Port; + CommandStructure.Features = RegNum; + + Status = StopController(AhciBusInterface, SataDevInterface,TRUE); + if (EFI_ERROR(Status)) return Status; + + Status = ReadytoAcceptCmd(SataDevInterface); + if (EFI_ERROR(Status)) { + StopController(AhciBusInterface, SataDevInterface,FALSE); + return Status; + } + + BuildCommandList(SataDevInterface, CommandList, AhciBusInterface->PortCommandTableBaseAddr); + BuildCommandFIS(SataDevInterface, CommandStructure, CommandList, Commandtable); + + // Data-in + CommandList->Ahci_Cmd_W = 0; + + // Update of Command Register + Commandtable->CFis.Ahci_CFis_C = 1; + + // Update the Port Address + CommandList->Ahci_Cmd_PMP = CONTROL_PORT; + Commandtable->CFis.AHci_CFis_PmPort = CONTROL_PORT; + + StartController(AhciBusInterface, SataDevInterface, BIT00); + + Status = WaitforCommandComplete(SataDevInterface, NON_DATA_CMD, TIMEOUT_1SEC); + + // Stop Controller + StopController(AhciBusInterface, SataDevInterface,FALSE); + + if (!READWRITE) { + *Data = 0; + if (!EFI_ERROR(Status)) { + *Data = PortFISBaseAddr->Ahci_Rfis[12] | + (PortFISBaseAddr->Ahci_Rfis[4] << 8) | + (PortFISBaseAddr->Ahci_Rfis[5] << 16) | + (PortFISBaseAddr->Ahci_Rfis[6] << 24); + } + } + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: GetIdentifyData +// +// Description: Reaturn Identify data from SATA device +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// +// Output: +// gIdentifyDataBuffer +// EFI_STATUS +// Modified: +// +// Referrals: +// +// Notes: +// 1. Build CommandStructure. +// 2. Issue ExecutePioDataCommand +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +GetIdentifyData ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +) +{ + EFI_STATUS Status; + COMMAND_STRUCTURE CommandStructure; + IDENTIFY_DATA tIdentifyData; + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + + // Read Identifydata + CommandStructure.Buffer = &tIdentifyData; + CommandStructure.ByteCount = sizeof(IDENTIFY_DATA); + CommandStructure.Device = 0; + CommandStructure.Command = SataDevInterface->DeviceType == ATA ? IDENTIFY_COMMAND : IDENTIFY_PACKET_COMMAND; + + Status = ExecutePioDataCommand (SataDevInterface, &CommandStructure, FALSE); + + if (CommandStructure.ByteCount != sizeof(IDENTIFY_DATA)) { Status = EFI_DEVICE_ERROR; } + + if(!EFI_ERROR(Status)) + pBS->CopyMem(&(SataDevInterface->IdentifyData), &tIdentifyData, sizeof(IDENTIFY_DATA)); + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: SataAtapiInquiryData +// +// Description: Return ATAPI Inquiry data +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// OUT UINT8 *InquiryData, +// IN OUT UINT16 *InquiryDataSize +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ExecutePioDataCommand +// +// Notes: +// 1. Update CommandStructure +// 2. Issue ExecutePioDataCommand +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +SataAtapiInquiryData ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + OUT UINT8 *InquiryData, + IN OUT UINT16 *InquiryDataSize +) +{ + + EFI_STATUS Status; + COMMAND_STRUCTURE CommandStructure; + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Buffer = InquiryData; + CommandStructure.ByteCount = *InquiryDataSize; + CommandStructure.Command = PACKET_COMMAND; + CommandStructure.LBAMid = (UINT8)*InquiryDataSize; + CommandStructure.LBAHigh = (UINT8)(*InquiryDataSize >> 8); + + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0]=ATAPI_INQUIRY; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[4]=(UINT8)*InquiryDataSize; + + Status = ExecutePioDataCommand (SataDevInterface, &CommandStructure, 0); + + if (!EFI_ERROR(Status)) { + *InquiryDataSize = (UINT16)CommandStructure.ByteCount; + } + + return Status; +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: DetectAtapiMedia +// +// Description: Detects whether a Media is present in the ATAPI Removable device or not. +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: TestUnitReady, ExecutePacketCommand +// +// Notes: +// 1. Issue Read Capacity command for CDROM or Read Format command for other ATAPI devices. +// 2. If step 1 is successfull, update last LBA, Block Size, Read/Write capable, Media ID +// +//--------------------------------------------------------------------------- +// +EFI_STATUS +DetectAtapiMedia( + IN SATA_DEVICE_INTERFACE *SataDevInterface + ) +{ + UINT8 *InputData, LoopCount; + ATAPI_DEVICE *AtapiDevice = SataDevInterface->AtapiDevice; + EFI_BLOCK_IO_MEDIA *BlkMedia = SataDevInterface->SataBlkIo->BlkIo.Media; + EFI_STATUS Status = EFI_NOT_FOUND; + UINT16 ByteCount = 256, Data16; + COMMAND_STRUCTURE CommandStructure; + BOOLEAN ReadCapacity=FALSE; + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + +// Default Values + BlkMedia->MediaPresent = FALSE; + BlkMedia->LastBlock = 0x100; // Dummy value + SataDevInterface->ReadCommand = ATAPI_READ_10; + SataDevInterface->WriteCommand = ATAPI_WRITE_10; + + Status = TestUnitReady(SataDevInterface); + if ((Status != EFI_MEDIA_CHANGED) && (Status != EFI_SUCCESS)) { + return Status; + } + +// Issue Read Capacity command + Status = pBS->AllocatePool (EfiBootServicesData, ByteCount, (VOID**)&InputData); + if (EFI_ERROR(Status)) return Status; + +// For CDROM use Read Capacity command else use Read Format Command + if (AtapiDevice->DeviceType == CDROM_DEVICE){ + BlkMedia->BlockSize = CDROM_BLOCK_SIZE; // Default size + AtapiDevice->BlockSize = (UINT16)(BlkMedia->BlockSize); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] = ATAPI_READ_CAPACITY; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[1] = AtapiDevice->Lun << 5; + Data16 = 8; + } + else { + BlkMedia->BlockSize = LS120_BLOCK_SIZE; // Default Size + AtapiDevice->BlockSize = (UINT16)(BlkMedia->BlockSize); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] = ATAPI_READ_FORMAT_CAPACITIES; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[1] = AtapiDevice->Lun << 5; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[7] = (UINT8)(ByteCount >> 8); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[8] = (UINT8)(ByteCount & 0xff); + Data16 = ByteCount; + } + + for (LoopCount = 0; LoopCount < 5; LoopCount++) { // 5sec loop + ByteCount = Data16; + ZeroMemory (InputData, ByteCount); + CommandStructure.Buffer = InputData; + CommandStructure.ByteCount = ByteCount; + Status = ExecutePacketCommand(SataDevInterface, &CommandStructure, 0); + if(CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] == ATAPI_READ_FORMAT_CAPACITIES && + AtapiDevice->Atapi_Status == ILLEGAL_REQUEST) { + // + //If the Read Format Capacities not supported by device, try + //ReadCapacity command + // + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + BlkMedia->BlockSize = CDROM_BLOCK_SIZE; // Default size + AtapiDevice->BlockSize = (UINT16)(BlkMedia->BlockSize); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] = ATAPI_READ_CAPACITY; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[1] = AtapiDevice->Lun << 5; + Data16 = 8; + ReadCapacity=TRUE; + } + if (AtapiDevice->Atapi_Status == EFI_SUCCESS) break; + if (AtapiDevice->Atapi_Status == MEDIUM_NOT_PRESENT) break; + } + + if (Status == EFI_SUCCESS) { + if(ReadCapacity == TRUE) { + BlkMedia->LastBlock = InputData[0] << 24 | InputData[1] << 16 | InputData[2] << 8 | InputData[3]; + BlkMedia->LastBlock--; + BlkMedia->MediaPresent = TRUE; + BlkMedia->MediaId ++; + BlkMedia->BlockSize = InputData[4] << 24 | InputData[5] << 16 | InputData[6] << 8 | InputData[7]; + AtapiDevice->BlockSize = BlkMedia->BlockSize; + BlkMedia->ReadOnly = FALSE; + } else if (AtapiDevice->DeviceType == CDROM_DEVICE) { + BlkMedia->LastBlock = InputData[0] << 24 | InputData[1] << 16 | InputData[2] << 8 | InputData[3]; + BlkMedia->LastBlock--; + BlkMedia->BlockSize = CDROM_BLOCK_SIZE; + AtapiDevice->BlockSize = (UINT16)(BlkMedia->BlockSize); + BlkMedia->MediaPresent = TRUE; + BlkMedia->MediaId ++; + BlkMedia->ReadOnly = TRUE; + } else if (InputData[8] != 3) { // No media present + BlkMedia->LastBlock = InputData[4] << 24 | InputData[5] << 16 | InputData[6] << 8 | InputData[7]; + BlkMedia->LastBlock--; + BlkMedia->MediaPresent = TRUE; + BlkMedia->MediaId ++; + BlkMedia->BlockSize = InputData[9] << 16 | InputData[10] << 8 | InputData[11]; + BlkMedia->ReadOnly = FALSE; + AtapiDevice->BlockSize = (UINT16)(BlkMedia->BlockSize); + } + +// Update ReadOnly Status + if (AtapiDevice->DeviceType != CDROM_DEVICE) { + ByteCount = 256; + ZeroMemory (InputData, ByteCount); + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] = ATAPI_MODE_SENSE; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[2] = RETURN_ALL_PAGES; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[7] = (UINT8)(ByteCount >> 8); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[8] = (UINT8)(ByteCount & 0xff); + CommandStructure.Buffer = InputData; + CommandStructure.ByteCount= ByteCount; + Status = ExecutePacketCommand(SataDevInterface, &CommandStructure, 0); + if ((Status == EFI_SUCCESS) && (ByteCount > 8)) { + BlkMedia->ReadOnly = (InputData[3] & 0x80) != 0 ? TRUE : FALSE; + } + } + } + + pBS->FreePool(InputData); + return Status; + +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: SataCheckOddType +// +// Description: Return ODD type +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ExecutePioDataCommand +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +SataGetOddType ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT UINT16 *OddType +) + +{ + + EFI_STATUS Status; + COMMAND_STRUCTURE CommandStructure; + UINT8 *ProfileData; + + Status = pBS->AllocatePool (EfiBootServicesData,16,(VOID**)&ProfileData); + + if (EFI_ERROR(Status)) { + return Status; + } + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Buffer = ProfileData; + CommandStructure.ByteCount = 16; + CommandStructure.Command = PACKET_COMMAND; + CommandStructure.LBAMid = 16; + CommandStructure.LBAHigh = 0; + + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0]= ATAPI_GET_CONFIGURATION; + // + // Get the Feature Discriptor. + // + CommandStructure.AtapiCmd.Ahci_Atapi_Command[1] = FEATURE_DISCRIPTOR; + // + // Get the Profile list + // + CommandStructure.AtapiCmd.Ahci_Atapi_Command[3] = GET_PROFILE_LIST; + // + // Responce Data Size + // + CommandStructure.AtapiCmd.Ahci_Atapi_Command[8] = 0x10; + + Status = ExecutePioDataCommand (SataDevInterface, &CommandStructure, 0); + + if (!EFI_ERROR(Status)) { + // + // Get the Profile Number + // + *OddType=(UINT16 )(((ProfileData[sizeof(GET_CONFIGURATION_HEADER)+4]) << 8) + ProfileData[sizeof(GET_CONFIGURATION_HEADER)+5]); + } + + pBS->FreePool(ProfileData); + return Status; +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: SataGetOddLoadingType +// +// Description: Return ODD Loading type information +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ExecutePioDataCommand +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +SataGetOddLoadingType ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN OUT UINT8 *OddLoadingType +) + +{ + + EFI_STATUS Status; + COMMAND_STRUCTURE CommandStructure; + UINT8 *ProfileData; + + Status = pBS->AllocatePool (EfiBootServicesData,16,(VOID**)&ProfileData); + + if (EFI_ERROR(Status)) { + return Status; + } + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.Buffer = ProfileData; + CommandStructure.ByteCount = 16; + CommandStructure.Command = PACKET_COMMAND; + CommandStructure.LBAMid = 16; + CommandStructure.LBAHigh = 0; + + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0]= ATAPI_GET_CONFIGURATION; + // + // Get the Feature Discriptor. + // + CommandStructure.AtapiCmd.Ahci_Atapi_Command[1] = FEATURE_DISCRIPTOR; + // + // Get the Removable Medium feature + // + CommandStructure.AtapiCmd.Ahci_Atapi_Command[3] = GET_REMOVEABLE_MEDIUM_FEATURE; + // + // Responce Data Size + // + CommandStructure.AtapiCmd.Ahci_Atapi_Command[8] = 0x10; + + Status = ExecutePioDataCommand (SataDevInterface, &CommandStructure, 0); + + if (!EFI_ERROR(Status)) { + // + // Get the ODD Loading Type + // + *OddLoadingType=(UINT8 )(((ProfileData[sizeof(GET_CONFIGURATION_HEADER)+4]) & 0xE0) >> 5); + } + + pBS->FreePool(ProfileData); + return Status; +} + +// +//--------------------------------------------------------------------------- +// +// Procedure: TestUnitReady +// +// Description: Issues Start/Stop unit Command +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// EFI_STATUS EFI_SUCCESS : If Media is accessible +// EFI_NO_MEDIA +// EFI_MEDIA_CHANGED +// EFI_DEVICE_ERROR +// +// Modified: +// +// Referrals: ExecutePacketCommand +// +// Notes: +// 1. Update CommandStructure for ATAPI_TEST_UNIT_READY command +// 2. Issue ExecutePacketCommand +// 3. Check if the device is ready to accept command, whether Media is present or not. +// +//--------------------------------------------------------------------------- +// +EFI_STATUS +TestUnitReady( + IN SATA_DEVICE_INTERFACE *SataDevInterface + ) +{ + + EFI_STATUS Status = EFI_SUCCESS; + ATAPI_DEVICE *AtapiDevice = SataDevInterface->AtapiDevice; + UINT16 LoopCount; + COMMAND_STRUCTURE CommandStructure; + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] = ATAPI_TEST_UNIT_READY; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[1] = AtapiDevice->Lun << 5; + CommandStructure.Buffer = NULL; + CommandStructure.ByteCount = 0x100; + + for (LoopCount = 0; LoopCount < 1000; LoopCount++) { // 10sec loop ( 1000 * 10 msec = 10Sec) + Status = ExecutePacketCommand(SataDevInterface, &CommandStructure, 0); + if (Status == EFI_SUCCESS) break; + if (AtapiDevice->Atapi_Status == MEDIUM_NOT_PRESENT) break; + if (AtapiDevice->Atapi_Status == MEDIA_CHANGED) break; + pBS->Stall(10000); // 10msec + } + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: BuildCommandList +// +// Description: Builds command list +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN AHCI_COMMAND_LIST *CommandList, +// IN UINT32 CommandTableBaseAddr +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Update CommandList bits +// 2. Not all fields like Ahci_Cmd_A are updated. +// 3. Port number is set to 0xF (Control port) if PM Port number is 0xFF. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +BuildCommandList ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN AHCI_COMMAND_LIST *CommandList, + IN UINT32 CommandTableBaseAddr +) +{ + + + ZeroMemory (CommandList, sizeof(AHCI_COMMAND_LIST)); + // CommandList->Ahci_Cmd_A = SataDevInterface->DeviceType == ATAPI ? 1 : 0; // set elsewhere + CommandList->Ahci_Cmd_P = 0; + CommandList->Ahci_Cmd_R = 0; + CommandList->Ahci_Cmd_B = 0; + CommandList->Ahci_Cmd_Rsvd1 = 0; + CommandList->Ahci_Cmd_PMP = SataDevInterface->PMPortNumber == 0xFF ? 0x0 : SataDevInterface->PMPortNumber; + CommandList->Ahci_Cmd_PRDTL = 0; + CommandList->Ahci_Cmd_PRDBC = 0; + CommandList->Ahci_Cmd_CTBA = CommandTableBaseAddr; + CommandList->Ahci_Cmd_CTBAU = 0; + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: BuildCommandFIS +// +// Description: Build Command FIS +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_STRUCTURE CommandStructure, +// IN AHCI_COMMAND_LIST *CommandList, +// IN AHCI_COMMAND_TABLE *Commandtable +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Update Command FIS data area. +// 2. Update the Command FIS lenght in Command List table +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +BuildCommandFIS ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN COMMAND_STRUCTURE CommandStructure, + IN AHCI_COMMAND_LIST *CommandList, + IN AHCI_COMMAND_TABLE *Commandtable +) +{ + + + ZeroMemory (Commandtable, sizeof(AHCI_COMMAND_TABLE)); + + Commandtable->CFis.Ahci_CFis_Type = FIS_REGISTER_H2D; + Commandtable->CFis.AHci_CFis_PmPort = SataDevInterface->PMPortNumber == 0xFF ? 0x0 : SataDevInterface->PMPortNumber; +// Commandtable->CFis.Ahci_CFis_C = 1; // Set elsewhere + Commandtable->CFis.Ahci_CFis_Cmd = CommandStructure.Command; + + Commandtable->CFis.Ahci_CFis_Features = CommandStructure.Features; + Commandtable->CFis.Ahci_CFis_FeaturesExp = CommandStructure.FeaturesExp; + + Commandtable->CFis.Ahci_CFis_SecNum = CommandStructure.LBALow; + Commandtable->CFis.Ahci_CFis_SecNumExp = CommandStructure.LBALowExp; + + Commandtable->CFis.Ahci_CFis_ClyLow = CommandStructure.LBAMid; + Commandtable->CFis.Ahci_CFis_ClyLowExp = CommandStructure.LBAMidExp; + + Commandtable->CFis.Ahci_CFis_ClyHigh = CommandStructure.LBAHigh; + Commandtable->CFis.Ahci_CFis_ClyHighExp = CommandStructure.LBAHighExp; + + Commandtable->CFis.Ahci_CFis_SecCount = (UINT8)(CommandStructure.SectorCount); + Commandtable->CFis.Ahci_CFis_SecCountExp = (UINT8)(CommandStructure.SectorCount >> 8); + + Commandtable->CFis.Ahci_CFis_DevHead = CommandStructure.Device; + Commandtable->CFis.Ahci_CFis_Control = CommandStructure.Control; + + CommandList->Ahci_Cmd_CFL = FIS_REGISTER_H2D_LENGTH / 4; + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: BuildAtapiCMD +// +// Description: +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_STRUCTURE CommandStructure +// IN AHCI_COMMAND_LIST *CommandList, +// IN AHCI_COMMAND_TABLE *Commandtable +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Copy Packet data to command table +// 2. Set Atapi bit in Command List +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +BuildAtapiCMD( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN COMMAND_STRUCTURE CommandStructure, + IN AHCI_COMMAND_LIST *CommandList, + IN AHCI_COMMAND_TABLE *Commandtable +) +{ + + + pBS->CopyMem(&(Commandtable->AtapiCmd),&(CommandStructure.AtapiCmd),sizeof(AHCI_ATAPI_COMMAND)); + + if (Commandtable->CFis.Ahci_CFis_Cmd == PACKET_COMMAND){ // Is it a packet command? + CommandList->Ahci_Cmd_A = 1; + } + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: BuildPRDT +// +// Description: Build PRDT table +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_STRUCTURE CommandStructure +// IN AHCI_COMMAND_LIST *CommandList, +// IN AHCI_COMMAND_TABLE *Commandtable +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Build as many PRDT table entries based on ByteCount. +// 2. Set the I flag for the lasr PRDT table. +// 3. Update PRDT table lenght in CommandList +// +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +BuildPRDT ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN COMMAND_STRUCTURE CommandStructure, + IN AHCI_COMMAND_LIST *CommandList, + IN AHCI_COMMAND_TABLE *Commandtable +) +{ + + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + UINT32 ByteCount = CommandStructure.ByteCount; + UINT16 Prdtlength = 0; + AHCI_COMMAND_PRDT *PrdtTable = &(Commandtable->PrdtTable); + + for (;ByteCount; (UINT8 *)PrdtTable += sizeof(AHCI_COMMAND_PRDT)){ + PrdtTable->Ahci_Prdt_DBA = (UINT32)(UINTN)CommandStructure.Buffer; + PrdtTable->Ahci_Prdt_DBAU = (UINT32)Shr64((UINTN)CommandStructure.Buffer, 32); + PrdtTable->Ahci_Prdt_DBC = ByteCount >= PRD_MAX_DATA_COUNT ? (PRD_MAX_DATA_COUNT - 1) : (ByteCount - 1); + ByteCount -= (PrdtTable->Ahci_Prdt_DBC + 1); + PrdtTable->Ahci_Prdt_I = 0; + Prdtlength+= sizeof(AHCI_COMMAND_PRDT); + if ((UINT32)(Prdtlength + 0x80) >= AhciBusInterface->PortCommandTableLength) { + //ASSERT_EFI_ERROR(EFI_OUT_OF_RESOURCES); + break; + } + (UINT8 *)CommandStructure.Buffer += PrdtTable->Ahci_Prdt_DBC + 1; + } + // Set I flag only for the last entry. + (UINT8 *)PrdtTable -= sizeof(AHCI_COMMAND_PRDT); + PrdtTable->Ahci_Prdt_I = 1; + CommandList->Ahci_Cmd_PRDTL = Prdtlength / sizeof(AHCI_COMMAND_PRDT); + + return EFI_SUCCESS; + +} + + +// +//---------------------------------------------------------------------------- +// Procedure: StartController +// +// Description: +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT32 CIBitMask +// +// Output: +// EFI_STATUS +// Modified: +// +// Referrals: +// +// Notes: +// 1. Clear Status register +// 2. Enable FIS and CR running bit +// 3. Enable Start bit +// 4. Update CI bit mask +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +StartController ( + IN AHCI_BUS_PROTOCOL *AhciBusInterface, + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN UINT32 CIBitMask +) +{ + + UINT32 AhciBaseAddr = (UINT32)(AhciBusInterface->AhciBaseAddress); + UINT8 Port = SataDevInterface->PortNumber; + + // Clear Status + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + // Enable FIS Receive + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_FRE); + + // Wait till FIS is running + WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + // Clear FIS Receive area + ZeroMemory ((VOID *)(UINTN)SataDevInterface->PortFISBaseAddr, RECEIVED_FIS_SIZE); + + // Enable ST + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_ST); + + // Enable Command Issued + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CI, CIBitMask); + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: WaitforCommandComplete +// +// Description: Wait till cmd completes +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_TYPE CommandType, +// IN UINTN TimeOut +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Check for SError bits. If set return error. +// 2. For PIO IN/Out and Packet IN/OUT command wait till PIO Setup FIS is received +// 3. If D2H register FIS is received, exit the loop. +// 4. Check for SError and TFD bits. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +WaitforCommandComplete ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN COMMAND_TYPE CommandType, + IN UINTN TimeOut +) +{ + + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + UINT32 AhciBaseAddr = (UINT32)AhciBusInterface->AhciBaseAddress; + UINT8 Port = SataDevInterface->PortNumber; + UINT32 Data32_SERR, Data32_IS, i; + BOOLEAN PxSERR_ERROR = FALSE, PIO_SETUP_FIS = FALSE; + volatile AHCI_RECEIVED_FIS *FISReceiveAddress = (AHCI_RECEIVED_FIS *)(UINTN)SataDevInterface->PortFISBaseAddr; + UINTN TimeOutCount = TimeOut; + + i=0; + do { + pBS->Stall(500); + + // Check for Error bits + Data32_SERR = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_SERR); + if (Data32_SERR & HBA_PORTS_ERR_CHK) { + PxSERR_ERROR = TRUE; + break; + } + + // Check for Error bits + Data32_IS = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_IS); + if (Data32_IS & HBA_PORTS_IS_ERR_CHK) { + PxSERR_ERROR = TRUE; + break; + } + + switch (CommandType) { + + case PIO_DATA_IN_CMD: + case PIO_DATA_OUT_CMD: + case PACKET_PIO_DATA_IN_CMD: + case PACKET_PIO_DATA_OUT_CMD: + // check if PIO setup received + if(FISReceiveAddress->Ahci_Psfis[0] == FIS_PIO_SETUP) { + FISReceiveAddress->Ahci_Psfis[0] = 0; + TimeOutCount = TimeOut; + PIO_SETUP_FIS = TRUE; + } + break; + default: + break; + + } + + // check if D2H register FIS is received + if(FISReceiveAddress->Ahci_Rfis[0] == FIS_REGISTER_D2H) break; + + // For PIO Data in D2H register FIS is not received. So rely on BSY bit + if ((CommandType == PIO_DATA_IN_CMD) && PIO_SETUP_FIS && + !((HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_TFD) & + (HBA_PORTS_TFD_BSY | HBA_PORTS_TFD_DRQ)))){ + break; + } + //If the Timeout is 0, Then there is no timeout for command processing + if(TimeOut==0) { + continue; + } + i++; + } while(i < TimeOutCount * 2); + + if (PxSERR_ERROR) { + // clear the status and return error + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + return EFI_DEVICE_ERROR; + } + + // check if CI register is zero + if (HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_CI)){ + return EFI_DEVICE_ERROR; + } + + // check for status bits + if (HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_TFD) & (HBA_PORTS_TFD_ERR | HBA_PORTS_TFD_DRQ)){ + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: StopController +// +// Description: Stop FIS and CR +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: GeneratePortReset +// +// Notes: +// 1. clear ST bit and wait till CR bits gets reset +// 2. if not generate Port reset +// 3. Clear FIS running bit. +// 4. Clear status register +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +StopController( + IN AHCI_BUS_PROTOCOL *AhciBusInterface, + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN BOOLEAN StartOrStop +) +{ + + UINT8 Port = SataDevInterface->PortNumber; + UINT8 PMPort = SataDevInterface->PMPortNumber; + UINT32 AhciBaseAddr = (UINT32)(AhciBusInterface->AhciBaseAddress); + EFI_STATUS Status; + UINT32 PortFISBaseAddr = SataDevInterface->PortFISBaseAddr; + UINT32 CommandListBaseAddress = SataDevInterface->PortCommandListBaseAddr; + UINT32 Data32; + + if(StartOrStop && (HBA_PORT_REG32(AhciBaseAddr,Port,HBA_PORTS_CLB) != CommandListBaseAddress)) { + gCommandListBaseAddress=HBA_PORT_REG32(AhciBaseAddr,Port,HBA_PORTS_CLB); + gFisBaseAddress=HBA_PORT_REG32(AhciBaseAddr,Port,HBA_PORTS_FB); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_CLB,CommandListBaseAddress); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FB,PortFISBaseAddr); + + // + // Saving the Upper 32 bits of FIS and Command List Registers + // + gCommandListBaseAddress2=HBA_PORT_REG32(AhciBaseAddr,Port,HBA_PORTS_CLBU); + gFisBaseAddress2=HBA_PORT_REG32(AhciBaseAddr,Port,HBA_PORTS_FBU); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_CLBU,0); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FBU,0); + } + + // Clear Start + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_CMD, ~(HBA_PORTS_CMD_ST)); + // Make sure CR is 0 with in 500msec + Status = WaitForMemClear(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_CR, + HBA_CR_CLEAR_TIMEOUT); + + if (EFI_ERROR(Status)) { + + // Get the Port Speed allowed and Interface Power Management Transitions Allowed + // Pass the values for PortReset. + Data32 = HBA_PORT_REG32 ((UINT32)(AhciBusInterface->AhciBaseAddress), Port, HBA_PORTS_SCTL); + Data32 &= 0xFF0; + + Status = GeneratePortReset(AhciBusInterface, SataDevInterface, Port, PMPort, + (UINT8)((Data32 & 0xF0) >> 4), (UINT8)(Data32 >> 8)); + }; + + if (EFI_ERROR(Status)) { + goto StopController_ErrorExit; + } + + // Clear FIS receive enable. + HBA_PORT_REG32_AND (AhciBaseAddr, Port, + HBA_PORTS_CMD, ~(HBA_PORTS_CMD_FRE)); + // Make sure FR is 0 with in 500msec + Status = WaitForMemClear(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + +StopController_ErrorExit: + + // Clear Status register + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + if(!StartOrStop && gCommandListBaseAddress) { + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_CLB,gCommandListBaseAddress); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FB,gFisBaseAddress); + // + // Restoring the Upper 32 bits of FIS and Command List Registers + // + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_CLBU,gCommandListBaseAddress2); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FBU,gFisBaseAddress2); + + gCommandListBaseAddress = 0; + } + + return Status; +} + +// +//---------------------------------------------------------------------------- +// Procedure: ReadytoAcceptCmd +// +// Description: Check if the device is ready to accept cmd. +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: GeneratePortReset, ReadWritePMPort +// +// Notes: +// 1. Check the device is ready to accept the command. BSY and DRQ should be de-asserted. +// 2. If set, generate Port reset +// 3. In case Port Multiplier is connected to the port, enable all the ports of the Port Multiplier. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ReadytoAcceptCmd ( + IN SATA_DEVICE_INTERFACE *SataDevInterface +) +{ + + EFI_STATUS Status = EFI_SUCCESS; + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + UINT32 AhciBaseAddr = (UINT32)(AhciBusInterface->AhciBaseAddress); + UINT8 Port = SataDevInterface->PortNumber; + UINT8 PMPort = SataDevInterface->PMPortNumber; + SATA_DEVICE_INTERFACE *SataPMDevInterface, *SataPMPortDevInterface; + UINT32 Data32 = 0, Init_SStatus = 0; + UINT8 PowerManagement, Speed; + + // Is the Device ready to accept the command + if (HBA_PORT_REG8 (AhciBaseAddr, Port, HBA_PORTS_TFD) & (HBA_PORTS_TFD_BSY | HBA_PORTS_TFD_DRQ)){ + Data32 = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_SCTL); + Data32 &= 0xFF0; + // make sure the status we read is for the right port + Status = GeneratePortReset(AhciBusInterface, SataDevInterface, Port, 0xFF, + (UINT8)((Data32 & 0xF0) >> 4), (UINT8)(Data32 >> 8)); + if (EFI_ERROR(Status)) return Status; + + // If it is a PMPort, Make sure all the Ports are in enabled state. + SataPMDevInterface = GetSataDevInterface(AhciBusInterface, Port, 0xFF); + if (!SataPMDevInterface) { + return EFI_DEVICE_ERROR; + } + if (SataPMDevInterface->DeviceType == PMPORT) { + for (PMPort = 0; PMPort < SataPMDevInterface->NumPMPorts; PMPort++){ + SataPMPortDevInterface = GetSataDevInterface(AhciBusInterface, Port, PMPort); + if (!SataPMPortDevInterface) continue; + ReadWritePMPort (SataDevInterface, PMPort, PSCR_0_SSTATUS, &Init_SStatus, FALSE); + if ((Init_SStatus & HBA_PORTS_SSTS_DET_MASK) == HBA_PORTS_SSTS_DET_PCE) { + Data32 = SataPMPortDevInterface->SControl; + ReadWritePMPort (SataDevInterface, PMPort, PSCR_2_SCONTROL, &Data32, TRUE); + } + else { + Speed = (UINT8)((SataDevInterface->SControl >> 4) & 0xF); + PowerManagement = (UINT8)((SataDevInterface->SControl >> 8) & 0xF); + GeneratePortReset(AhciBusInterface, SataDevInterface, Port, PMPort, + Speed, PowerManagement); + } + Data32 = HBA_PORTS_ERR_CLEAR; + ReadWritePMPort (SataDevInterface, PMPort, PSCR_1_SERROR, &Data32, TRUE); + } + } + } + return Status; +} + +// +//---------------------------------------------------------------------------- +// Procedure: HostReset +// +// Description: +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// +// Output: +// +// Modified: +// +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +HostReset ( + IN AHCI_BUS_PROTOCOL *AhciBusInterface +) +{ + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: GeneratePortReset +// +// Description: Issue a Port Reset +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT8 CurrentPort, +// IN UINT8 Speed, +// IN UINT8 PowerManagement +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ReadWritePMPort, HandlePortComReset +// +// Notes: +// 1. Issue port reset by setting DET bit in SControl register +// 2. Call HandlePortComReset to check the status of the reset. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +GeneratePortReset ( + AHCI_BUS_PROTOCOL *AhciBusInterface, + SATA_DEVICE_INTERFACE *SataDevInterface, + UINT8 Port, + UINT8 PMPort, + UINT8 Speed, + UINT8 PowerManagement +) +{ + + EFI_STATUS Status; + UINT32 AhciBaseAddr = (UINT32) AhciBusInterface->AhciBaseAddress; + volatile AHCI_RECEIVED_FIS *FISAddress = (AHCI_RECEIVED_FIS *)HBA_PORT_REG32(AhciBaseAddr, Port, HBA_PORTS_FB); + UINT32 Data32; + + TRACE_AHCI_LEVEL2((-1,"AHCI: PortReset on Port : %x PMPort : %x", Port, PMPort)); + + if (!FISAddress) return EFI_DEVICE_ERROR; // FIS receive address is not programmed. + + if (gPortReset) return EFI_SUCCESS; + gPortReset = TRUE; + + // Disable Start bit + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_CMD, ~HBA_PORTS_CMD_ST); + + // Wait till CR is cleared + Status = WaitForMemClear(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_CR, + HBA_CR_CLEAR_TIMEOUT); + + // Clear Status register + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); + if (PMPort != 0xFF) { + Data32 = HBA_PORTS_ERR_CLEAR; + ReadWritePMPort (SataDevInterface, PMPort, PSCR_1_SERROR, &Data32, TRUE); + } + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + // Enable FIS Receive Enable + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_FRE); + + // Wait till FIS is running and then clear the data area + WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + + FISAddress->Ahci_Rfis[0] = 0; + + if (PMPort == 0xFF) { + // Issue Port COMRESET + HBA_PORT_REG32_AND_OR (AhciBaseAddr, Port, HBA_PORTS_SCTL, 0xFFFFF000, + HBA_PORTS_SCTL_DET_INIT + (Speed << 4) + (PowerManagement << 8)); + pBS->Stall (1000); // 1msec + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_SCTL, ~HBA_PORTS_SCTL_DET_MASK); + } + else { + Data32 = HBA_PORTS_SCTL_DET_INIT + (Speed << 4) + (PowerManagement << 8); + ReadWritePMPort (SataDevInterface, PMPort, PSCR_2_SCONTROL, &Data32, TRUE); + pBS->Stall (1000); // 1msec + Data32 = (Speed << 4) + (PowerManagement << 8); + ReadWritePMPort (SataDevInterface, PMPort, PSCR_2_SCONTROL, &Data32, TRUE); + } + + Status = HandlePortComReset(AhciBusInterface, SataDevInterface, Port, PMPort); + + // Disable FIS Receive Enable + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_CMD, ~HBA_PORTS_CMD_FRE); + + SataDevInterface->SControl = (Speed << 4) + (PowerManagement << 8); + + gPortReset = FALSE; + + if (EFI_ERROR(Status)) { + TRACE_AHCI_LEVEL2((-1," Status : %r\n", Status)); + return EFI_DEVICE_ERROR; + } + + TRACE_AHCI_LEVEL2((-1," Status : %r\n", Status)); + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: GenerateSoftReset +// +// Description: Generate Soft Reset +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// In UINT8 PMPort +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: StopController, ReadytoAcceptCmd, BuildCommandList, BuildCommandFIS, StartController +// +// Notes: +// 1. Issue a Control register update, H2D register FIS with reset bit set. +// 2. Wait for 100usec +// 3. Issue a Control register update, H2D register FIS with reset bit reset. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +GenerateSoftReset ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN UINT8 PMPort + +) +{ + + EFI_STATUS Status; + AHCI_BUS_PROTOCOL *AhciBusInterface = SataDevInterface->AhciBusInterface; + UINT32 AhciBaseAddr = (UINT32)(AhciBusInterface->AhciBaseAddress); + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *)(UINTN) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)(UINTN)AhciBusInterface->PortCommandTableBaseAddr; + COMMAND_STRUCTURE CommandStructure; + UINT32 Data32; + UINT8 Port = SataDevInterface->PortNumber; + + TRACE_AHCI_LEVEL2((-1,"AHCI: SoftReset on Port : %x PMPort : %x", Port, PMPort)); + + PROGRESS_CODE(DXE_IDE_RESET); + + if (gSoftReset) return EFI_SUCCESS; + + gSoftReset = TRUE; + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + + Status = StopController(AhciBusInterface, SataDevInterface,TRUE); + if (EFI_ERROR(Status)) { + goto GenerateSoftReset_Exit; + } + + + // if Command list Override is supported, set CLO bit + Data32 = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_TFD) & (HBA_PORTS_TFD_DRQ | HBA_PORTS_TFD_BSY); + if ((AhciBusInterface->HBACapability & HBA_CAP_SCLO) && Data32){ + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_CLO); + Status = WaitForMemClear(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_CLO, + BUSY_CLEAR_TIMEOUT); + } + + CommandStructure.Control = 4; + BuildCommandList(SataDevInterface, CommandList, (UINT32)(UINTN)Commandtable); + BuildCommandFIS(SataDevInterface, CommandStructure, CommandList, Commandtable); + + CommandList->Ahci_Cmd_W = 0; + // Update of Control Register + Commandtable->CFis.Ahci_CFis_C = 0; + CommandList->Ahci_Cmd_R = 1; + CommandList->Ahci_Cmd_C= 1; + + if (PMPort != 0xFF) Commandtable->CFis.AHci_CFis_PmPort = PMPort; + + StartController(AhciBusInterface, SataDevInterface, BIT00); + // Wait till command is processed + Status = WaitForMemClear(AhciBaseAddr, Port, HBA_PORTS_CI, + BIT00, + ONE_MILLISECOND * 5); + + // Is the command complete? + if (EFI_ERROR(Status)){ + goto GenerateSoftReset_Exit; + } + pBS->Stall (100); // 100 usec + + ZeroMemory (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + BuildCommandList(SataDevInterface, CommandList, (UINT32)(UINTN)Commandtable); + BuildCommandFIS(SataDevInterface, CommandStructure, CommandList, Commandtable); + + CommandList->Ahci_Cmd_W = 0; + // Update of Control Register + Commandtable->CFis.Ahci_CFis_C = 0; + if (PMPort != 0xFF) Commandtable->CFis.AHci_CFis_PmPort = PMPort; + + StartController(AhciBusInterface, SataDevInterface, BIT00); + Status = WaitforCommandComplete(SataDevInterface, NON_DATA_CMD, ATAPI_BUSY_CLEAR_TIMEOUT); + + // Stop Controller + StopController(AhciBusInterface, SataDevInterface,FALSE); + +GenerateSoftReset_Exit: + + gSoftReset = FALSE; + TRACE_AHCI_LEVEL2((-1," Status : %r\n", Status)); + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: HandlePortComReset +// +// Description: Check if COM Reset is successful or not +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT8 Port, +// IN UINT8 PMPort, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ReadSCRRegister, WriteSCRRegister +// +// Notes: +// 1. Check if Link is active. If not return error. +// 2. If Link is present, wait for PhyRdy Change bit to be set. +// 3. Clear SError register +// 4. Wait for D2H register FIS +// 5. Check the Status register for errors. +// 6. If COMRESET is success wait for sometime if the device is ATAPI or GEN1 +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +HandlePortComReset( + IN AHCI_BUS_PROTOCOL *AhciBusInterface, + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN UINT8 Port, + IN UINT8 PMPort +) +{ + + EFI_STATUS Status = EFI_SUCCESS; + BOOLEAN DeviceDetected = FALSE; + UINT32 Data32, i, SStatusData; + UINT32 AhciBaseAddr = (UINT32)(AhciBusInterface->AhciBaseAddress); + volatile AHCI_RECEIVED_FIS *FISAddress; + UINT32 SError = 0; + // Check if detection is complete + for (i = 0; i < HBA_PRESENCE_DETECT_TIMEOUT; i++){ // Total delay 10msec + SStatusData = ReadSCRRegister (AhciBusInterface, SataDevInterface, Port, PMPort, 0); // SStatus + SStatusData &= HBA_PORTS_SSTS_DET_MASK; + if ((SStatusData == HBA_PORTS_SSTS_DET_PCE) || (SStatusData == HBA_PORTS_SSTS_DET)) { + DeviceDetected = TRUE; + break; + } + pBS->Stall (1000); // 1msec + } + + if (DeviceDetected) { + // Wait till PhyRdy Change bit is set + if (PMPort == 0xFF) { + Status = WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_SERR, + HBA_PORTS_SERR_EX, + HBA_PORTS_SERR_EX, + ATAPI_BUSY_CLEAR_TIMEOUT); + } + else { + Status = WaitforPMMemSet (SataDevInterface, PMPort, PSCR_1_SERROR, + HBA_PORTS_SERR_EX, HBA_PORTS_SERR_EX, ATAPI_BUSY_CLEAR_TIMEOUT); + } + + FISAddress = (AHCI_RECEIVED_FIS *)HBA_PORT_REG32(AhciBaseAddr, Port, HBA_PORTS_FB); + + for (i = 0; i < ATAPI_BUSY_CLEAR_TIMEOUT; ) { + SError = ReadSCRRegister (AhciBusInterface, SataDevInterface, Port, PMPort, 2); // SError + if (SError & HBA_PORTS_ERR_CHK) { + WriteSCRRegister (AhciBusInterface, SataDevInterface, Port, PMPort, 1, HBA_PORTS_ERR_CLEAR ); //SError + } + if(FISAddress->Ahci_Rfis[0] == FIS_REGISTER_D2H) {break;} + pBS->Stall (1000); // 1msec Strange. Delay is needed for read to succeed. + if (PMPort != 0xFF) {i+= 100;} // For device behind PM Port, there is a delay in writing to the register. So count can be decreased. + else { i++; } + } + + // Wait till PxTFD gets updated from D2H FIS + for (i = 0; i < 100; i++){ // Total delay 10msec + WriteSCRRegister (AhciBusInterface, SataDevInterface, Port, PMPort, 1, HBA_PORTS_ERR_CLEAR); //SError + if((FISAddress->Ahci_Rfis[2] & HBA_PORTS_TFD_MASK) == (HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_TFD) & HBA_PORTS_TFD_MASK)) break; + pBS->Stall (100); // 100usec + } + + // check for errors + if (FISAddress->Ahci_Rfis[2] & (HBA_PORTS_TFD_BSY | HBA_PORTS_TFD_ERR)) Status = EFI_DEVICE_ERROR; + + Data32 = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_IS); + if (Data32 & (BIT30 + BIT29 + BIT28 + BIT27 + BIT26)) Status = EFI_DEVICE_ERROR; + + // Clear the status + WriteSCRRegister (AhciBusInterface, SataDevInterface, Port, PMPort, 1, HBA_PORTS_ERR_CLEAR); //SError + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + } + else { + Status = EFI_DEVICE_ERROR; + } + + + return Status; + +} + + +// +//---------------------------------------------------------------------------- +// Procedure: ReadSCRRegister +// +// Description: +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT8 Port, +// IN UINT8 PMPort, +// IN UINT8 Register (0 : SStatus 1: SError 2: SControl) +// +// Output: +// UINT32 +// Modified: +// +// Referrals: +// +// Notes: +// 1. Check if the device is connected directly to the port +// 2. if yes, read to the AHCI Controller else write to the Port Multiplier register. +// +//---------------------------------------------------------------------------- +// +UINT32 +ReadSCRRegister ( + IN AHCI_BUS_PROTOCOL *AhciBusInterface, + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN UINT8 Port, + IN UINT8 PMPort, + IN UINT8 Register +) +{ + + UINT32 Data32 = 0; + UINT32 Reg = HBA_PORTS_SSTS; + + if (PMPort != 0xFF) { + ReadWritePMPort (SataDevInterface, PMPort, Register, &Data32, FALSE); + } + else { + if (Register == 1) Reg = HBA_PORTS_SCTL; + if (Register == 2) Reg = HBA_PORTS_SERR; + Data32 = HBA_PORT_REG32 (AhciBusInterface->AhciBaseAddress, Port, Reg); + } + + return Data32; +} + +// +//---------------------------------------------------------------------------- +// Procedure: WriteSCRRegister +// +// Description: Write to SCONTROL/Serror/SStatus register +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT8 Port, +// IN UINT8 PMPort, +// IN UINT8 Register, (0 : SStatus 1: SError 2: SControl) +// IN UINT32 Data32 +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Check if the device is connected directly to the port +// 2. if yes, write to the AHCI Controller else write to the Port Multiplier register +// +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +WriteSCRRegister ( + IN AHCI_BUS_PROTOCOL *AhciBusInterface, + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN UINT8 Port, + IN UINT8 PMPort, + IN UINT8 Register, + IN UINT32 Data32 +) +{ + + UINT32 Reg = HBA_PORTS_SSTS; + + if (PMPort != 0xFF) { + ReadWritePMPort (SataDevInterface, PMPort, Register, &Data32, TRUE); + } + else { + if (Register == 2) Reg = HBA_PORTS_SCTL; + if (Register == 1) Reg = HBA_PORTS_SERR; + HBA_PORT_REG32_OR (AhciBusInterface->AhciBaseAddress, Port, Reg, Data32); + } + + return EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// Procedure: WaitforPMMemSet +// +// Description: Wait for memory to be set to the test value. +// +// Input: +// SATA_DEVICE_INTERFACE *SataDevInterface, +// PMPort +// Register +// MaskValue - The mask value of memory +// TestValue - The test value of memory +// WaitTimeInMs - The time out value for wait memory set +// +// Output: EFI_SUCCESS - HBA reset successfully. +// EFI_DEVICE_ERROR - HBA failed to complete hardware reset. +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +WaitforPMMemSet ( + IN SATA_DEVICE_INTERFACE *SataDevInterface, + IN UINT8 PMPort, + IN UINT8 Register, + IN UINT32 AndMask, + IN UINT32 TestValue, + IN UINT32 WaitTimeInMs +) +{ + UINT32 Data32; + + while(WaitTimeInMs!=0){ + ReadWritePMPort (SataDevInterface, PMPort, Register, &Data32, FALSE); + if((Data32 & AndMask) == TestValue) {return EFI_SUCCESS;} + pBS->Stall (1000); // 1Msec + WaitTimeInMs--; + } + return EFI_DEVICE_ERROR; +} + + +// +//---------------------------------------------------------------------------- +// Procedure: CheckValidDevice +// +// Description: Check for valid ATA/ATAPI/PMPORT signature +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN UINT8 Port, +// IN UINT8 PMPort +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Check if Link is active +// 2. Enable FIS and Command list run bits +// 3. Check for valid signature +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +CheckValidDevice ( + IN AHCI_BUS_PROTOCOL *AhciBusInterface, + IN UINT8 Port, + IN UINT8 PMPort +) +{ + + UINT8 Data8; + UINT32 Data32; + UINT32 AhciBaseAddr = (UINT32)(AhciBusInterface->AhciBaseAddress); + + // Check if Link is active + Data8 = (UINT8)(HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_SSTS) & HBA_PORTS_SSTS_DET_MASK); + if (Data8 != HBA_PORTS_SSTS_DET_PCE) return EFI_DEVICE_ERROR; + + // Enable FIS receive and CI so that TFD gets updated properly + // Clear out the command slot + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_CI, 0); + + // Enable FIS Receive + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_FRE | HBA_PORTS_CMD_ST); + + // Wait till FIS is running + WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + // Wait till CR list is running + WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_CR, + HBA_PORTS_CMD_CR, + HBA_FR_CLEAR_TIMEOUT); + + // Clear Start Bit + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_CMD, ~(HBA_PORTS_CMD_ST)); + WaitForMemClear(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_CR, + HBA_CR_CLEAR_TIMEOUT); + + //Clear FIS Receive enable bit + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_CMD, ~(HBA_PORTS_CMD_FRE)); + WaitForMemClear(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + + // Check if valid signature is present + Data32 = HBA_PORT_REG32(AhciBaseAddr, Port, HBA_PORTS_SIG); + if (Data32 != ATA_SIGNATURE_32 && Data32 != ATAPI_SIGNATURE_32 && Data32 != PMPORT_SIGNATURE) + return EFI_DEVICE_ERROR; + + Data8 = HBA_PORT_REG8 (AhciBaseAddr, Port, HBA_PORTS_TFD); + if (Data8 & (HBA_PORTS_TFD_BSY | HBA_PORTS_TFD_DRQ)) return EFI_DEVICE_ERROR; + + return EFI_SUCCESS; + +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** \ No newline at end of file diff --git a/Core/EM/Ahci/AhciController.h b/Core/EM/Ahci/AhciController.h new file mode 100644 index 0000000..9ec5e75 --- /dev/null +++ b/Core/EM/Ahci/AhciController.h @@ -0,0 +1,633 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2013, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/AhciController.h 9 11/13/13 1:52a Divyac $ +// +// $Revision: 9 $ +// +// $Date: 11/13/13 1:52a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/AHCI/AhciController.h $ +// +// 9 11/13/13 1:52a Divyac +// [TAG] EIP143018 +// [Category] Improvement +// [Description] Removed the EIP 128912 changes and checked-in again. +// EIP 128912 changes creates lot more side effect, so we planed to remove +// the changes. +// [Files] AhciController.h +// +// 8 7/23/13 11:56p Srikantakumarp +// [TAG] EIP129989 +// [Category] Improvement +// [Description] Added DIPM support in Aptio 4.x AHCIBUS driver. +// [Files] AhciBus.c, AhciBus.h, AhciController.h, AhciSrc.sdl, +// PAhciBus.h +// +// 7 7/18/13 7:35a Rameshr +// [TAG] EIP128912 +// [Category] Improvement +// [Description] 10b to 8b decode error is mentioned as Diagnostic error +// for use by Diagnostic software, So removed this error status checking +// [Files] AhciController.h +// +// 6 7/17/13 10:40a Rameshr +// [TAG] EIP128912 +// [Category] Improvement +// [Description] 10b to 8b decode error is mentioned as Diagnostic error +// for use by Diagnostic software, So removed this error status checking. +// [Files] AhciController.h +// +// 5 2/10/11 10:35a Rameshr +// [TAG] EIP53704 +// [Category] Improvement +// [Description] AMI headers update for Alaska Ahci Driver +// [Files] AhciSrc.mak +// AhciBus.c +// AhciController.c +// AhciComponentName.c +// AhciBus.h +// AhciController.h +// +// 4 5/07/10 11:45a Krishnakumarg +// Coding standard update +// +// 3 7/09/09 4:50p Fasihm +// Fixed the Read/Write failure when ALPE is Enabled. +// +// 2 5/28/08 9:39a Rameshraju +// Based on the SDL token index/data or MMIO method used to access the +// AHCI configuration space. +// +// 1 28/02/08 6:03p Anandakrishnanl +// AHCI Bus Driver initial check-in. +// +//********************************************************************** +// +// +// Name: AhciController.h +// +// Description: +// +// +//********************************************************************** + +// Forward reference for pure ANSI compatability +typedef struct _AHCI_COMMAND_FIS AHCI_COMMAND_FIS; +typedef struct _AHCI_ATAPI_COMMAND AHCI_ATAPI_COMMAND; +typedef struct _AHCI_COMMAND_PRDT AHCI_COMMAND_PRDT; + +#pragma pack(1) + +// Command List Structure +typedef struct { + UINT32 Ahci_Cmd_CFL:5; + UINT32 Ahci_Cmd_A:1; + UINT32 Ahci_Cmd_W:1; + UINT32 Ahci_Cmd_P:1; + UINT32 Ahci_Cmd_R:1; + UINT32 Ahci_Cmd_B:1; + UINT32 Ahci_Cmd_C:1; + UINT32 Ahci_Cmd_Rsvd1:1; + UINT32 Ahci_Cmd_PMP:4; + UINT32 Ahci_Cmd_PRDTL:16; + UINT32 Ahci_Cmd_PRDBC; + UINT32 Ahci_Cmd_CTBA; + UINT32 Ahci_Cmd_CTBAU; + UINT32 Ahci_Cmd_Rsvd2[4]; +} AHCI_COMMAND_LIST; + +typedef struct { + UINT8 Ahci_Dsfis[0x1C]; // DMA Setup Fis + UINT8 Ahci_Dsfis_Rsvd[0x04]; + UINT8 Ahci_Psfis[0x14]; // PIO Setip Fis + UINT8 Ahci_Psfis_Rsvd[0x0C]; + UINT8 Ahci_Rfis[0x14]; // D2H Register Fis + UINT8 Ahci_Rfis_Rsvd[0x04]; + UINT64 Ahci_Sdbfis; // Set Device Bits Fis + UINT8 Ahci_Ufis[0x40]; // Unkonw FIS + UINT8 Ahci_Ufis_Rsvd[0x60]; +} AHCI_RECEIVED_FIS; + +// Register - Host to Device FIS Layout +typedef struct _AHCI_COMMAND_FIS{ + UINT8 Ahci_CFis_Type; + UINT8 AHci_CFis_PmPort:4; + UINT8 Ahci_CFis_Rsvd1:1; + UINT8 Ahci_CFis_Rsvd2:1; + UINT8 Ahci_CFis_Rsvd3:1; + UINT8 Ahci_CFis_C:1; + UINT8 Ahci_CFis_Cmd; + UINT8 Ahci_CFis_Features; + UINT8 Ahci_CFis_SecNum; + UINT8 Ahci_CFis_ClyLow; + UINT8 Ahci_CFis_ClyHigh; + UINT8 Ahci_CFis_DevHead; + UINT8 Ahci_CFis_SecNumExp; + UINT8 Ahci_CFis_ClyLowExp; + UINT8 Ahci_CFis_ClyHighExp; + UINT8 Ahci_CFis_FeaturesExp; + UINT8 Ahci_CFis_SecCount; + UINT8 Ahci_CFis_SecCountExp; + UINT8 Ahci_CFis_Rsvd4; + UINT8 Ahci_CFis_Control; + UINT8 Ahci_CFis_Rsvd5[4]; + UINT8 Ahci_CFis_Rsvd6[44]; +} AHCI_COMMAND_FIS; + +// Physical Region Descriptor Table +typedef struct _AHCI_COMMAND_PRDT{ + UINT32 Ahci_Prdt_DBA; + UINT32 Ahci_Prdt_DBAU; + UINT32 Ahci_Prdt_Rsvd; + UINT32 Ahci_Prdt_DBC:22; + UINT32 Ahci_Prdt_Rsvd1:9; + UINT32 Ahci_Prdt_I:1; +} AHCI_COMMAND_PRDT; + +// Command table + +typedef struct _AHCI_COMMAND_TABLE{ + AHCI_COMMAND_FIS CFis; + AHCI_ATAPI_COMMAND AtapiCmd; + UINT8 Rsvd[0x30]; + AHCI_COMMAND_PRDT PrdtTable; +} AHCI_COMMAND_TABLE; + +typedef struct _AHCI_COMMAND_TABLE_NO_PRDT{ + AHCI_COMMAND_FIS CFis; + AHCI_ATAPI_COMMAND AtapiCmd; + UINT8 Rsvd[0x30]; +} AHCI_COMMAND_TABLE_NO_PRDT; + +#pragma pack() + +#define ATA_SIGNATURE_32 0x00000101 +#define ATAPI_SIGNATURE_32 0xEB140101 +#define PMPORT_SIGNATURE 0x96690101 +#define PRD_MAX_DATA_COUNT 0x400000 + + + +#define PCI_ABAR 0x24 +#define RECEIVED_FIS_SIZE 0x100 + +#define CONTROL_PORT 0x0F + +//Generic Host Control Registers +#define HBA_CAP 0x0000 +#define HBA_CAP_NP_MASK 0x1F +#define HBA_CAP_EMS BIT06 +#define HBA_CAP_PSC BIT13 +#define HBA_CAP_SSC BIT14 +#define HBA_CAP_PMD BIT15 +#define HBA_CAP_FBSS BIT16 +#define HBA_CAP_SPM BIT17 +#define HBA_CAP_SAM BIT18 +#define HBA_CAP_SNZO BIT19 +#define HBA_CAP_ISS_MASK (BIT20 | BIT21 | BIT22 | BIT23) +#define HBA_CAP_SCLO BIT24 +#define HBA_CAP_SAL BIT25 +#define HBA_CAP_SALP BIT26 +#define HBA_CAP_SSS BIT27 +#define HBA_CAP_SMPS bit28 +#define HBA_CAP_SSNTF BIT29 +#define HBA_CAP_SCQA BIT30 +#define HBA_CAP_S64A BIT31 + +#define HBA_GHC 0x0004 +#define HBA_GHC_RESET 0x0001 +#define HBA_GHC_IE 0x0002 +#define HBA_GHC_AE 0x80000000 +#define HBA_GHC_AE_RESET 0x80000001 +#define HBA_IS 0x0008 +#define HBA_PI 0x000C +#define HBA_VS 0x0010 +#define HBA_CCC_CTL 0x0014 +#define HBA_CCC_PORTS 0x0018 +#define HBA_EM_LOC 0x001C +#define HBA_EM_CTL 0x0020 +#define HBA_CAP2 0x0024 +#define HBA_CAP2_APST 0x0004 +#define HBA_CAP2_SDS 0x0008 +#define HBA_CAP2_SADM 0x0010 +#define HBA_CAP2_DESO 0x0020 + +//Port Registers +#define HBA_PORTS_START 0x0100 +#define HBA_PORTS_REG_WIDTH 0x0080 +#define HBA_PORTS_CLB 0x0000 +#define HBA_PORTS_CLBU 0x0004 +#define HBA_PORTS_FB 0x0008 +#define HBA_PORTS_FBU 0x000C +#define HBA_PORTS_IS 0x0010 +#define HBA_PORTS_IS_DHRS BIT00 +#define HBA_PORTS_IS_PSS BIT01 +#define HBA_PORTS_IS_SSS BIT02 +#define HBA_PORTS_IS_SDBS BIT03 +#define HBA_PORTS_IS_UFS BIT04 +#define HBA_PORTS_IS_DPS BIT05 +#define HBA_PORTS_IS_PCS BIT06 +#define HBA_PORTS_IS_DIS BIT07 +#define HBA_PORTS_IS_PRCS BIT22 +#define HBA_PORTS_IS_IPMS BIT23 +#define HBA_PORTS_IS_OFS BIT24 +#define HBA_PORTS_IS_INFS BIT26 +#define HBA_PORTS_IS_IFS BIT27 +#define HBA_PORTS_IS_HBDS BIT28 +#define HBA_PORTS_IS_HBFS BIT29 +#define HBA_PORTS_IS_TFES BIT30 +#define HBA_PORTS_IS_CPDS BIT31 +#define HBA_PORTS_IS_CLEAR 0xFFC000FF +#define HBA_PORTS_IS_FIS_CLEAR 0x0000001F +#define HBA_PORTS_IS_ERR_CHK BIT04 + BIT06 + BIT23 + BIT24 + BIT27 + \ + BIT28 + BIT29 + BIT30 + BIT31 + +#define HBA_PORTS_IE 0x0014 +#define HBA_PORTS_CMD 0x0018 +#define HBA_PORTS_CMD_ST_MASK 0xFFFFFFFE +#define HBA_PORTS_CMD_ST BIT00 +#define HBA_PORTS_CMD_SUD BIT01 +#define HBA_PORTS_CMD_POD BIT02 +#define HBA_PORTS_CMD_CLO BIT03 +#define HBA_PORTS_CMD_CR BIT15 +#define HBA_PORTS_CMD_FRE BIT04 +#define HBA_PORTS_CMD_FR BIT14 +#define HBA_PORTS_CMD_MASK ~(HBA_PORTS_CMD_ST | HBA_PORTS_CMD_FRE | HBA_PORTS_CMD_CLO) +#define HBA_PORTS_CMD_PMA BIT17 +#define HBA_PORTS_CMD_HPCP BIT18 +#define HBA_PORTS_CMD_MPSP BIT19 +#define HBA_PORTS_CMD_CPD BIT20 +#define HBA_PORTS_CMD_ESP BIT21 +#define HBA_PORTS_CMD_ATAPI BIT24 +#define HBA_PORTS_CMD_DLAE BIT25 +#define HBA_PORTS_CMD_ALPE BIT26 +#define HBA_PORTS_CMD_ASP BIT27 +#define HBA_PORTS_CMD_ICC_MASK (BIT28 | BIT29 | BIT30 | BIT31) +#define HBA_PORTS_CMD_ACTIVE (1 << 28 ) +#define HBA_PORTS_TFD 0x0020 +#define HBA_PORTS_TFD_MASK (BIT07 | BIT03 | BIT00) +#define HBA_PORTS_TFD_BSY BIT07 +#define HBA_PORTS_TFD_DRQ BIT03 +#define HBA_PORTS_TFD_ERR BIT00 +#define HBA_PORTS_TFD_ERR_MASK 0x00FF00 // BIT8 - BIT15 +#define HBA_PORTS_SIG 0x0024 +#define HBA_PORTS_SSTS 0x0028 +#define HBA_PORTS_SSTS_DET_MASK 0x000F +#define HBA_PORTS_SSTS_DET 0x0001 +#define HBA_PORTS_SSTS_DET_PCE 0x0003 +#define HBA_PORTS_SSTS_SPD_MASK 0x00F0 +#define HBA_PORTS_SCTL 0x002C +#define HBA_PORTS_SCTL_DET_MASK 0x000F +#define HBA_PORTS_SCTL_MASK (~HBA_PORTS_SCTL_DET_MASK) +#define HBA_PORTS_SCTL_DET_INIT 0x0001 +#define HBA_PORTS_SCTL_DET_PHYCOMM 0x0003 +#define HBA_PORTS_SCTL_SPD_MASK 0x00F0 +#define HBA_PORTS_SCTL_SPD_NSNR 0x0 +#define HBA_PORTS_SCTL_SPD_GEN1 0x1 +#define HBA_PORTS_SCTL_SPD_GEN2 0x2 +#define HBA_PORTS_SCTL_SPD_GEN3 0x3 +#define HBA_PORTS_SCTL_IPM_MASK 0x0F00 +#define HBA_PORTS_SCTL_IPM_DIS 0x00 +#define HBA_PORTS_SCTL_IPM_PSD 0x01 +#define HBA_PORTS_SCTL_IPM_SSD 0x02 +#define HBA_PORTS_SCTL_IPM_PSSD 0x03 +#define HBA_PORTS_SCTL_IPM_PSD_SSD 0x0300 +#define HBA_PORTS_SERR 0x0030 +#define HBA_PORTS_SERR_RDIE BIT00 +#define HBA_PORTS_SERR_RCE BIT01 +#define HBA_PORTS_SERR_TDIE BIT08 +#define HBA_PORTS_SERR_PCDIE BIT09 +#define HBA_PORTS_SERR_PE BIT10 +#define HBA_PORTS_SERR_IE BIT11 +#define HBA_PORTS_SERR_PRC BIT16 +#define HBA_PORTS_SERR_PIE BIT17 +#define HBA_PORTS_SERR_CW BIT18 +#define HBA_PORTS_SERR_BDE BIT19 +#define HBA_PORTS_SERR_DE BIT20 // Not used +#define HBA_PORTS_SERR_CRCE BIT21 +#define HBA_PORTS_SERR_HE BIT22 +#define HBA_PORTS_SERR_LSE BIT23 +#define HBA_PORTS_SERR_TSTE BIT24 +#define HBA_PORTS_SERR_UFT BIT25 +#define HBA_PORTS_SERR_EX BIT26 +#define HBA_PORTS_PxSACT 0x0034 +#define HBA_PORTS_PxCI 0x0038 +#define HBA_PORTS_PxDEVSLP 0x0044 +#define HBA_PORTS_PxDEVSLP_ADSE BIT00 +#define HBA_PORTS_PxDEVSLP_DSP BIT01 +#define HBA_PORTS_PxDEVSLP_DETO_MASK (0x000003FC) +#define HBA_PORTS_PxDEVSLP_DMDAT_MASK (0x00007C00) +#define HBA_PORTS_PxDEVSLP_DITO_MASK (0x01FF8000) +#define HBA_PORTS_PxDEVSLP_DM_MASK (0x1E000000) + +#define HBA_PORTS_ERR_CHK (HBA_PORTS_SERR_TDIE + HBA_PORTS_SERR_PCDIE +\ + HBA_PORTS_SERR_PE + HBA_PORTS_SERR_IE + \ + HBA_PORTS_SERR_PIE + \ + HBA_PORTS_SERR_BDE + \ + HBA_PORTS_SERR_DE + HBA_PORTS_SERR_CRCE + \ + HBA_PORTS_SERR_HE + HBA_PORTS_SERR_LSE + \ + HBA_PORTS_SERR_TSTE + HBA_PORTS_SERR_UFT + \ + HBA_PORTS_SERR_EX) + +#define HBA_PORTS_ERR_CLEAR (HBA_PORTS_SERR_RDIE + HBA_PORTS_SERR_RCE +\ + HBA_PORTS_SERR_TDIE + HBA_PORTS_SERR_PCDIE +\ + HBA_PORTS_SERR_PE + HBA_PORTS_SERR_IE + \ + HBA_PORTS_SERR_PRC + HBA_PORTS_SERR_PIE + \ + HBA_PORTS_SERR_CW + HBA_PORTS_SERR_BDE + \ + HBA_PORTS_SERR_DE + HBA_PORTS_SERR_CRCE + \ + HBA_PORTS_SERR_HE + HBA_PORTS_SERR_LSE + \ + HBA_PORTS_SERR_TSTE + HBA_PORTS_SERR_UFT + \ + HBA_PORTS_SERR_EX) +#define HBA_PORTS_SACT 0x0034 +#define HBA_PORTS_CI 0x0038 +#define HBA_PORTS_SNTF 0x003C + +//FIS Types +#define D2H_FIS_OFFSET 0x40 +#define DMA_FIS_OFFSET 0x00 +#define PIO_FIS_OFFSET 0x20 +#define SDB_FIS_OFFSET 0x58 +#define FIS_TYPE_MASK 0xFF +#define U_FIS_OFFSET 0x60 + +#define FIS_REGISTER_H2D 0x27 // Host To Device +#define FIS_REGISTER_H2D_LENGTH 20 +#define FIS_REGISTER_D2H 0x34 // Device To Host +#define FIS_REGISTER_D2H_LENGTH 20 // Device To Host +#define FIS_DMA_ACTIVATE 0x39 // Device To Host +#define FIS_DMA_ACTIVATE_LENGTH 4 +#define FIS_DMA_SETUP 0x41 // Bi-directional +#define FIS_DMA_SETUP_LENGTH 28 +#define FIS_DATA 0x46 // Bi-directional +#define FIS_BIST 0x58 // Bi-directional +#define FIS_BIST_LENGTH 12 +#define FIS_PIO_SETUP 0x5F // Device To Host +#define FIS_PIO_SETUP_LENGTH 20 +#define FIS_SET_DEVICE 0xA1 // Device To Host +#define FIS_SET_DEVICE_LENGTH 8 + + +#define READ_PORT_MULTIPLIER 0xE4 +#define WRITE_PORT_MULTIPLIER 0xE8 + +#define GSCR_0 0x00 +#define GSCR_1 0x01 +#define GSCR_2 0x02 +#define GSCR_32 32 +#define GSCR_64 64 +#define GSCR_96 96 + +#define PSCR_0_SSTATUS 0x00 +#define PSCR_1_SERROR 0x01 +#define PSCR_2_SCONTROL 0x02 + + +#define HBA_CR_CLEAR_TIMEOUT 500 // AHCI 1.2 spec 10.1.2 +#define HBA_FR_CLEAR_TIMEOUT 500 // AHCI 1.2 spec 10.1.2 +#define HBA_PRESENCE_DETECT_TIMEOUT 10 // 10msec Serial ATA 1.0 Sec 5.2 + +#if INDEX_DATA_PORT_ACCESS + + // + //Index , Data port access + // + +#define HBA_PORT_REG_BASE(Port) \ + (UINTN) (Port * HBA_PORTS_REG_WIDTH + HBA_PORTS_START) + +#define HBA_REG32( BaseAddr, Register ) \ + (ReadDataDword ((BaseAddr), (Register))) + +#define HBA_WRITE_REG32( BaseAddr, Register, Data ) \ + (WriteDataDword( BaseAddr, Register, Data )) + +#define HBA_REG16( BaseAddr, Register ) \ + (ReadDataWord( BaseAddr, Register )) + +#define HBA_WRITE_REG16( BaseAddr, Register, Data ) \ + (WriteDataWord( BaseAddr, Register, Data )) + +#define HBA_REG8( BaseAddr, Register ) \ + (ReadDataByte ((BaseAddr), (Register))) + +#define HBA_WRITE_REG8( BaseAddr, Register, Data ) \ + (WriteDataByte( BaseAddr, Register, Data )) + +#define HBA_REG8_OR( BaseAddr, Register, OrData) \ + HBA_WRITE_REG8(BaseAddr, Register, ((HBA_REG8 ((BaseAddr), (Register))) | ((UINT8) (OrData)))) + +#define HBA_REG16_OR( BaseAddr, Register, OrData) \ + HBA_WRITE_REG16(BaseAddr, Register, ((HBA_REG16 ((BaseAddr), (Register))) | ((UINT16) (OrData)))) + +#define HBA_REG32_OR( BaseAddr, Register, OrData) \ + HBA_WRITE_REG32(BaseAddr, Register, ((HBA_REG32 ((BaseAddr), (Register))) | ((UINT32) (OrData)))) + +#define HBA_REG8_AND( BaseAddr, Register, AndData) \ + HBA_WRITE_REG8(BaseAddr, Register, ((HBA_REG8 ((BaseAddr), (Register))) & ((UINT8) (AndData)))) + +#define HBA_REG16_AND( BaseAddr, Register, AndData) \ + HBA_WRITE_REG16(BaseAddr, Register, ((HBA_REG16 ((BaseAddr), (Register))) & ((UINT16) (AndData)))) + +#define HBA_REG32_AND( BaseAddr, Register, AndData) \ + HBA_WRITE_REG32(BaseAddr, Register, ((HBA_REG32 ((BaseAddr), (Register))) & ((UINT32) (AndData)))) + +#define HBA_REG8_AND_OR( BaseAddr, Register, AndData, OrData) \ + HBA_WRITE_REG8(BaseAddr, Register, ((HBA_REG8 ((BaseAddr), (Register))) & ((UINT8) (AndData)) | ((UINT8) (OrData)))) + +#define HBA_REG16_AND_OR( BaseAddr, Register, AndData, OrData) \ + HBA_WRITE_REG16(BaseAddr, Register, ((HBA_REG16 ((BaseAddr), (Register))) & ((UINT16) (AndData)) | ((UINT16) (OrData)))) + +#define HBA_REG32_AND_OR( BaseAddr, Register,AndData, OrData) \ + HBA_WRITE_REG32(BaseAddr, Register, ((HBA_REG32 ((BaseAddr), (Register))) & ((UINT32) (AndData)) | ((UINT32) (OrData)))) + +//Ports +#define HBA_PORT_REG8(BaseAddr, Port, Register) \ + (HBA_REG8 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)))) + +#define HBA_PORT_REG16(BaseAddr, Port, Register) \ + (HBA_REG16 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)))) + +#define HBA_PORT_REG32(BaseAddr, Port, Register) \ + (HBA_REG32 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)))) + +#define HBA_PORT_WRITE_REG8(BaseAddr, Port, Register, Data) \ + (HBA_WRITE_REG8 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), Data)) + +#define HBA_PORT_WRITE_REG16(BaseAddr, Port, Register, Data) \ + (HBA_WRITE_REG16 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)),Data)) + +#define HBA_PORT_WRITE_REG32(BaseAddr, Port, Register,Data) \ + (HBA_WRITE_REG32 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)),Data)) + +#define HBA_PORT_REG8_OR(BaseAddr, Port, Register, OrData) \ + (HBA_REG8_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (OrData))) + +#define HBA_PORT_REG16_OR(BaseAddr, Port, Register, OrData) \ + (HBA_REG16_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (OrData))) + +#define HBA_PORT_REG32_OR(BaseAddr, Port, Register, OrData) \ + (HBA_REG32_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (OrData))) + +#define HBA_PORT_REG8_AND(BaseAddr, Port, Register, AndData) \ + (HBA_REG8_AND ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData))) + +#define HBA_PORT_REG16_AND(BaseAddr, Port, Register, AndData) \ + (HBA_REG16_AND ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData))) + +#define HBA_PORT_REG32_AND(BaseAddr, Port, Register, AndData) \ + (HBA_REG32_AND ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData))) + +#define HBA_PORT_REG8_AND_OR(BaseAddr, Port, Register, AndData, OrData) \ + (HBA_REG8_AND_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData), (OrData))) + +#define HBA_PORT_REG16_AND_OR(BaseAddr, Port, Register, AndData, OrData) \ + (HBA_REG16_AND_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData), (OrData))) + +#define HBA_PORT_REG32_AND_OR(BaseAddr, Port, Register, AndData, OrData) \ + (HBA_REG32_AND_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData), (OrData))) + +#else + // + //MMIO Access + // +#define MmAddress( BaseAddr, Register ) \ + ((UINTN)(BaseAddr) + \ + (UINTN)(Register) \ + ) +#define Mm32Ptr( BaseAddr, Register ) \ + ((volatile UINT32 *)MmAddress (BaseAddr, Register )) + +#define Mm16Ptr( BaseAddr, Register ) \ + ((volatile UINT16 *)MmAddress (BaseAddr, Register )) + +#define Mm8Ptr( BaseAddr, Register ) \ + ((volatile UINT8 *)MmAddress (BaseAddr, Register )) + +//HBA Generic +#define HBA_PORT_REG_BASE(Port) \ + (UINTN) (Port * HBA_PORTS_REG_WIDTH + HBA_PORTS_START) + +#define HBA_REG32( BaseAddr, Register ) \ + (*Mm32Ptr ((BaseAddr), (Register))) + +#define HBA_REG16( BaseAddr, Register ) \ + (*Mm16Ptr ((BaseAddr), (Register))) + +#define HBA_REG8( BaseAddr, Register ) \ + (*Mm8Ptr ((BaseAddr), (Register))) + +#define HBA_WRITE_REG32( BaseAddr, Register, Data ) \ + (HBA_REG32 ((BaseAddr), (Register))) = ((UINT32) (Data)) + +#define HBA_WRITE_REG16( BaseAddr, Register, Data ) \ + (HBA_REG16 ((BaseAddr), (Register))) = ((UINT16) (Data)) + +#define HBA_WRITE_REG8( BaseAddr, Register, Data ) \ + (HBA_REG8 ((BaseAddr), (Register))) = ((UINT8) (Data)) + +#define HBA_REG8_OR( BaseAddr, Register, OrData) \ + (HBA_REG8 ((BaseAddr), (Register))) |= ((UINT8) (OrData)) + +#define HBA_REG16_OR( BaseAddr, Register, OrData) \ + (HBA_REG16 ((BaseAddr), (Register))) |= ((UINT16) (OrData)) + +#define HBA_REG32_OR( BaseAddr, Register, OrData) \ + (HBA_REG32 ((BaseAddr), (Register))) = (HBA_REG32 ((BaseAddr), (Register))) | ((UINT32) (OrData)) + +#define HBA_REG8_AND( BaseAddr, Register, AndData) \ + (HBA_REG8 ((BaseAddr), (Register))) = (HBA_REG8 ((BaseAddr), (Register))) & ((UINT8) (AndData)) + +#define HBA_REG16_AND( BaseAddr, Register, AndData) \ + (HBA_REG16 ((BaseAddr), (Register))) &= ((UINT16) (AndData)) + +#define HBA_REG32_AND( BaseAddr, Register, AndData) \ + (HBA_REG32 ((BaseAddr), (Register))) = (HBA_REG32 ((BaseAddr), (Register))) & ((UINT32) (AndData)) + +#define HBA_REG8_AND_OR( BaseAddr, Register, AndData, OrData) \ + (HBA_REG8 ((BaseAddr), (Register)) = \ + (((HBA_REG8 ((BaseAddr), (Register))) & ((UINT8) (AndData))) | ((UINT8) (OrData)))) + +#define HBA_REG16_AND_OR( BaseAddr, Register, AndData, OrData) \ + (HBA_REG16 ((BaseAddr), (Register)) = \ + (((HBA_REG16 ((BaseAddr), (Register))) & ((UINT16) AndData)) | ((UINT16) (OrData)))) + +#define HBA_REG32_AND_OR( BaseAddr, Register,AndData, OrData) \ + (HBA_REG32 ((BaseAddr), (Register)) = \ + (((HBA_REG32 ((BaseAddr), (Register))) & ((UINT32) (AndData))) | ((UINT32) (OrData)))) + +//Ports +#define HBA_PORT_REG8(BaseAddr, Port, Register) \ + (HBA_REG8 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)))) + +#define HBA_PORT_REG16(BaseAddr, Port, Register) \ + (HBA_REG16 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)))) + +#define HBA_PORT_REG32(BaseAddr, Port, Register) \ + (HBA_REG32 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)))) + +#define HBA_PORT_WRITE_REG8(BaseAddr, Port, Register, Data) \ + (HBA_WRITE_REG8 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), Data)) + +#define HBA_PORT_WRITE_REG16(BaseAddr, Port, Register, Data) \ + (HBA_WRITE_REG16 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)),Data)) + +#define HBA_PORT_WRITE_REG32(BaseAddr, Port, Register,Data) \ + (HBA_WRITE_REG32 ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)),Data)) + +#define HBA_PORT_REG8_OR(BaseAddr, Port, Register, OrData) \ + (HBA_REG8_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (OrData))) + +#define HBA_PORT_REG16_OR(BaseAddr, Port, Register, OrData) \ + (HBA_REG16_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (OrData))) + +#define HBA_PORT_REG32_OR(BaseAddr, Port, Register, OrData) \ + (HBA_REG32_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (OrData))) + +#define HBA_PORT_REG8_AND(BaseAddr, Port, Register, AndData) \ + (HBA_REG8_AND ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData))) + +#define HBA_PORT_REG16_AND(BaseAddr, Port, Register, AndData) \ + (HBA_REG16_AND ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData))) + +#define HBA_PORT_REG32_AND(BaseAddr, Port, Register, AndData) \ + (HBA_REG32_AND ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData))) + +#define HBA_PORT_REG8_AND_OR(BaseAddr, Port, Register, AndData, OrData) \ + (HBA_REG8_AND_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData), (OrData))) + +#define HBA_PORT_REG16_AND_OR(BaseAddr, Port, Register, AndData, OrData) \ + (HBA_REG16_AND_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData), (OrData))) + +#define HBA_PORT_REG32_AND_OR(BaseAddr, Port, Register, AndData, OrData) \ + (HBA_REG32_AND_OR ((BaseAddr), ((Register) + HBA_PORT_REG_BASE (Port)), (AndData), (OrData))) + +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2013, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** \ No newline at end of file diff --git a/Core/EM/Ahci/AhciInt13Dxe.c b/Core/EM/Ahci/AhciInt13Dxe.c new file mode 100644 index 0000000..20724ad --- /dev/null +++ b/Core/EM/Ahci/AhciInt13Dxe.c @@ -0,0 +1,412 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Dxe.c 1 11/25/14 12:09a Kapilporwal $Revision: +// +// $Date: 11/25/14 12:09a $Log: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Dxe.c $ +// +// +// +//**************************************************************************** + +// +//**************************************************************************** +// +// Name: AhciInt13Dxe.c +// +// Description: +// This file will register one CALLBACK function, AmiLegacyBootNotify(), +// it will collect AHCI Int13 runtime data from gAhciI13Data and +// send it to SMM for AHCI INT13 SMI handler. +//**************************************************************************** +// + +//--------------------------------------------------------------------------- +#include +#include + +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION>=0x4028B) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AInt13.h" +#include "AhciInt13Smm.h" + +AHCI_I13_RTDATA *gAhciI13Data = NULL; +extern EFI_GUID gAint13SmmDataGuid; +EFI_GUID gEfiLegacyBiosProtocolGuid = EFI_LEGACY_BIOS_PROTOCOL_GUID; +EFI_GUID gEfiDiskInfoProtocolGuid = EFI_DISK_INFO_PROTOCOL_GUID; +EFI_GUID gEfiEventLegacyBootGuid = EFI_EVENT_LEGACY_BOOT_GUID; + +//--------------------------------------------------------------------------- + +// +//--------------------------------------------------------------------------- +// +// Name: IsSataDeviceInAhciMode +// +// Description: Check input BBS device is a SATA DEVICE in AHCI mode. +// +// Input: BBS_TABLE* - Pointer to an entry in BBS table +// +// Output: UINT8 TRUE - It is a SATA device and in AHCI mode +// FALSE - It is not a SATA device or not in AHCI mode +// +//--------------------------------------------------------------------------- +// + +UINT8 +IsSataDeviceInAhciMode ( + IN BBS_TABLE *BbsEntry +) +{ + + if((BbsEntry->DeviceType == BBS_HARDDISK || BbsEntry->DeviceType == BBS_CDROM)) { + if(BbsEntry->Class == MASS_STORAGE || BbsEntry->SubClass == AHCI_CONTROLLER ){ + return TRUE; + } + } + + return FALSE; +} + +// +//--------------------------------------------------------------------------- +// +// Name: InitializeAhciI13Data +// +// Description: It initializes AHCI INT13 runtime data pointer (gAhciI13Data). +// +// Input: BBS_TABLE* - Pointer to an entry in BBS table +// +// Output: VOID +// +//--------------------------------------------------------------------------- +// + +VOID +InitializeAhciI13Data ( + IN BBS_TABLE *BbsEntry +) +{ + UINT16 StrSeg = 0, StrOff = 0; + UINT32 DevOutfitAddr = 0, DevOutfitStartAddr = 0; + UINT8 AInt13No = 0, DevNo = 0; + + if(!gAhciI13Data) { + // INT13 Drive number (0x80~0x8F) + AInt13No = (UINT8)(BbsEntry->InitPerReserved >> 8); + DevNo = AInt13No & 0x7F; // Drive index + + // Get address of drive description string i.e. AHCI_I13_RTDATA.DevOutfit[DevNo] + StrSeg = BbsEntry->DescStringSegment; + StrOff = BbsEntry->DescStringOffset; + DevOutfitAddr = (UINT32)((UINTN)StrSeg << 4) + (UINT32)StrOff; + + // Now get address of description string of 1st drive i.e. AHCI_I13_RTDATA.DevOutfit[0] + DevOutfitStartAddr = DevOutfitAddr - (sizeof(DEV_BBS_OUTFIT)*DevNo); + // Now get base address of AHCI_I13_RTDATA structure + gAhciI13Data = (AHCI_I13_RTDATA*)(DevOutfitStartAddr - EFI_FIELD_OFFSET(AHCI_I13_RTDATA, DevOutfit)); + } + + return; +} + +// +//--------------------------------------------------------------------------- +// +// Name: TransferAhciInt13SmmDataToSmm +// +// Description: It uses EFI_SMM_COMMUNICATION_PROTOCOL API to transfer data +// from Non-SMM mode to SMM mode. +// +// Input: VOID* - Pointer to data to be transfered +// UINTN - size of the data +// EFI_GUID* - Pointer to GUID identifier for the data +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +TransferAhciInt13SmmDataToSmm ( + IN VOID *pData, + IN UINTN DataSize, + IN EFI_GUID *pGuid +) +{ + EFI_SMM_COMMUNICATION_PROTOCOL *gSmmCommunication = NULL; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + UINT8 *CommunicateBuffer = NULL; + UINTN CommunicateBufferSize; + EFI_STATUS Status; + + if ( pData == NULL || DataSize == 0 || pGuid == NULL ) { + return EFI_INVALID_PARAMETER; + } + + // Calculate Size of Communication buffer + CommunicateBufferSize = (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) + DataSize; // Header size (without data) + data size + + // Allocate memory for Communication Buffer. + Status = pBS->AllocatePool( EfiBootServicesData, + CommunicateBufferSize, + (VOID**)&CommunicateBuffer ); + if ( EFI_ERROR( Status )) { + ASSERT_EFI_ERROR(Status); + return Status; + } + + // Copy SMM Communicate Header Here + SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommunicateBuffer; + + // Copy data GUID + pBS->CopyMem( &SmmCommunicateHeader->HeaderGuid, pGuid, sizeof( EFI_GUID ) ); + + // Updated data length + SmmCommunicateHeader->MessageLength = DataSize; + + // Copy Data Here + pBS->CopyMem( &SmmCommunicateHeader->Data, pData, DataSize ); + + // Locate EFI_SMM_COMMUNICATION_PROTOCOL + Status = pBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &gSmmCommunication); + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR(Status); + return Status; + } + + // Send data to SMM using protocol API + Status = gSmmCommunication->Communicate (gSmmCommunication, CommunicateBuffer, &CommunicateBufferSize); + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR(Status); + return Status; + } + + // Free memory allocated for Communication Buffer. + Status = pBS->FreePool(CommunicateBuffer); + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR(Status); + return Status; + } + + return EFI_SUCCESS; +} + +// +//--------------------------------------------------------------------------- +// +// Name: AmiLegacyBootNotify +// +// Description: This function will be called upon legacy boot event. It +// collects information about all AHCI devices present in the system and +// send it to SMM so that AHCI INT13 SMI handler can use it. +// Operation: +// 1. Locate EFI_LEGACY_BIOS_PROTOCOL and get All BBS entries and look +// for entry corresponding to a drive in AHCI mode +// 2. If a valid entry is found then it will use AHCI INT13 runtime +// data and AHCI bus interface data to fill data required by AHCI +// INT13 SMI handler. +// 3. This newly created data structure will be transfered to SMM using +// SmmCommunicationProtocol API. +// +// Input: EFI_EVENT - Event +// VOID* - Pointer to Context +// +// Output: VOID +// +//--------------------------------------------------------------------------- +// + +VOID +AmiLegacyBootNotify( + IN EFI_EVENT Event, + IN VOID *Context +) +{ + EFI_STATUS Status; + UINT16 HddCount = 0; + HDD_INFO *HddInfo = NULL; + BBS_TABLE *BbsTable = NULL; + UINT16 BbsCount = 0; + UINT8 DevNo = 0; + UINTN SegNum; + UINTN BusNum; + UINTN DevNum; + UINTN FuncNum; + UINT16 i = 0; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + EFI_DISK_INFO_PROTOCOL *DiskInfo = NULL; + SATA_DEVICE_INTERFACE *SataDevInterface = NULL; + SMM_AINT13_DRIVE_INFO *pDriveInfo = NULL; + AHCI_INT13_SMM_DATA *AhciInt13SmmData = NULL; + + // Run this function only once + pBS->CloseEvent(Event); + + // Locate EFI_LEGACY_BIOS_PROTOCOL + Status = pBS->LocateProtocol( &gEfiLegacyBiosProtocolGuid, + NULL, + &LegacyBios); + if (EFI_ERROR(Status)) { + return; + } + + // Get BBS_TABLE + Status = LegacyBios->GetBbsInfo( LegacyBios, + &HddCount, + &HddInfo, + &BbsCount, + &BbsTable); + if (EFI_ERROR(Status)) { + return; + } + + // Allocate Memory for AhciInt13SmmData buffer. + Status = pBS->AllocatePool( EfiBootServicesData, + sizeof(AHCI_INT13_SMM_DATA), + (VOID**)&AhciInt13SmmData ); + if ( EFI_ERROR( Status )) { + ASSERT_EFI_ERROR(Status); + return; + } + + // Initialize drive count to 0 + AhciInt13SmmData->DriveCount = 0; + + // Loop through all BBS entries + for (i = 0; i < BbsCount; i++) { + + // Process if this BDS entry is corresponding to a HDD in AHCI mode + if (IsSataDeviceInAhciMode(&BbsTable[i])) { + + // NOTE: We don't need EFI_DISK_INFO_PROTOCOL this is just to get SATA_DEVICE_INTERFACE structure. + Status = pBS->HandleProtocol ( (EFI_HANDLE)BbsTable[i].IBV1, &gEfiDiskInfoProtocolGuid, &DiskInfo ); + if(EFI_ERROR(Status)) { + continue; // Goto next BBS entry + } + SataDevInterface = ((SATA_DISK_INFO *)DiskInfo)->SataDevInterface; + + // Fill data in AhciInt13SmmData + pDriveInfo = &(AhciInt13SmmData->DriveInfo[AhciInt13SmmData->DriveCount]); + pDriveInfo->DriveNum = (UINT8)(BbsTable[i].InitPerReserved >> 8); + pDriveInfo->PMPortNum = SataDevInterface->PMPortNumber; + pDriveInfo->PortNum = SataDevInterface->PortNumber; + SataDevInterface->AhciBusInterface->PciIO->GetLocation( + SataDevInterface->AhciBusInterface->PciIO, + &SegNum, &BusNum, &DevNum, &FuncNum + ); + pDriveInfo->BusNo = (UINT8)BusNum; + pDriveInfo->DevNo = (UINT8)DevNum; + pDriveInfo->FuncNo = (UINT8)FuncNum; + pDriveInfo->DeviceType = SataDevInterface->DeviceType; + if(pDriveInfo->DeviceType == ATAPI) { + pDriveInfo->Lun = SataDevInterface->AtapiDevice->Lun; + pDriveInfo->BlockSize = SataDevInterface->AtapiDevice->BlockSize; + } else { + // Initialize AHCI INT13 runtime data + if(!gAhciI13Data) { + InitializeAhciI13Data(&BbsTable[i]); + } + // Get drive index in device parameter array of gAhciI13Data + DevNo = pDriveInfo->DriveNum & 0x7F; + + // Fill the information using gAhciI13Data + pDriveInfo->wMAXCYL = gAhciI13Data->DevParam[DevNo].wMAXCYL; + pDriveInfo->bMAXHN = gAhciI13Data->DevParam[DevNo].bMAXHN; + pDriveInfo->bMAXSN = gAhciI13Data->DevParam[DevNo].bMAXSN; + pDriveInfo->wLBACYL = gAhciI13Data->DevParam[DevNo].wLBACYL; + pDriveInfo->bLBAHD = gAhciI13Data->DevParam[DevNo].bLBAHD; + pDriveInfo->bLBASPT = gAhciI13Data->DevParam[DevNo].bLBASPT; + } + pDriveInfo->RCommand = SataDevInterface->ReadCommand; + pDriveInfo->WCommand = SataDevInterface->WriteCommand; + + AhciInt13SmmData->DriveCount += 1; // Update drive count + } + } + + // Save AhciInt13SmmData in SMM + if(AhciInt13SmmData->DriveCount != 0) { + Status = TransferAhciInt13SmmDataToSmm ( AhciInt13SmmData, sizeof(AHCI_INT13_SMM_DATA), &gAint13SmmDataGuid ); + } + + // Free the Memory Allocated for AhciInt13SmmData Buffer. + Status = pBS->FreePool(AhciInt13SmmData); + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR(Status); + return; + } +} + +// +//--------------------------------------------------------------------------- +// +// Name: AhciInt13DxeEntry +// +// Description: This is entry point function. It registers a call back function +// for Legacy boot event. +// +// Input: EFI_HANDLE - Standard EFI Image handle +// EFI_SYSTEM_TABLE* - Pointer to System Table +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +AhciInt13DxeEntry( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + InitAmiLib(ImageHandle, SystemTable); + + Status = pBS->CreateEventEx ( + EFI_EVENT_NOTIFY_SIGNAL, + TPL_CALLBACK, + AmiLegacyBootNotify, + NULL, + &gEfiEventLegacyBootGuid, + &Event + ); + + return Status; +} +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AhciInt13Dxe.dxs b/Core/EM/Ahci/AhciInt13Dxe.dxs new file mode 100644 index 0000000..8223f9b --- /dev/null +++ b/Core/EM/Ahci/AhciInt13Dxe.dxs @@ -0,0 +1,51 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Dxe.dxs 1 11/25/14 12:09a Kapilporwal $Revision: +// +// $Date: 11/25/14 12:09a $Log: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Dxe.dxs $ +// +// +// +//**************************************************************************** + +// +//**************************************************************************** +// +// Name: AhciInt13Dxe.dxs +// +// Description: +// Dependency expression for the AhciInt13Dxe component +//**************************************************************************** +// + +#include + +DEPENDENCY_START + EFI_SMM_COMMUNICATION_PROTOCOL_GUID +DEPENDENCY_END + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** \ No newline at end of file diff --git a/Core/EM/Ahci/AhciInt13Smm.c b/Core/EM/Ahci/AhciInt13Smm.c new file mode 100644 index 0000000..8715bce --- /dev/null +++ b/Core/EM/Ahci/AhciInt13Smm.c @@ -0,0 +1,1157 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Smm.c 2 12/08/14 5:39a Anbuprakashp $Revision: +// +// $Date: 12/08/14 5:39a $Log: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Smm.c $ +// +// +// +//**************************************************************************** + +// +//**************************************************************************** +// +// Name: AhciInt13Smm.C +// +// Description: This file contains code for SMI handler for AHCI INT13. +//**************************************************************************** +// + +#include +#include +#include + +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION>=0x4028B) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AhciInt13Smm.h" + +EFI_SMM_CPU_PROTOCOL *gSmmCpuProtocol = NULL; +AHCI_BUS_SMM_PROTOCOL *gAhciBusSmmProtocol = NULL; +DLIST gDriveInfoList; +EFI_GUID gAint13SmmDataGuid = AHCI_INT13_SMM_DATA_GUID; +EFI_GUID gAhciSmmProtocolGuid = AHCI_SMM_PROTOCOL_GUID; +EFI_GUID gEfiSmmCpuProtocolGuid = EFI_SMM_CPU_PROTOCOL_GUID; +EFI_GUID gEfiSmmSwDispatch2ProtocolGuid = EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID; +UINT64 PciExpressBaseAddress = 0; +UINT8 *gBuffer = NULL; +#endif + +// +//---------------------------------------------------------------------- +// Procedure: AhciMmioRead +// +// Description: Read from AHCI MMIO address +// +// Input: IN UINT32 - AHCI MMIO address +// +// Output: OUT UINT32 - Value read from AHCI MMIO address +// +//---------------------------------------------------------------------- +// + +EFI_STATUS +AhciMmioRead ( + IN UINT32 AhciMmioAddress, + OUT UINT32 *ReadValue +) +{ + EFI_STATUS Status; + // Validate AhciBaseAddress is valid MMIO address and not reside in SMRAM region + Status = AmiValidateMmioBuffer( (VOID*)AhciMmioAddress, 4 ); + if( EFI_ERROR(Status) ) { + return Status; + } + + *ReadValue = *(UINT32*)(AhciMmioAddress); + return Status; +} + +// +//---------------------------------------------------------------------- +// Procedure: AhciMmioWrite +// +// Description: Write to the AHCI MMIO Address +// +// Input: IN UINT32 - AHCI MMIO address +// IN UINT32 - Value to be written +// +// Output: EFI_STATUS - EFI_NOT_FOUND: Invalid address, EFI_SUCCESS: Success +// +//---------------------------------------------------------------------- +// + +EFI_STATUS +AhciMmioWrite ( + IN UINT32 AhciMmioAddress, + IN UINT32 WriteValue +) +{ + EFI_STATUS Status; + + // Validate AhciBaseAddress is valid MMIO address and not reside in SMRAM region + Status = AmiValidateMmioBuffer( (VOID*)AhciMmioAddress, 4 ); + if( EFI_ERROR(Status) ) { + return Status; + } + + *(UINT32*)(AhciMmioAddress) = WriteValue; + return Status; +} + +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION>=0x4028B) + +//--------------------------------------------------------------------------- + +// +//--------------------------------------------------------------------------- +// +// Name: Is48BitCommand +// +// Description: Check if input command is a LBA48 command +// +// Input: UINT8 - Command +// +// Output: BOOLEAN - TRUE - LBA48 command +// FALSE - Not a LBA48 command +// +//--------------------------------------------------------------------------- +// + +BOOLEAN +Is48BitCommand ( + IN UINT8 Command + ) +{ + if ( Command == READ_SECTORS_EXT || + Command == READ_MULTIPLE_EXT || + Command == WRITE_SECTORS_EXT || + Command == WRITE_MULTIPLE_EXT || + Command == READ_DMA_EXT || + Command == WRITE_DMA_EXT ) + return TRUE; + else + return FALSE; +} + +// +//--------------------------------------------------------------------------- +// +// Name: IsDmaCommand +// +// Description: Check if input command is a DMA command +// +// Input: UINT8 - Command +// +// Output: BOOLEAN - TRUE - DMA command +// FALSE - Not a DMA command +// +//--------------------------------------------------------------------------- +// + +BOOLEAN +IsDmaCommand ( + IN UINT8 Command + ) +{ + if ( Command == READ_DMA || + Command == READ_DMA_EXT || + Command == WRITE_DMA || + Command == WRITE_DMA_EXT ) + return TRUE; + else + return FALSE; +} + +// +//--------------------------------------------------------------------------- +// +// Name: CheckErrorCode +// +// Description: It maps EFI_STATUS code to corresponding INT13 error code +// +// Input: EFI_STATUS - Status +// +// Output: UINT8 - INT13 error code +// +//--------------------------------------------------------------------------- +// + +UINT8 +CheckErrorCode ( + IN EFI_STATUS Status + ) +{ + switch(Status){ + case EFI_SUCCESS: + return 0x0; // successful completion + break; + case EFI_INVALID_PARAMETER: + return 0x01; // invalid function in AH or invalid parameter + break; + case EFI_UNSUPPORTED: + return 0x01; // invalid function in AH or invalid parameter + break; + case EFI_NOT_READY: + return 0xAA; // drive not ready (hard disk) + break; + case EFI_DEVICE_ERROR: + return 0xE0; // status register error (hard disk) + break; + case EFI_WRITE_PROTECTED: + return 0x03; // disk write-protected + break; + case EFI_NO_MEDIA: + return 0x31; // no media in drive (IBM/MS INT 13 extensions) + break; + case EFI_MEDIA_CHANGED: + return 0x06; // disk changed + break; + case EFI_NOT_FOUND: + return 0x01; // invalid function in AH or invalid parameter + break; + case EFI_ACCESS_DENIED: + return 0xB6; // volume present but read protected (INT 13 extensions) + break; + case EFI_TIMEOUT: + return 0x80; // timeout (not ready) + break; + case EFI_ABORTED: + return 0xBB; // undefined error (hard disk) + break; + default: + break; + } + return 0xBB; +} + +// +//--------------------------------------------------------------------------- +// +// Name: GetDriveInfoByDriveNum +// +// Description: It returns the drive information corresponding to input drive +// number, if found. +// +// Input: IN UINT8 - INT13 drive number +// IN OUT VOID** - Pointer to SMM_AINT13_DRIVE_INFO variable +// It will be filled with corresponding drive +// information +// +// Output: EFI_STATUS +// EFI_SUCCESS - DriveInfo is valid +// EFI_UNSUPPORTED - Can't find the corresponding data. +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +GetDriveInfoByDriveNum( + IN UINT8 DriveNum, + IN OUT VOID **DriveInfo +) +{ + DLINK *DriveInfoLink = NULL; + SMM_AINT13_DRIVE_INFO *pDriveInfo = NULL; + + // Look for drive information corresponding to DriveNum in gDriveInfoList + DriveInfoLink = gDriveInfoList.pHead; + for(;DriveInfoLink;DriveInfoLink=DriveInfoLink->pNext){ + pDriveInfo = OUTTER(DriveInfoLink, dLink, SMM_AINT13_DRIVE_INFO); + if(DriveNum == pDriveInfo->DriveNum) { + // Return the information if found, also set status as success + *DriveInfo = pDriveInfo; + return EFI_SUCCESS; + } + } + + // No drive information corresponding to DriveNum in gDriveInfoList + return EFI_UNSUPPORTED; +} + +// +//--------------------------------------------------------------------------- +// +// Name: ProcessInt13Function +// +// Description: Worker function to service AHCI INT13 request. Currently it +// supports Read/Write function only. +// Operation: +// 1. Parse information passed as IA registers to parameter required +// by AMI_AHCI_BUS_SMM_PROTOCOL APIs. +// 2. Call appropriate AMI_AHCI_BUS_SMM_PROTOCOL API. +// +// Input: EFI_IA32_REGISTER_SET* - Pointer of EFI_IA32_REGISTER_SET +// +// Output: EFI_STATUS +// EFI_SUCCESS - Int13 request complete +// EFI_UNSUPPORTED - This Int13 request is unsupported +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +ProcessInt13Function( + IN EFI_IA32_REGISTER_SET *ExRegs +) +{ + EFI_STATUS Status; + BOOLEAN IsSupported = TRUE; + VOID *Buffer = NULL; + UINT8 *BufferBackup = NULL; + UINT32 ByteCount = 0; + UINT16 SectorCount = 0; + UINT8 Command = 0; + EFI_LBA Lba = 0; + UINT16 SkipBytesBefore = 0, SkipBytesAfter = 0; + UINT16 Header = 0, Cylinder = 0, Sector = 0; + UINT8 ReadWrite = 0; // 0 : read, 1: write + UINT8 *UserBuf = NULL; + UINT64 bAhciBaseAddress = 0; + UINTN i = 0; + UINT16 BlksPerTransfer; + VOID *AhciBuffer; + BOOLEAN UnalignedTransfer = FALSE; + DISK_ADDRESS_PACKAGE *Package = NULL; + SMM_AINT13_DRIVE_INFO *pDriveInfo = NULL; + COMMAND_STRUCTURE CommandStructure; + + // Get drive information based on drive number + Status = GetDriveInfoByDriveNum(ExRegs->H.DL,&pDriveInfo); + + if(!EFI_ERROR(Status)){ + if(pDriveInfo->DeviceType == ATA) { + // Calculate AHCI parameter to be filled in COMMAND_STRUCTURE based on INT13 function + if(ExRegs->H.AH == READ_SECTOR || ExRegs->H.AH == EXT_READ){ + Command = pDriveInfo->RCommand; + ReadWrite = 0; // read + }else if(ExRegs->H.AH == WRITE_SECTOR || ExRegs->H.AH == EXT_WRITE){ + Command = pDriveInfo->WCommand; + ReadWrite = 1; // write + } + switch(ExRegs->H.AH){ + case READ_SECTOR: + case WRITE_SECTOR: + Cylinder = ((UINT16)(ExRegs->H.CL & 0xC0 ) << 2) +ExRegs->H.CH; // cylinder: bit 6-7(CL) + CH + Header = (UINT16)ExRegs->H.DH; // header : DH + Sector = (UINT16)(ExRegs->H.CL & 0x3F); // sector : bit 0-5(CL) + Lba = (Cylinder*(pDriveInfo->bMAXHN) + Header) * (pDriveInfo->bMAXSN) + Sector - 1; + SectorCount = ExRegs->H.AL; + Buffer = (VOID*)(((ExRegs->X.ES) << 4 ) + ExRegs->X.BX); + ByteCount = SectorCount*HDD_BLOCK_SIZE; + break; + case EXT_READ: + case EXT_WRITE: + Package = (DISK_ADDRESS_PACKAGE*)(((ExRegs->X.DS) << 4 ) + ExRegs->X.SI); + Lba = Package->StartLba; + SectorCount = Package->XferSector; + Buffer = (VOID*)(((Package->Buffer >> 16 & 0xFFFF) << 4) + (UINT16)Package->Buffer); + ByteCount = SectorCount*HDD_BLOCK_SIZE; + break; + default: + IsSupported = FALSE; + break; + } + } else if(pDriveInfo->DeviceType == ATAPI){ // Only read command support is required + Command = pDriveInfo->RCommand; + ReadWrite = 0; // read + Buffer = (VOID*)((((ExRegs->E.EDI) >> 16 & 0xFFFF) << 4) + (UINT16)(ExRegs->E.EDI)); + Lba = ExRegs->E.EAX; + SectorCount = ExRegs->X.CX; // CX + SkipBytesAfter = ((ExRegs->E.ECX) >> 24) * 512; // CH+ (Higher byte of higher word of ECX) + SkipBytesBefore = (((ExRegs->E.ECX) >> 16) & 0xFF) * 512; // CL+ (Lower byte of higher word of ECX) + ByteCount = SectorCount * pDriveInfo->BlockSize; // 2048 + if(SkipBytesBefore || SkipBytesAfter) { + Status = pSmst->SmmAllocatePool(EfiRuntimeServicesData, sizeof(UINT8)*(SkipBytesBefore + SkipBytesAfter), &BufferBackup); + if (EFI_ERROR(Status)) { + ASSERT(TRUE); + IsSupported = FALSE; + } else { + // Backup bytes to be preserved. + for(i = 0;i<(SkipBytesBefore + SkipBytesAfter);i++) { + BufferBackup[i] = *(((UINT8*)Buffer)+i + (ByteCount - SkipBytesBefore - SkipBytesAfter)); + } + } + } + } else { + IsSupported = FALSE; + } + } // if(!EFI_ERROR(Status)) + else { + IsSupported = FALSE; + } + + if(IsSupported){ + // Backup AHCI base address from gAhciBusSmmProtocol + bAhciBaseAddress = gAhciBusSmmProtocol->AhciBaseAddress; + + // Save current AHCI base address from AHCI controller. + gAhciBusSmmProtocol->AhciBaseAddress = *(UINT32*)PCI_CFG_ADDR(pDriveInfo->BusNo, pDriveInfo->DevNo, pDriveInfo->FuncNo, PCI_ABAR); + + BlksPerTransfer = SectorCount; + AhciBuffer = Buffer; + + //If Buffer isn't aligned use internal buffer + if(((UINT32)Buffer) & 0x1) { + BlksPerTransfer = 1; + AhciBuffer = gBuffer; + UnalignedTransfer = TRUE; + } + + if(pDriveInfo->DeviceType == ATA) { + ByteCount = BlksPerTransfer * HDD_BLOCK_SIZE; + } else if(pDriveInfo->DeviceType == ATAPI){ + ByteCount = BlksPerTransfer * pDriveInfo->BlockSize; + } + + UserBuf = (UINT8*)Buffer; + + for ( ; SectorCount; SectorCount -= BlksPerTransfer){ + + if (ReadWrite == 1 && UnalignedTransfer) { + for(i = 0; i < ByteCount; i++) { + *(((UINT8*)AhciBuffer)+i) = *(((UINT8*)Buffer)+i); + } + } + + // clear Command structure + MemSet (&CommandStructure, sizeof(COMMAND_STRUCTURE), 0); + + // Fill CommandStructure buffer. + CommandStructure.Buffer = AhciBuffer; + CommandStructure.ByteCount = ByteCount; + if(pDriveInfo->DeviceType == ATA) { // ATA + CommandStructure.Features = 0; + CommandStructure.FeaturesExp = 0; + CommandStructure.SectorCount = BlksPerTransfer; + CommandStructure.LBALow = (UINT8)Lba; + CommandStructure.LBAMid = (UINT8) (((UINT32)Lba >>8) & 0xff); + CommandStructure.LBAHigh = (UINT8) (((UINT32)Lba >>16) & 0xff); + if(Is48BitCommand(Command)){ // if support LBA48 feature? + CommandStructure.LBALowExp = (UINT8) (UINT8)Shr64(Lba,24); + CommandStructure.LBAMidExp = (UINT8) (UINT8)Shr64(Lba,32); + CommandStructure.LBAHighExp = (UINT8) (UINT8)Shr64(Lba,40); + CommandStructure.Device = 0x40; // LBA48 + }else{ + CommandStructure.Device = ((UINT8)Shr64(Lba,24) & 0x0f) | 0x40; // LBA28 + } + CommandStructure.Command = Command; + CommandStructure.Control = 0; + } else if(pDriveInfo->DeviceType == ATAPI) { + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] = Command; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[1] = pDriveInfo->Lun << 5; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[2] = (UINT8)(((UINT32) Lba) >> 24); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[3] = (UINT8)(((UINT32) Lba) >> 16); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[4] = (UINT8)(((UINT16) Lba) >> 8); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[5] = (UINT8)(((UINT8) Lba) & 0xff); + CommandStructure.AtapiCmd.Ahci_Atapi_Command[7] = (UINT8) (BlksPerTransfer >> 8); // MSB + CommandStructure.AtapiCmd.Ahci_Atapi_Command[8] = (UINT8) (BlksPerTransfer & 0xff); // LSB + } + + // Send ATA/ATAPI command in AHCI mode + if(pDriveInfo->DeviceType == ATA) { // ATA + if(IsDmaCommand(Command)) { + Status = gAhciBusSmmProtocol->AhciSmmExecuteDmaDataCommand( gAhciBusSmmProtocol, + &CommandStructure, + pDriveInfo->PortNum, + pDriveInfo->PMPortNum, + pDriveInfo->DeviceType, + ReadWrite); + } else { + Status = gAhciBusSmmProtocol->AhciSmmExecutePioDataCommand( gAhciBusSmmProtocol, + &CommandStructure, + pDriveInfo->PortNum, + pDriveInfo->PMPortNum, + pDriveInfo->DeviceType, + ReadWrite); + } + } else { // ATAPI + Status = gAhciBusSmmProtocol->AhciSmmExecutePacketCommand( gAhciBusSmmProtocol, + &CommandStructure, + ReadWrite, + pDriveInfo->PortNum, + pDriveInfo->PMPortNum, + pDriveInfo->DeviceType); + } + + if (EFI_ERROR(Status)) { + break; + } + + if (ReadWrite == 0 && UnalignedTransfer) { + for(i = 0; i < ByteCount; i++) { + *(((UINT8*)Buffer)+i) = *(((UINT8*)AhciBuffer)+i); + } + } + + (UINTN)Buffer = (UINTN)Buffer + ByteCount; + Lba += BlksPerTransfer; + + } + + Buffer = UserBuf; + + // Restore base address to gAhciBusSmmProtocol + gAhciBusSmmProtocol->AhciBaseAddress = bAhciBaseAddress; + + if(pDriveInfo->DeviceType == ATAPI){ + // fill output buffer with requested data only. + if(SkipBytesBefore || SkipBytesAfter) { + UserBuf = (UINT8*)Buffer; + // Move requested data at start of the buffer + if(SkipBytesBefore != 0) + for(i = 0;iSmmFreePool(BufferBackup); + } + } + + // update return register data whatever success or error!! + if(!EFI_ERROR(Status)){ + // AHCI success + ExRegs->X.Flags.CF = 0x0; // clear if successful + ExRegs->H.AH = CheckErrorCode(Status); // successful completion + } + else{ + // AHCI error + ExRegs->X.Flags.CF = 0x1; // set on error + ExRegs->H.AH = CheckErrorCode(Status); // return error code + } + } + + // return EFI_SUCCESS: Int13 request is complete. + // return EFI_UNSUPPORTED: This function isn't supported by this routine. + return (IsSupported)? EFI_SUCCESS : EFI_UNSUPPORTED; +} + +// +//--------------------------------------------------------------------------- +// +// Name: AhciInt13SmiHandler +// +// Description: This is the SWSMI handler to service AHCI INT13 request. +// Operation: +// 1. Take INT13 parameters stored on real mode stack from CPU save state. +// 2. Call a sub-function to process INT13 request. +// 3. Update output parameters (IA registers) on real mode stack. +// +// Input: UINTN - Index of CPU which triggered SW SMI +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +AhciInt13SmiHandler ( + IN UINTN CpuIndex +) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT16 StackSegment = 0; + UINT16 StackOffset = 0; + EFI_IA32_REGISTER_SET ExRegs; + INT13_TO_SMI_EXREGS *Int13ToSmiExRegs = NULL; +TRACE((-1, "\nKAPIL: AhciInt13SmiHandler.")); + // Read SS/ESP from CPU save state + gSmmCpuProtocol->ReadSaveState ( gSmmCpuProtocol, + 2, + EFI_SMM_SAVE_STATE_REGISTER_RSP, + CpuIndex, + &StackOffset ); + + gSmmCpuProtocol->ReadSaveState ( gSmmCpuProtocol, + 2, + EFI_SMM_SAVE_STATE_REGISTER_SS, + CpuIndex, + &StackSegment ); + + // Get base address of real mode stack + Int13ToSmiExRegs = (INT13_TO_SMI_EXREGS*)(((StackSegment << 4) + StackOffset) + 2); + + MemSet (&ExRegs, sizeof(EFI_IA32_REGISTER_SET), 0); + + // Initialize the SMM THUNK registers + ExRegs.E.EAX = Int13ToSmiExRegs->StackEAX; + ExRegs.E.EBX = Int13ToSmiExRegs->StackEBX; + ExRegs.E.ECX = Int13ToSmiExRegs->StackECX; + ExRegs.E.EDX = Int13ToSmiExRegs->StackEDX; + ExRegs.E.EDI = Int13ToSmiExRegs->StackEDI; + ExRegs.E.ESI = Int13ToSmiExRegs->StackESI; + ExRegs.E.EBP = Int13ToSmiExRegs->StackEBP; + ExRegs.E.DS = Int13ToSmiExRegs->StackDS; + ExRegs.E.ES = Int13ToSmiExRegs->StackES; + ExRegs.E.FS = Int13ToSmiExRegs->StackFS; + ExRegs.E.GS = Int13ToSmiExRegs->StackGS; + ExRegs.X.Flags = Int13ToSmiExRegs->StackFlags; + + if(gAhciBusSmmProtocol && gDriveInfoList.pHead){ + // Execute Int13 function by AhciSmmProtocol and update ExRegs for return caller. + // Note: Function will return non-EFI_SUCCESS value if Int13 function isn't + // supported by ProcessInt13Function(). + Status = ProcessInt13Function(&ExRegs); + } + + // Update the registers before go back caller. + Int13ToSmiExRegs->StackEAX = ExRegs.E.EAX; + Int13ToSmiExRegs->StackEBX = ExRegs.E.EBX; + Int13ToSmiExRegs->StackECX = ExRegs.E.ECX; + Int13ToSmiExRegs->StackEDX = ExRegs.E.EDX; + Int13ToSmiExRegs->StackEDI = ExRegs.E.EDI; + Int13ToSmiExRegs->StackESI = ExRegs.E.ESI; + Int13ToSmiExRegs->StackEBP = ExRegs.E.EBP; + Int13ToSmiExRegs->StackDS = ExRegs.E.DS; + Int13ToSmiExRegs->StackES = ExRegs.E.ES; + Int13ToSmiExRegs->StackFS = ExRegs.E.FS; + Int13ToSmiExRegs->StackGS = ExRegs.E.GS; + Int13ToSmiExRegs->StackFlags = ExRegs.X.Flags; + + return Status; +} + +// +//---------------------------------------------------------------------- +// Procedure: AhciMmioSmiHandler +// +// Description: SMI handler for the AHCI_MMIO_SWSMI SW SMI +// +// Input: IN UINTN - Index of CPU which triggered SW SMI +// IN UINT32 - 1/2: Read or Write MMIO operation +// +// Output: EFI_STATUS - EFI_SUCCESS +// +//---------------------------------------------------------------------- +// + +EFI_STATUS +AhciMmioSmiHandler ( + IN UINTN CpuIndex, + IN UINT32 FunctionNo +) +{ + EFI_STATUS Status; + UINT32 AhciMmioAddress; + UINT32 WriteValue; + UINT32 ReadValue; + UINT32 ReturnStatus = 0x0FF; + + gSmmCpuProtocol->ReadSaveState (gSmmCpuProtocol, + 4, + EFI_SMM_SAVE_STATE_REGISTER_RSI, + CpuIndex, + &AhciMmioAddress ); + + + if(FunctionNo == 1) { + Status=AhciMmioRead(AhciMmioAddress, &ReadValue); + + if(!EFI_ERROR(Status)) { + gSmmCpuProtocol->WriteSaveState(gSmmCpuProtocol, + 4, + EFI_SMM_SAVE_STATE_REGISTER_RAX, + CpuIndex, + &ReadValue); + ReturnStatus = 0; // Update success + } + + gSmmCpuProtocol->WriteSaveState(gSmmCpuProtocol, + 4, + EFI_SMM_SAVE_STATE_REGISTER_RCX, + CpuIndex, + &ReturnStatus); + + } else if(FunctionNo == 2) { + + gSmmCpuProtocol->ReadSaveState (gSmmCpuProtocol, + 4, + EFI_SMM_SAVE_STATE_REGISTER_RBX, + CpuIndex, + &WriteValue ); + + Status = AhciMmioWrite(AhciMmioAddress, WriteValue); + + if(!EFI_ERROR(Status)) { + ReturnStatus = 0; // Update success + } + + gSmmCpuProtocol->WriteSaveState(gSmmCpuProtocol, + 4, + EFI_SMM_SAVE_STATE_REGISTER_RCX, + CpuIndex, + &ReturnStatus); + } else { + // Invalid function number, return Error(i.e. ReturnStatus==0xFF) + gSmmCpuProtocol->WriteSaveState(gSmmCpuProtocol, + 4, + EFI_SMM_SAVE_STATE_REGISTER_RCX, + CpuIndex, + &FunctionNo); + } + + return EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------- +// Procedure: AhciCommonSmmHandler +// +// Description: Common SMI handler for AHCI INT13 SMIs +// +// Input: IN EFI_HANDLE - EFI Handle +// IN VOID* - Pointer to the EFI_SMM_SW_REGISTER_CONTEXT +// IN VOID* - Pointer to Communication data +// IN UINTN* - Pointer to size of Communication data +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------- +// + +EFI_STATUS +AhciCommonSmmHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINTN CpuIndex = (UINTN)-1; + UINT32 FunctionNo = 0; + + // Get CPU number of CPU which generated this SWSMI + if (CommBuffer != NULL && CommBufferSize != NULL) { + CpuIndex = ((EFI_SMM_SW_CONTEXT*)CommBuffer)->SwSmiCpuIndex; + } + + // Return if CPU number is invalid + if(CpuIndex == (UINTN)-1) return Status; + + // Read ECX from CPU save state + gSmmCpuProtocol->ReadSaveState ( gSmmCpuProtocol, + 4, + EFI_SMM_SAVE_STATE_REGISTER_RCX, + CpuIndex, + &FunctionNo ); + + switch(FunctionNo) { + case 0x1: + case 0x2: + Status = AhciMmioSmiHandler(CpuIndex, FunctionNo); + break; + + case 0x3: + Status = AhciInt13SmiHandler(CpuIndex); + break; + + default: + // Invalid Function. Return Error. + FunctionNo = 0xFF; + gSmmCpuProtocol->WriteSaveState(gSmmCpuProtocol, + 4, + EFI_SMM_SAVE_STATE_REGISTER_RCX, + CpuIndex, + &FunctionNo); + Status = EFI_UNSUPPORTED; + break; + } + + return Status; +} + +// +//---------------------------------------------------------------------- +// Procedure: GetAhciInt13SmmData +// +// Description: Saves AINT13 information passed from Non-SMM mode using +// EFI_SMM_COMMUNICATION_PROTOCOL API. This is required for below reason: +// 1)AhciSmmProtocol use port number, but Int13 service uses drive number. +// 2)AhciSmmProtocol use LBA addressing on HDD, but Int13 Read/Write function +// uses Cylinder, Header and Sector addressing on HDD. +// +// Input: IN EFI_HANDLE - EFI Handle +// IN VOID* - Pointer to the EFI_SMM_SW_REGISTER_CONTEXT +// IN VOID* - Pointer to Communication data +// IN UINTN* - Pointer to size of Communication data +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------- +// + +EFI_STATUS +GetAhciInt13SmmData ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL +) +{ + EFI_STATUS Status; + UINTN i = 0, j = 0; + AHCI_INT13_SMM_DATA *AhciInt13SmmData = NULL; + SMM_AINT13_DRIVE_INFO *pDriveInfo = NULL; + SMM_AINT13_DRIVE_INFO *pSmmDriveInfo = NULL; + + // Confirm that communication buffer contains required data + AhciInt13SmmData = (AHCI_INT13_SMM_DATA *)CommBuffer; + if (!AhciInt13SmmData || AhciInt13SmmData->DriveCount == 0) { + return EFI_SUCCESS; + } + + // Save all information from AhciInt13SmmData to gDriveInfoList + for(j=0;jDriveCount;j++){ + + // Allocate SMM memory + Status = pSmst->SmmAllocatePool(EfiRuntimeServicesData, sizeof(SMM_AINT13_DRIVE_INFO), &pSmmDriveInfo); + if (EFI_ERROR(Status)) { + continue; + } + // Copy all data + pDriveInfo = &(AhciInt13SmmData->DriveInfo[j]); + for(i=0;idLink); + } + + // Locate AMI_AHCI_BUS_SMM_PROTOCOL + if(gAhciBusSmmProtocol == NULL) { + gAhciBusSmmProtocol = (AHCI_BUS_SMM_PROTOCOL*) GetSmstConfigurationTablePi(&gAhciSmmProtocolGuid); + } + + return EFI_SUCCESS; +} + +// +//--------------------------------------------------------------------------- +// +// Name: AhciInt13SmmEntry +// +// Description: Driver entry point function. It does following tasks: +// 1. Initializes global variables (gDriveInfoList, PciExpressBaseAddress etc.) +// 2. Register SMI handler to get information passed through SmmCommunicationProtocol API. +// 3. Register SW SMI handler to process AHCI INT13 requests. +// 4. Locate EFI_SMM_CPU_PROTOCOL for Read/Write from/to CPU save state +// +// Input: EFI_HANDLE - Standard EFI Image handle +// EFI_SYSTEM_TABLE* - Pointer to System Table +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +AhciInt13SmmEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch2; + EFI_SMM_SW_REGISTER_CONTEXT AhciInt13SwSmiContext = {AHCI_INT13_SMM_SWSMI_VALUE}; + EFI_HANDLE AhciInt13SmmHandle; + EFI_HANDLE AhciInt13SmmDataHandle; + + InitAmiSmmLibPi(ImageHandle, SystemTable); + + InitAmiBufferValidationLib( ImageHandle, SystemTable ); + + // Initialize global drive info list + DListInit(&gDriveInfoList); + + // Get the PCI Express Base Address from the PCD + PciExpressBaseAddress = PCIEX_BASE_ADDRESS; + + // Return error if PSmstPi is NULL + if(pSmmBasePi == NULL || pSmstPi == NULL) { + ASSERT(TRUE); + return EFI_NOT_FOUND; + } + + // Register SMI handler to save AHCI_INT13_SMM_DATA passed from DXE through SmmCommunicationProtocol + Status = pSmstPi->SmiHandlerRegister( + (VOID *)GetAhciInt13SmmData, + &gAint13SmmDataGuid, + &AhciInt13SmmDataHandle + ); + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR(Status); + return Status; + } + + // Locate EFI_SMM_SW_DISPATCH2_PROTOCOL + Status = pSmstPi->SmmLocateProtocol( + &gEfiSmmSwDispatch2ProtocolGuid, + NULL, + &SwDispatch2 + ); + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR(Status); + return Status; + } + + // Register SMI handler to handle AHCI INT13 operations + Status = SwDispatch2->Register( + SwDispatch2, + AhciCommonSmmHandler, + &AhciInt13SwSmiContext, + &AhciInt13SmmHandle + ); + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR(Status); + return Status; + } + + // Locate EFI_SMM_CPU_PROTOCOL for Read/Write from/to CPU save state + Status = pSmstPi->SmmLocateProtocol( + &gEfiSmmCpuProtocolGuid, + NULL, + &gSmmCpuProtocol + ); + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR(Status); + return Status; + } + + // Use this buffer for unaligned read or write + Status = pBS->AllocatePages ( + AllocateAnyPages, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES(2048), // 512 for ATA and 2048 for ATAPI, so taking 2048 + (EFI_PHYSICAL_ADDRESS*)&(gBuffer)); + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR(Status); + return Status; + } + + return Status; +} + +// +//--------------------------------------------------------------------------- +// +// Name: AhciInt13SmmEntryPoint +// +// Description: Entry point function for both DXE and SMM driver. +// +// Input: EFI_HANDLE - Standard EFI Image handle +// EFI_SYSTEM_TABLE* - Pointer to System Table +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +AhciInt13SmmEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + + InitAmiLib(ImageHandle, SystemTable); + + Status = InitSmmHandler(ImageHandle, SystemTable, AhciInt13SmmEntry, AhciInt13DxeEntry); + + return Status; +} + +#else +#include +#include +#include +#include +#include + +EFI_GUID gEfiSmmSwDispatchProtocolGuid = EFI_SMM_SW_DISPATCH_PROTOCOL_GUID; +EFI_GUID gSwSmiCpuTriggerGuid = SW_SMI_CPU_TRIGGER_GUID; + +// +//---------------------------------------------------------------------------- +// Procedure: AhciMmioSmmSMIHandler +// +// Description: Smi handler for the AHCI_MMIO_SWSMI Sw Smi +// +// Input: DispatchHandle - EFI Handle +// DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT +// +// Output: +// +//---------------------------------------------------------------------------- +// + +VOID +AhciMmioSmmSMIHandler ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext +) +{ + UINTN Cpu = (UINTN)-1; + UINT32 FunctionNo; + UINT32 AhciBaseAddress; + UINT32 Value; + EFI_SMM_CPU_SAVE_STATE *pCpuSaveState; + SW_SMI_CPU_TRIGGER *SwSmiCpuTrigger; + UINTN i; + + for (i = 0; i < pSmst->NumberOfTableEntries; ++i) { + if (guidcmp(&pSmst->SmmConfigurationTable[i].VendorGuid,&gSwSmiCpuTriggerGuid) == 0) { + break; + } + } + + //If found table, check for the CPU that caused the software Smi. + if (i != pSmst->NumberOfTableEntries) { + SwSmiCpuTrigger = pSmst->SmmConfigurationTable[i].VendorTable; + Cpu = SwSmiCpuTrigger->Cpu; + } + + // Found Invalid CPU number, return + if(Cpu == (UINTN) -1) { + return ; + } + + pCpuSaveState = (EFI_SMM_CPU_SAVE_STATE*)pSmst->CpuSaveState; + + FunctionNo = pCpuSaveState[Cpu].Ia32SaveState.ECX; + AhciBaseAddress = pCpuSaveState[Cpu].Ia32SaveState.ESI; + + switch(FunctionNo) { + case 0x1: + Status=AhciMmioRead(AhciBaseAddress, &Value); + if( EFI_ERROR(Status) ) { + // Return Error. + pCpuSaveState[Cpu].Ia32SaveState.ECX = 0xFF; + break; + } + pCpuSaveState[Cpu].Ia32SaveState.EAX = Value; + pCpuSaveState[Cpu].Ia32SaveState.ECX = 0; + break; + + case 0x2: + + Status = AhciMmioWrite ( AhciBaseAddress, pCpuSaveState[Cpu].Ia32SaveState.EBX ); + if( EFI_ERROR(Status) ) { + // Return Error. + pCpuSaveState[Cpu].Ia32SaveState.ECX = 0xFF; + break; + } + pCpuSaveState[Cpu].Ia32SaveState.ECX = 0; + break; + default: + // Invalid Function. Return Error. + pCpuSaveState[Cpu].Ia32SaveState.ECX = 0xFF; + break; + } + + return; +} + +// +//--------------------------------------------------------------------------- +// +// Name: AhciMmioSmmInSmmFunction +// +// Description: Regsiter the AHCI_MMIO_SWSMI SMI +// +// Input: Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT +// EFI System Table - Pointer to System Table +// +// Output: EFI_STATUS OR EFI_NOT_FOUND +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +AhciMmioSmmInSmmFunction( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_HANDLE Handle; + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH_PROTOCOL *pSwDispatch; + EFI_SMM_SW_DISPATCH_CONTEXT SwContext; + + InitAmiBufferValidationLib( ImageHandle, SystemTable ); + + Status = pBS->LocateProtocol(&gEfiSmmSwDispatchProtocolGuid, NULL, &pSwDispatch); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + return Status; + } + + SwContext.SwSmiInputValue = AHCI_INT13_SMM_SWSMI_VALUE; + Status = pSwDispatch->Register(pSwDispatch, AhciMmioSmmSMIHandler, &SwContext, &Handle); + return EFI_SUCCESS; +} + +// +//--------------------------------------------------------------------------- +// +// Name: AhciMmioSmmEntryPoint +// +// Description: Ahci MMIO access module entry Point +// +// Input: Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT +// EFI System Table - Pointer to System Table +// +// Output: EFI_STATUS OR EFI_NOT_FOUND +// +//--------------------------------------------------------------------------- +// + +EFI_STATUS +AhciInt13SmmEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + InitAmiLib(ImageHandle, SystemTable); + return InitSmmHandler(ImageHandle, SystemTable, AhciMmioSmmInSmmFunction, NULL); + +} +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AhciInt13Smm.cif b/Core/EM/Ahci/AhciInt13Smm.cif new file mode 100644 index 0000000..a06480e --- /dev/null +++ b/Core/EM/Ahci/AhciInt13Smm.cif @@ -0,0 +1,15 @@ + + name = "AhciInt13Smm" + category = ModulePart + LocalRoot = "Core\eM\Ahci" + RefName = "AhciInt13Smm" +[files] +"AhciInt13Smm.sdl" +"AhciInt13Smm.h" +"AhciInt13Dxe.c" +"AhciInt13Dxe.dxs" +"AhciInt13Smm.c" +"AhciInt13Smm.dxs" +"AhciInt13Smm.mak" + + diff --git a/Core/EM/Ahci/AhciInt13Smm.dxs b/Core/EM/Ahci/AhciInt13Smm.dxs new file mode 100644 index 0000000..cb8a532 --- /dev/null +++ b/Core/EM/Ahci/AhciInt13Smm.dxs @@ -0,0 +1,65 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Smm.dxs 1 11/25/14 12:09a Kapilporwal $Revision: +// +// $Date: 11/25/14 12:09a $Log: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Smm.dxs $ +// +// +// +//**************************************************************************** + +// +//**************************************************************************** +// +// Name: AhciInt13Smm.dxs +// +// Description: +// Dependency expression for the AhciInt13Smm component +//**************************************************************************** +// + +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION>=0x4028B) +#include +#include +#include +#else +#include +#include +#endif + +DEPENDENCY_START +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION>=0x4028B) + EFI_SMM_BASE2_PROTOCOL_GUID AND + EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID AND + EFI_SMM_CPU_PROTOCOL_GUID +#else + EFI_SMM_BASE_PROTOCOL_GUID AND + EFI_SMM_SW_DISPATCH_PROTOCOL_GUID +#endif +DEPENDENCY_END + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** \ No newline at end of file diff --git a/Core/EM/Ahci/AhciInt13Smm.h b/Core/EM/Ahci/AhciInt13Smm.h new file mode 100644 index 0000000..efe0fad --- /dev/null +++ b/Core/EM/Ahci/AhciInt13Smm.h @@ -0,0 +1,155 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Smm.h 1 11/25/14 12:09a Kapilporwal $Revision: +// +// $Date: 11/25/14 12:09a $Log: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Smm.h $ +// +// +// +//**************************************************************************** + +// +//**************************************************************************** +// +// Name: AhciInt13Smm.h +// +// Description: +// This file contains the definitions of function prototype, constant and +// data structure for AhciInt13Smm module. +//**************************************************************************** +// + +#ifndef __AINT13_SMM_HEADER__ +#define __AINT13_SMM_HEADER__ + +#define AHCI_INT13_SMM_DATA_GUID \ + { 0xF4F63525, 0x281E, 0x4040, 0xA3, 0x13, 0xC1, 0xD6, 0x76, 0x63, 0x84, 0xBE } + +// PciExpressBaseAddress uses PCIEX_BASE_ADDRESS +#define PCI_CFG_ADDR(bus,dev,func,reg) \ + ((VOID*)(UINTN) (PciExpressBaseAddress + ((bus) << 20) + ((dev) << 15) + ((func) << 12) + reg)) + +#define AHCI_CONTROLLER 0x06 +#define MASS_STORAGE 0x01 +#define PCI_ABAR 0x24 +#define HDD_BLOCK_SIZE 512 + +#define READ_SECTORS 0x20 +#define READ_SECTORS_EXT 0x24 +#define READ_MULTIPLE 0xC4 +#define READ_MULTIPLE_EXT 0x29 +#define WRITE_SECTORS 0x30 +#define WRITE_SECTORS_EXT 0x34 +#define WRITE_MULTIPLE 0xC5 +#define WRITE_MULTIPLE_EXT 0x39 +#define READ_DMA 0xC8 +#define READ_DMA_EXT 0x25 +#define WRITE_DMA 0xCA +#define WRITE_DMA_EXT 0x35 + +// Int13 parameter definition +// function(AH) definition +#define READ_SECTOR 0x02 +#define WRITE_SECTOR 0x03 +#define EXT_READ 0x42 +#define EXT_WRITE 0x43 + +#ifndef OFFSET_OF +#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field)) +#endif + +EFI_STATUS AhciInt13DxeEntry( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +); + +EFI_STATUS AhciInt13SmmEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +); + +// Prevent compiler from padding the structures +#pragma pack(1) + +typedef struct { + DLINK dLink; + UINT8 DriveNum; // Int13's Drive Number(dl) + UINT8 PMPortNum; // PMPort number on HBA + UINT8 PortNum; // Port number on HBA + UINT8 BusNo; // Bus# of Controller + UINT8 DevNo; // Device# of Controller + UINT8 FuncNo; // Function# of Controller + UINT8 DeviceType; // 0 ATA, 1 ATAPI + UINT8 Lun; // ATAPI LUN + UINT16 BlockSize; // ATAPI Block Size + UINT16 wMAXCYL; // maximum no. of cylinders..INT13 interface. (logical) + UINT8 bMAXHN; // maximum no. of heads..INT13 interface. (logical) + UINT8 bMAXSN; // no. of sectors per track..INT13 interface. (logical) + UINT16 wLBACYL; // #of cylinders drive is configured for. (physical) + UINT8 bLBAHD; // #of heads drive is configured for. (physical) + UINT8 bLBASPT; // #of sectors per track drive is configured for. (physical) + UINT8 WCommand; // write command + UINT8 RCommand; // read command +} SMM_AINT13_DRIVE_INFO; + +typedef struct { + UINT8 DriveCount; + SMM_AINT13_DRIVE_INFO DriveInfo[32]; // Sync array length with SATA_PORT_COUNT of Aint13.h +} AHCI_INT13_SMM_DATA; + +typedef struct { + UINT8 PackageSize; // size of package(10h or 18h) + UINT8 Reserved; // reserved + UINT16 XferSector; // transfer sectors + UINT32 Buffer; // 32 bit address transfer buffer + UINT64 StartLba; // Start LBA sectors; + UINT64 Buffer64; // 64 bit address transfer buffer(option); +} DISK_ADDRESS_PACKAGE; + +// DO NOT MODIFY BELOW STRUCTURE +// NOTE: If modified, AINT13.ASM (of AI13.bin) also needs to be modified +typedef struct { + UINT32 StackEDI; + UINT32 StackESI; + UINT32 StackEBP; + UINT32 StackESP; + UINT32 StackEBX; + UINT32 StackEDX; + UINT32 StackECX; + UINT32 StackEAX; + UINT16 StackDS; + UINT16 StackES; + UINT16 StackGS; + UINT16 StackFS; + EFI_FLAGS_REG StackFlags; +} INT13_TO_SMI_EXREGS; + +#pragma pack() + +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AhciInt13Smm.mak b/Core/EM/Ahci/AhciInt13Smm.mak new file mode 100644 index 0000000..bb6a422 --- /dev/null +++ b/Core/EM/Ahci/AhciInt13Smm.mak @@ -0,0 +1,72 @@ +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** +#********************************************************************** +# $Header: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Smm.mak 2 12/08/14 5:39a Anbuprakashp $Revision: +# +# $Date: 12/08/14 5:39a $Log: /Alaska/SOURCE/Modules/AHCI/INT13/AhciInt13Smm.mak $ +# +# +# +#**************************************************************************** + +# +#**************************************************************************** +# +# Name: AhciInt13Smm.mak +# +# Description: +# MAK file for the AhciInt13Smm component +#**************************************************************************** +# + +all : AhciInt13Smm +AhciInt13Smm : $(BUILD_DIR)\AhciInt13Smm.mak AhciInt13SmmBin + +$(BUILD_DIR)\AhciInt13Smm.mak : $(AHCI_INT13_SMM_DIR)\AhciInt13Smm.cif $(AHCI_INT13_SMM_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(AHCI_INT13_SMM_DIR)\AhciInt13Smm.cif $(CIF2MAK_DEFAULTS) + +AHCI_INT13_SMM_INCLUDES = $(AMIDXELIB) \ + $(BUILD_DIR)\AmiBufferValidationLib.lib + +AhciInt13SmmBin : $(AHCI_INT13_SMM_INCLUDES) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\AhciInt13Smm.mak all\ + GUID=501f30e9-d14f-47da-ae60-b101e4189d07\ + ENTRY_POINT=AhciInt13SmmEntryPoint\ +!IF $(PI_SPECIFICATION_VERSION) >= 0x1000A && $(CORE_COMBINED_VERSION) >= 0x4028B + TYPE=DXESMM_DRIVER PE_TYPE=RT_DRIVER\ + DEPEX1=$(AHCI_INT13_SMM_DIR)\AhciInt13Smm.dxs \ + DEPEX1_TYPE=EFI_SECTION_SMM_DEPEX \ + DEPEX2=$(AHCI_INT13_SMM_DIR)\AhciInt13Dxe.dxs \ + DEPEX2_TYPE=EFI_SECTION_DXE_DEPEX \ +!ELSE + TYPE=BS_DRIVER\ + DEPEX1=$(AHCI_INT13_SMM_DIR)\AhciInt13Smm.dxs \ + DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX \ +!ENDIF + COMPRESS=1 + +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** \ No newline at end of file diff --git a/Core/EM/Ahci/AhciInt13Smm.sdl b/Core/EM/Ahci/AhciInt13Smm.sdl new file mode 100644 index 0000000..b5ad133 --- /dev/null +++ b/Core/EM/Ahci/AhciInt13Smm.sdl @@ -0,0 +1,58 @@ +TOKEN + Name = "AHCI_INT13_SMM_SUPPORT" + Value = "0" + Help = "Main switch to enable SMM support for AHCI Int13/MMIO operations in Project. Currently only INT13 Read/Write functions are supported." + TokenType = Boolean + Master = Yes + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes +End + +PATH + Name = "AHCI_INT13_SMM_DIR" +End + +MODULE + Help = "Includes AhciInt13Smm.mak" + File = "AhciInt13Smm.mak" +End + +TOKEN + Name = "AHCI_INT13_SMM_SWSMI_VALUE" + Value = "043h" + Help = "Value to write into SMI command register to generate software SMI for AHCI INT13/MMIO operations." + TokenType = Integer + TargetH = Yes + TargetEQU = Yes + Range = "0 - 0xff" +End + +TOKEN + Name = "AINT13_AVOID_MULTIPLE_SMI" + Value = "0" + Help = "Execute INT13 Read/Write functions completely in SMM and avoid multiple SMI generation for single AHCI INT13 function/call." + TokenType = Boolean + TargetEQU = Yes + TargetH = Yes + Token = "PI_SPECIFICATION_VERSION" ">=" "0x1000A" + Token = "CORE_COMBINED_VERSION" ">=" "0x4028B" + Token = "SMM_COMMUNICATE_SUPPORT" "=" "1" + Token = "AhciSmm_SUPPORT" "=" "1" +End + +TOKEN + Name = "BIG_REAL_MODE_MMIO_ACCESS" + Value = "0" + Help = "1- Access the MMIO region by switching to big real mode, 0 - Access the MMIO using SMI handler" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes +End + +ELINK + Name = "$(BUILD_DIR)\AhciInt13Smm.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End \ No newline at end of file diff --git a/Core/EM/Ahci/AhciSmm/AhciSmm.c b/Core/EM/Ahci/AhciSmm/AhciSmm.c new file mode 100644 index 0000000..730c1d1 --- /dev/null +++ b/Core/EM/Ahci/AhciSmm/AhciSmm.c @@ -0,0 +1,2217 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/AhciSmm/AhciSmm.c 12 11/24/14 11:56p Kapilporwal $ +// +// $Revision: 12 $ +// +// $Date: 11/24/14 11:56p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/AHCI/AhciSmm/AhciSmm.c $ +// +// 12 11/24/14 11:56p Kapilporwal +// [TAG] EIP191939 +// [Category] Improvement +// [Description] Issue about BIG_REAL_MODE_MMIO_ACCESS of AHCI module +// [Files] AI13.bin +// AHCIACC.ASM +// AhciInt13Dxe.c +// AhciInt13Dxe.dxs +// AhciInt13Smm.c +// AhciInt13Smm.cif +// AhciInt13Smm.dxs +// AhciInt13Smm.h +// AhciInt13Smm.mak +// AhciInt13Smm.sdl +// AInt13.c +// Aint13.cif +// AInt13.h +// AhciSmm.c +// AhciSmm.h +// AhciSmmProtocol.h +// +// 11 8/11/14 6:47a Anbuprakashp +// [TAG] EIP178239 +// [Category] Improvement +// [Description] S3 Resume fails when HDD password is set where platform +// have more than one AHCI controller +// [Files] AhciSmm.c,AhciSmm.sdl,IDESMM.c +// +// 10 8/17/12 3:14a Srikantakumarp +// [TAG] EIP95863 +// [Category] Bug Fix +// [Symptom] AhciSmm doesnt save and restore the upper 32bits of FBU and +// CLBU +// [RootCause] As Windows uses the 64bit address for FIS Base Address +// and Command List Base Address, and AHCISMM driver doesn't take care of +// the upper 32bit value of those which cause the failure in AhciSMM +// driver. +// [Solution] Save and Restore the upper 32bits of FBU and CLBU in +// AhciSmm Driver. +// [Files] AhciController.c, AhciSmm.c +// +// 9 11/14/11 3:13a Rameshr +// [TAG] EIP73137 +// [Category] Improvement +// [Description] Modified the code to use correct status regsiter and +// bits to check the device status. +// [Files] AhciSmm.c +// +// 8 3/15/11 4:12a Rameshr +// [TAG]- EIP 51884 +// [Category]- New Feature +// [Description]- Added packet command function in AhciSMM for sending +// command in SMM handler +// [Files]- AhciSmm.c, AhciSmm.h, AhciSmmProtocols.h +// +// 7 2/11/11 4:11a Rameshr +// [TAG] EIP53704 +// [Category] Improvement +// [Description] AMI headers update for Alaska Ahci Driver +// [Files] AhciSmm.mak +// AhciSmm.dxs +// AhciSmm.c +// AhciSmm.h +// +// 6 5/07/10 2:32p Krishnakumarg +// Updated the date in AMI header +// +// 5 5/07/10 12:37p Krishnakumarg +// Update for coding standard +// +// 4 11/13/09 6:05a Rameshr +// AhciBaseAddress initilization moved from entryfunction to +// AhciSmmInitPortOnS3Resume. +// EIP: 29827 +// +// 3 11/02/09 6:15p Davidd +// Correct S3 resume hanging problem in AHCI mode (EIP 29827). +// +// 2 6/05/09 2:45p Rameshr +// x64 mode compilation error Resolved. +// Eip:22710 +// +// 1 4/28/09 6:39p Rameshr +// Initial Check-in +// +// +//********************************************************************** + +// +//-------------------------------------------------------------------------- +// +// Name: AHCISmm.c +// +// Description: AHCISmm funtion implementation. +// +//-------------------------------------------------------------------------- +// + +//--------------------------------------------------------------------------- +// Include files +//--------------------------------------------------------------------------- +//********************************************************************** + +#include +#include +#include +#include +#include "Protocol\PciIo.h" +#include "Protocol\PDiskInfo.h" +#include "Protocol\PIDEController.h" +#include "protocol\BlockIo.h" +#include "Protocol\PIDEBus.h" +#include +#include +#include "AhciSmm.h" +#include +#include +#include "AhciController.h" + +#define SCC_AHCI_CONTROLLER 0x06 +#define SCC_RAID_CONTROLLER 0x04 +#define PCI_SCC 0x000A // Sub Class Code Register + + +EFI_GUID gAhciSmmProtocolGuid=AHCI_SMM_PROTOCOL_GUID; +UINT32 gCommandListBaseAddress; +UINT32 gFisBaseAddress; +UINT32 gCommandListBaseAddress2; +UINT32 gFisBaseAddress2; + +AHCI_BUS_SMM_PROTOCOL AhciSmm; +BOOLEAN gPortReset = FALSE; // Avoid Re-entry +UINT8 *SenseData=NULL; + + +#if defined(EFI64) || defined(EFIx64) +static UINT64 +DivU64x32 ( + IN UINT64 Dividend, + IN UINTN Divisor, + OUT UINTN *Remainder OPTIONAL + ) +{ + UINT64 Result = Dividend/Divisor; + if (Remainder) *Remainder=Dividend%Divisor; + return Result; +} + +#else +static UINT64 +DivU64x32 ( + IN UINT64 Dividend, + IN UINTN Divisor, //Can only be 31 bits. + OUT UINTN *Remainder OPTIONAL + ) +{ + UINT64 Result; + UINT32 Rem; + _asm + { + mov eax, dword ptr Dividend[0] + mov edx, dword ptr Dividend[4] + mov esi, Divisor + xor edi, edi ; Remainder + mov ecx, 64 ; 64 bits +Div64_loop: + shl eax, 1 ;Shift dividend left. This clears bit 0. + rcl edx, 1 + rcl edi, 1 ;Shift remainder left. Bit 0 = previous dividend bit 63. + + cmp edi, esi ; If Rem >= Divisor, don't adjust + cmc ; else adjust dividend and subtract divisor. + sbb ebx, ebx ; if Rem >= Divisor, ebx = 0, else ebx = -1. + sub eax, ebx ; if adjust, bit 0 of dividend = 1 + and ebx, esi ; if adjust, ebx = Divisor, else ebx = 0. + sub edi, ebx ; if adjust, subtract divisor from remainder. + loop Div64_loop + + mov dword ptr Result[0], eax + mov dword ptr Result[4], edx + mov Rem, edi + } + + if (Remainder) *Remainder = Rem; + + return Result; +} + +#endif + +// +//---------------------------------------------------------------------------- +// Procedure: Stall +// +// Description: Stalls for the Required Amount of MicroSeconds +// +// Input: +// UINTN Usec // Number of microseconds to delay +// +// Output: None +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +VOID +SmmStall ( + UINTN Usec + ) +{ + UINTN Counter, i; + UINT32 Data32, PrevData; + UINTN Remainder; + + Counter = (UINTN)DivU64x32 ((Usec * 10), 3, &Remainder); + + if (Remainder != 0) { + Counter++; + } + + // + // Call WaitForTick for Counter + 1 ticks to try to guarantee Counter tick + // periods, thus attempting to ensure Microseconds of stall time. + // + if (Counter != 0) { + + PrevData = IoRead32(PM_BASE_ADDRESS + 8); + for (i=0; i < Counter; ) { + Data32 = IoRead32(PM_BASE_ADDRESS + 8); + if (Data32 < PrevData) { // Reset if there is a overlap + PrevData=Data32; + continue; + } + i += (Data32 - PrevData); + PrevData = Data32; + } + } + return; +} + +// +//---------------------------------------------------------------------------- +// Procedure: ZeromemorySmm +// +// Description: Clears the buffer +// +// Input: void *Buffer, +// UINTN Size +// +// Output: None +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +void +ZeroMemorySmm ( + void *Buffer, + UINTN Size + ) +{ + UINT8 *Ptr; + Ptr = Buffer; + while (Size--) { + *(Ptr++) = 0; + } +} + +// +//---------------------------------------------------------------------------- +// Procedure: WaitforPMMemSet +// +// Description: Wait for memory to be set to the test value. +// +// Input: +// SATA_DEVICE_INTERFACE *SataDevInterface, +// PMPort +// Register +// MaskValue - The mask value of memory +// TestValue - The test value of memory +// WaitTimeInMs - The time out value for wait memory set +// +// Output: EFI_SUCCESS - HBA reset successfully. +// EFI_DEVICE_ERROR - HBA failed to complete hardware reset. +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +WaitforPMMemSet ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN UINT8 PMPort, + IN UINT8 Register, + IN UINT32 AndMask, + IN UINT32 TestValue, + IN UINT32 WaitTimeInMs +) +{ + UINT32 Data32; + + while(WaitTimeInMs!=0){ + ReadWritePMPort (SataDevInterface, PMPort, Register, &Data32, FALSE); + if((Data32 & AndMask) == TestValue) {return EFI_SUCCESS;} + SmmStall (1000); // 1Msec + WaitTimeInMs--; + } + return EFI_DEVICE_ERROR; +} + + +// +//---------------------------------------------------------------------------- +// Procedure: WaitForMemSet +// +// Description: Wait for memory to be set to the test value. +// +// Input: MemTestAddr - The memory address to test +// MaskValue - The mask value of memory +// TestValue - The test value of memory +// WaitTimeInMs - The time out value for wait memory set +// +// Output: EFI_SUCCESS - HBA reset successfully. +// EFI_DEVICE_ERROR - HBA failed to complete hardware reset. +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +WaitForMemSet ( + IN UINT32 BaseAddr, + IN UINT8 Port, + IN UINT8 Register, + IN UINT32 AndMask, + IN UINT32 TestValue, + IN UINT32 WaitTimeInMs +) +{ + UINT8 Delay; + while(WaitTimeInMs!=0){ + for ( Delay = 10; Delay > 0; Delay--) { + if(((HBA_PORT_REG32(BaseAddr, Port, Register)) & AndMask) == TestValue) {return EFI_SUCCESS;} + SmmStall (100); // 100 usec * 10 = 1Msec + } + WaitTimeInMs--; + } + return EFI_DEVICE_ERROR; +} + +// +//---------------------------------------------------------------------------- +// Procedure: WaitForMemClear +// +// Description: Wait for memory to be set to the test value. +// +// Input: MemTestAddr - The memory address to test +// MaskValue - The mask value of memory +// WaitTimeInMs - The time out value for wait memory set +// +// Output: EFI_SUCCESS - HBA reset successfully. +// EFI_DEVICE_ERROR - HBA failed to complete hardware reset. +// +// Modified: +// +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +WaitForMemClear ( + IN UINT32 BaseAddr, + IN UINT8 Port, + IN UINT8 Register, + IN UINT32 AndMask, + IN UINT32 WaitTimeInMs +) +{ + UINT8 Delay; + while(WaitTimeInMs!=0){ + for ( Delay = 10; Delay > 0; Delay--) { + if(!((HBA_PORT_REG32(BaseAddr, Port, Register)) & AndMask)) {return EFI_SUCCESS;} + SmmStall (100); // 100 usec * 10 = 1Msec + } + WaitTimeInMs--; + } + return EFI_DEVICE_ERROR; +} + +// +//---------------------------------------------------------------------------- +// Procedure: ReadSCRRegister +// +// Description: +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT8 Port, +// IN UINT8 PMPort, +// IN UINT8 Register (0 : SStatus 1: SError 2: SControl) +// +// Output: +// UINT32 +// Modified: +// +// Referrals: +// +// Notes: +// 1. Check if the device is connected directly to the port +// 2. if yes, read to the AHCI Controller else write to the Port Multiplier register. +// +//---------------------------------------------------------------------------- +// +UINT32 +ReadSCRRegister ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN UINT8 Port, + IN UINT8 PMPort, + IN UINT8 Register +) +{ + + UINT32 Data32 = 0; + UINT32 Reg = HBA_PORTS_SSTS; + + if (PMPort != 0xFF) { + ReadWritePMPort (SataDevInterface, PMPort, Register, &Data32, FALSE); + } + else { + if (Register == 1) Reg = HBA_PORTS_SCTL; + if (Register == 2) Reg = HBA_PORTS_SERR; + Data32 = HBA_PORT_REG32 (SataDevInterface->AhciBaseAddress, Port, Reg); + } + + return Data32; +} + +// +//---------------------------------------------------------------------------- +// Procedure: WriteSCRRegister +// +// Description: Write to SCONTROL/Serror/SStatus register +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT8 Port, +// IN UINT8 PMPort, +// IN UINT8 Register, (0 : SStatus 1: SError 2: SControl) +// IN UINT32 Data32 +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Check if the device is connected directly to the port +// 2. if yes, write to the AHCI Controller else write to the Port Multiplier register +// +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +WriteSCRRegister ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN UINT8 Port, + IN UINT8 PMPort, + IN UINT8 Register, + IN UINT32 Data32 +) +{ + + UINT32 Reg = HBA_PORTS_SSTS; + + if (PMPort != 0xFF) { + ReadWritePMPort (SataDevInterface, PMPort, Register, &Data32, TRUE); + } + else { + if (Register == 2) Reg = HBA_PORTS_SCTL; + if (Register == 1) Reg = HBA_PORTS_SERR; + HBA_PORT_REG32_OR (SataDevInterface->AhciBaseAddress, Port, Reg, Data32); + } + + return EFI_SUCCESS; +} + +// +//---------------------------------------------------------------------------- +// Procedure: WaitforCommandComplete +// +// Description: Wait till cmd completes +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_TYPE CommandType, +// IN UINTN TimeOut +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Check for SError bits. If set return error. +// 2. For PIO IN/Out and Packet IN/OUT command wait till PIO Setup FIS is received +// 3. If D2H register FIS is received, exit the loop. +// 4. Check for SError and TFD bits. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +WaitforCommandComplete ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN COMMAND_TYPE CommandType, + IN UINTN TimeOut +) +{ + + UINT32 AhciBaseAddr = (UINT32)SataDevInterface->AhciBaseAddress; + UINT8 Port = SataDevInterface->PortNumber; + UINT32 Data32_SERR, Data32_IS, i; + BOOLEAN PxSERR_ERROR = FALSE, PIO_SETUP_FIS = FALSE; + volatile AHCI_RECEIVED_FIS *FISReceiveAddress = (AHCI_RECEIVED_FIS *)SataDevInterface->PortFISBaseAddr; + UINTN TimeOutCount = TimeOut; + + for(i = 0; i < TimeOutCount * 2; i++, SmmStall(500)) { // 500usec + + // + // Check for Error bits + // + Data32_SERR = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_SERR); + if (Data32_SERR & HBA_PORTS_ERR_CHK) { + PxSERR_ERROR = TRUE; + break; + } + + // + // Check for Error bits + // + Data32_IS = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_IS); + if (Data32_IS & HBA_PORTS_IS_ERR_CHK) { + PxSERR_ERROR = TRUE; + break; + } + + switch (CommandType) { + + case PIO_DATA_IN_CMD: + case PIO_DATA_OUT_CMD: + case PACKET_PIO_DATA_IN_CMD: + case PACKET_PIO_DATA_OUT_CMD: + + // + // check if PIO setup received + // + if(FISReceiveAddress->Ahci_Psfis[0] == FIS_PIO_SETUP) { + FISReceiveAddress->Ahci_Psfis[0] = 0; + TimeOutCount = TimeOut; + PIO_SETUP_FIS = TRUE; + } + break; + default: + break; + + } + + // + // check if D2H register FIS is received + // + if(FISReceiveAddress->Ahci_Rfis[0] == FIS_REGISTER_D2H) break; + + // + // For PIO Data in D2H register FIS is not received. So rely on BSY bit + // + if ((CommandType == PIO_DATA_IN_CMD) && PIO_SETUP_FIS && + !((HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_TFD) & + (HBA_PORTS_TFD_BSY | HBA_PORTS_TFD_DRQ)))){ + break; + } + } + + if (PxSERR_ERROR) { + + // + // clear the status and return error + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + return EFI_DEVICE_ERROR; + } + + // + // check if CI register is zero + // + if (HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_CI)){ + return EFI_DEVICE_ERROR; + } + + // + // check for status bits + // + if (HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_TFD) & (HBA_PORTS_TFD_ERR | HBA_PORTS_TFD_DRQ)){ + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: StartController +// +// Description: +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT32 CIBitMask +// +// Output: +// EFI_STATUS +// Modified: +// +// Referrals: +// +// Notes: +// 1. Clear Status register +// 2. Enable FIS and CR running bit +// 3. Enable Start bit +// 4. Update CI bit mask +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +StartController ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN UINT32 CIBitMask +) +{ + + UINT32 AhciBaseAddr = (UINT32)(SataDevInterface->AhciBaseAddress); + UINT8 Port = SataDevInterface->PortNumber; + + // + // Clear Status + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + // + // Enable FIS Receive + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_FRE); + + // + // Wait till FIS is running + // + WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + // + // Clear FIS Receive area + // + ZeroMemorySmm ((VOID *)SataDevInterface->PortFISBaseAddr, RECEIVED_FIS_SIZE); + + // + // Enable ST + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_ST); + + // + // Enable Command Issued + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CI, CIBitMask); + + return EFI_SUCCESS; + +} + + +// +//---------------------------------------------------------------------------- +// Procedure: HandlePortComReset +// +// Description: Check if COM Reset is successful or not +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT8 Port, +// IN UINT8 PMPort, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ReadSCRRegister, WriteSCRRegister +// +// Notes: +// 1. Check if Link is active. If not return error. +// 2. If Link is present, wait for PhyRdy Change bit to be set. +// 3. Clear SError register +// 4. Wait for D2H register FIS +// 5. Check the Status register for errors. +// 6. If COMRESET is success wait for sometime if the device is ATAPI or GEN1 +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +HandlePortComReset( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN UINT8 Port, + IN UINT8 PMPort +) +{ + + EFI_STATUS Status = EFI_SUCCESS; + BOOLEAN DeviceDetected = FALSE; + UINT32 Data32, i, Delay, SStatusData; + UINT32 AhciBaseAddr = (UINT32)(SataDevInterface->AhciBaseAddress); + volatile AHCI_RECEIVED_FIS *FISAddress; + + // + // Check if detection is complete + // + for (i = 0; i < HBA_PRESENCE_DETECT_TIMEOUT; i++){ // Total delay 10msec + SStatusData = ReadSCRRegister (SataDevInterface, Port, PMPort, 0); // SStatus + SStatusData &= HBA_PORTS_SSTS_DET_MASK; + if ((SStatusData == HBA_PORTS_SSTS_DET_PCE) || (SStatusData == HBA_PORTS_SSTS_DET)) { + DeviceDetected = TRUE; + break; + } + SmmStall (1000); // 1msec + } + + if (DeviceDetected) { + + // + // Wait till PhyRdy Change bit is set + // + if (PMPort == 0xFF) { + Status = WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_SERR, + HBA_PORTS_SERR_EX, + HBA_PORTS_SERR_EX, + ATAPI_BUSY_CLEAR_TIMEOUT); + } + else { + Status = WaitforPMMemSet (SataDevInterface, PMPort, PSCR_1_SERROR, + HBA_PORTS_SERR_EX, HBA_PORTS_SERR_EX, ATAPI_BUSY_CLEAR_TIMEOUT); + } + + // + // Clear Status register + // + FISAddress = * ((AHCI_RECEIVED_FIS **)(HBA_PORT_REG_BASE(Port) + AhciBaseAddr + HBA_PORTS_FB)); + for (i = 0; i < ATAPI_BUSY_CLEAR_TIMEOUT; ) { + WriteSCRRegister (SataDevInterface, Port, PMPort, 1, HBA_PORTS_ERR_CLEAR); //SError + + if(FISAddress->Ahci_Rfis[0] == FIS_REGISTER_D2H){ + break; + } + + // + // 1msec Strange. Delay is needed for read to succeed. + // + SmmStall (1000); // 1msec (1000); + + // + // For device behind PM Port, there is a delay in + // writing to the register. So count can be decreased. + // + if (PMPort != 0xFF) {i+= 100;} + else { i++; } + } + + + for ( Delay = 0; Delay < (ATAPI_BUSY_CLEAR_TIMEOUT * 10); Delay++) { + if(!((HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_TFD)) & HBA_PORTS_TFD_BSY)) {break;} + if((HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_IS)) & (BIT30 + BIT29 + BIT28 + BIT27 + BIT26)) {break;} + SmmStall (1000); // 1msec (100); // 100 usec * 10 = 1Msec + } + + // + // check for errors + // + Data32 = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_TFD); + if (Data32 & (HBA_PORTS_TFD_BSY | HBA_PORTS_TFD_ERR)) Status = EFI_DEVICE_ERROR; + + Data32 = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_IS); + if (Data32 & (BIT30 + BIT29 + BIT28 + BIT27 + BIT26)) Status = EFI_DEVICE_ERROR; + + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + } else { + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +// +//---------------------------------------------------------------------------- +// Procedure: GeneratePortReset +// +// Description: Issue a Port Reset +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT8 CurrentPort, +// IN UINT8 Speed, +// IN UINT8 PowerManagement +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ReadWritePMPort, HandlePortComReset +// +// Notes: +// 1. Issue port reset by setting DET bit in SControl register +// 2. Call HandlePortComReset to check the status of the reset. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +GeneratePortReset ( + AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + UINT8 Port, + UINT8 PMPort, + UINT8 Speed, + UINT8 PowerManagement +) +{ + + EFI_STATUS Status; + UINT32 AhciBaseAddr = (UINT32) SataDevInterface->AhciBaseAddress; + volatile AHCI_RECEIVED_FIS *FISAddress = *((AHCI_RECEIVED_FIS **)(HBA_PORT_REG_BASE(Port) + AhciBaseAddr + HBA_PORTS_FB)); + UINT32 Data32; + + if (!FISAddress){ + return EFI_DEVICE_ERROR; // FIS receive address is not programmed. + } + + if (gPortReset){ + return EFI_SUCCESS; + } + + gPortReset = TRUE; + + // + // Disable Start bit + // + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_CMD, ~HBA_PORTS_CMD_ST); + + // + // Wait till CR is cleared + // + Status = WaitForMemClear(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_CR, + HBA_CR_CLEAR_TIMEOUT); + + // + // Clear Status register + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); + if (PMPort != 0xFF) { + Data32 = HBA_PORTS_ERR_CLEAR; + ReadWritePMPort (SataDevInterface, PMPort, PSCR_1_SERROR, &Data32, TRUE); + } + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + // + // Enable FIS Receive Enable + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_FRE); + + // + // Wait till FIS is running and then clear the data area + // + WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + + FISAddress->Ahci_Rfis[0] = 0; + + if (PMPort == 0xFF) { + + // + // Issue Port COMRESET + // + HBA_PORT_REG32_AND_OR (AhciBaseAddr, Port, HBA_PORTS_SCTL, 0xFFFFF000, + HBA_PORTS_SCTL_DET_INIT + (Speed << 4) + (PowerManagement << 8)); + SmmStall (1000); // 1msec + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_SCTL, ~HBA_PORTS_SCTL_DET_MASK); + } + else { + Data32 = HBA_PORTS_SCTL_DET_INIT + (Speed << 4) + (PowerManagement << 8); + ReadWritePMPort (SataDevInterface, PMPort, PSCR_2_SCONTROL, &Data32, TRUE); + SmmStall (1000); // 1msec + Data32 = (Speed << 4) + (PowerManagement << 8); + ReadWritePMPort (SataDevInterface, PMPort, PSCR_2_SCONTROL, &Data32, TRUE); + } + + Status = HandlePortComReset(SataDevInterface, Port, PMPort); + + // + // Disable FIS Receive Enable + // + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_CMD, ~HBA_PORTS_CMD_FRE); + + gPortReset = FALSE; + + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + + +// +//---------------------------------------------------------------------------- +// Procedure: StopController +// +// Description: Stop FIS and CR +// +// Input: +// IN AHCI_BUS_PROTOCOL *AhciBusInterface, +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: GeneratePortReset +// +// Notes: +// 1. clear ST bit and wait till CR bits gets reset +// 2. if not generate Port reset +// 3. Clear FIS running bit. +// 4. Clear status register +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +StopController( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN BOOLEAN StartOrStop +) +{ + + UINT8 Port = SataDevInterface->PortNumber; + UINT8 PMPort = SataDevInterface->PMPortNumber; + UINT32 AhciBaseAddr = (UINT32)(SataDevInterface->AhciBaseAddress); + EFI_STATUS Status; + UINT32 PortFISBaseAddr = SataDevInterface->PortFISBaseAddr; + UINT32 CommandListBaseAddress = SataDevInterface->PortCommandListBaseAddr; + + if(StartOrStop) { + gCommandListBaseAddress=HBA_PORT_REG32(AhciBaseAddr,Port,HBA_PORTS_CLB); + gFisBaseAddress=HBA_PORT_REG32(AhciBaseAddr,Port,HBA_PORTS_FB); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_CLB,CommandListBaseAddress); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FB,PortFISBaseAddr); + + // + // Saving the Upper 32 bits of FIS and Command List Registers + // + gCommandListBaseAddress2=HBA_PORT_REG32(AhciBaseAddr,Port,HBA_PORTS_CLBU); + gFisBaseAddress2=HBA_PORT_REG32(AhciBaseAddr,Port,HBA_PORTS_FBU); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_CLBU,0); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FBU,0); + } + + // + // Clear Start + // + HBA_PORT_REG32_AND (AhciBaseAddr, Port, HBA_PORTS_CMD, ~(HBA_PORTS_CMD_ST)); + + // + // Make sure CR is 0 with in 500msec + // + Status = WaitForMemClear(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_CR, + HBA_CR_CLEAR_TIMEOUT); + + if (EFI_ERROR(Status)) { + Status = GeneratePortReset(SataDevInterface, Port, PMPort, + HBA_PORTS_SCTL_SPD_NSNR, HBA_PORTS_SCTL_IPM_DIS); + }; + + if (EFI_ERROR(Status)) { + goto StopController_ErrorExit; + } + + if (EFI_ERROR(Status)){ + return Status; + } + + // + // Clear FIS receive enable. + // + HBA_PORT_REG32_AND (AhciBaseAddr, Port, + HBA_PORTS_CMD, ~(HBA_PORTS_CMD_FRE)); + // + // Make sure FR is 0 with in 500msec + // + Status = WaitForMemClear(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + if (EFI_ERROR(Status)) { + goto StopController_ErrorExit; + } + + // + // Clear Status register + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + if(!StartOrStop) { + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_CLB,gCommandListBaseAddress); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FB,gFisBaseAddress); + + // + // Restoring the Upper 32 bits of FIS and Command List Registers + // + + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_CLBU,gCommandListBaseAddress2); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FBU,gFisBaseAddress2); + } + + return EFI_SUCCESS; + +StopController_ErrorExit: + + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_CLB,gCommandListBaseAddress); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FB,gFisBaseAddress); + + // + // Restoring the Upper 32 bits of FIS and Command List Registers + // + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_CLBU,gCommandListBaseAddress2); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FBU,gFisBaseAddress2); + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: ReadytoAcceptCmd +// +// Description: Check if the device is ready to accept cmd. +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: GeneratePortReset, ReadWritePMPort +// +// Notes: +// 1. Check the device is ready to accept the command. BSY and DRQ +// should be de-asserted. +// 2. If set, generate Port reset +// 3. In case Port Multiplier is connected to the port, enable all +// the ports of the Port Multiplier. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ReadytoAcceptCmd ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface +) +{ + + EFI_STATUS Status = EFI_SUCCESS; + UINT32 AhciBaseAddr = (UINT32)(SataDevInterface->AhciBaseAddress); + UINT8 Port = SataDevInterface->PortNumber; + UINT8 PMPort = SataDevInterface->PMPortNumber; + UINT32 Data32 = 0, Init_SStatus = 0; + + // + // Is the Device ready to accept the command + // + if (HBA_PORT_REG8 (AhciBaseAddr, Port, HBA_PORTS_TFD) & (HBA_PORTS_TFD_BSY | HBA_PORTS_TFD_DRQ)){ + Data32 = HBA_PORT_REG32 (AhciBaseAddr, Port, HBA_PORTS_SCTL); + Data32 &= 0xFF0; + + // + // make sure the status we read is for the right port + // + Status = GeneratePortReset(SataDevInterface, Port, 0xFF, + (UINT8)((Data32 & 0xF0) >> 4), (UINT8)(Data32 >> 8)); + if (EFI_ERROR(Status)) return Status; + + } + return Status; +} + +// +//---------------------------------------------------------------------------- +// Procedure: BuildCommandList +// +// Description: Builds command list +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN AHCI_COMMAND_LIST *CommandList, +// IN UINT32 CommandTableBaseAddr +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Update CommandList bits +// 2. Not all fields like Ahci_Cmd_A are updated. +// 3. Port number is set to 0xF (Control port) if PM Port number is 0xFF. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +BuildCommandList ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN AHCI_COMMAND_LIST *CommandList, + IN UINT32 CommandTableBaseAddr +) +{ + UINT8 PMPort = SataDevInterface->PMPortNumber; + + ZeroMemorySmm (CommandList, sizeof(AHCI_COMMAND_LIST)); + CommandList->Ahci_Cmd_A = SataDevInterface->DeviceType == ATAPI ? 1 : 0; // set elsewhere + CommandList->Ahci_Cmd_P = 0; + CommandList->Ahci_Cmd_R = 0; + CommandList->Ahci_Cmd_B = 0; + CommandList->Ahci_Cmd_Rsvd1 = 0; + CommandList->Ahci_Cmd_PMP = PMPort == 0xFF ? 0x0 : SataDevInterface->PMPortNumber; + CommandList->Ahci_Cmd_PRDTL = 0; + CommandList->Ahci_Cmd_PRDBC = 0; + CommandList->Ahci_Cmd_CTBA = CommandTableBaseAddr; + CommandList->Ahci_Cmd_CTBAU = 0; + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: CopyMemSmm +// +// Description: Copy Length bytes from Source to Destination. +// +// Input: +// IN VOID *Destination, +// IN VOID *Source, +// IN UINTN Length +// +// Output: +// None +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +VOID +CopyMemSmm ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +/*++ + +Routine Description: + + Copy Length bytes from Source to Destination. + +Arguments: + + Destination - Target of copy + + Source - Place to copy from + + Length - Number of bytes to copy + +Returns: + + None + +--*/ +{ + CHAR8 *Destination8; + CHAR8 *Source8; + + if (Source < Destination) { + Destination8 = (CHAR8 *) Destination + Length - 1; + Source8 = (CHAR8 *) Source + Length - 1; + while (Length--) { + *(Destination8--) = *(Source8--); + } + } else { + Destination8 = (CHAR8 *) Destination; + Source8 = (CHAR8 *) Source; + while (Length--) { + *(Destination8++) = *(Source8++); + } + } +} + +// +//---------------------------------------------------------------------------- +// Procedure: BuildAtapiCMD +// +// Description: +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_STRUCTURE CommandStructure +// IN AHCI_COMMAND_LIST *CommandList, +// IN AHCI_COMMAND_TABLE *Commandtable +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Copy Packet data to command table +// 2. Set Atapi bit in Command List +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +BuildAtapiCMD( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN COMMAND_STRUCTURE CommandStructure, + IN AHCI_COMMAND_LIST *CommandList, + IN AHCI_COMMAND_TABLE *Commandtable +) +{ + + CopyMemSmm(&(Commandtable->AtapiCmd),&(CommandStructure.AtapiCmd),sizeof(AHCI_ATAPI_COMMAND)); + + if (Commandtable->CFis.Ahci_CFis_Cmd == PACKET_COMMAND){ // Is it a packet command? + CommandList->Ahci_Cmd_A = 1; + } + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: BuildPRDT +// +// Description: Build PRDT table +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_STRUCTURE CommandStructure +// IN AHCI_COMMAND_LIST *CommandList, +// IN AHCI_COMMAND_TABLE *Commandtable +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Build as many PRDT table entries based on ByteCount. +// 2. Set the I flag for the lasr PRDT table. +// 3. Update PRDT table lenght in CommandList +// +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +BuildPRDT ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN COMMAND_STRUCTURE CommandStructure, + IN AHCI_COMMAND_LIST *CommandList, + IN AHCI_COMMAND_TABLE *Commandtable +) +{ + + UINT32 ByteCount = CommandStructure.ByteCount; + UINT16 Prdtlength = 0; + AHCI_COMMAND_PRDT *PrdtTable = &(Commandtable->PrdtTable); + + for (;ByteCount; (UINT8 *)PrdtTable += sizeof(AHCI_COMMAND_PRDT)){ + PrdtTable->Ahci_Prdt_DBA = (UINT32)CommandStructure.Buffer; + PrdtTable->Ahci_Prdt_DBC = ByteCount >= PRD_MAX_DATA_COUNT ? (PRD_MAX_DATA_COUNT - 1) : (ByteCount - 1); + ByteCount -= (PrdtTable->Ahci_Prdt_DBC + 1); + PrdtTable->Ahci_Prdt_I = 0; + Prdtlength+= sizeof(AHCI_COMMAND_PRDT); + (UINT8 *)CommandStructure.Buffer += PrdtTable->Ahci_Prdt_DBC + 1; + } + + // + // Set I flag only for the last entry. + // + (UINT8 *)PrdtTable -= sizeof(AHCI_COMMAND_PRDT); + PrdtTable->Ahci_Prdt_I = 1; + CommandList->Ahci_Cmd_PRDTL = Prdtlength / sizeof(AHCI_COMMAND_PRDT); + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: BuildCommandFIS +// +// Description: Build Command FIS +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_STRUCTURE CommandStructure, +// IN AHCI_COMMAND_LIST *CommandList, +// IN AHCI_COMMAND_TABLE *Commandtable +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// 1. Update Command FIS data area. +// 2. Update the Command FIS lenght in Command List table +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +BuildCommandFIS ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN COMMAND_STRUCTURE CommandStructure, + IN AHCI_COMMAND_LIST *CommandList, + IN AHCI_COMMAND_TABLE *Commandtable +) +{ + + ZeroMemorySmm (Commandtable, sizeof(AHCI_COMMAND_TABLE)); + + Commandtable->CFis.Ahci_CFis_Type = FIS_REGISTER_H2D; + Commandtable->CFis.AHci_CFis_PmPort = SataDevInterface->PMPortNumber == 0xFF ? 0x0 : SataDevInterface->PMPortNumber; + + Commandtable->CFis.Ahci_CFis_Cmd = CommandStructure.Command; + + Commandtable->CFis.Ahci_CFis_Features = CommandStructure.Features; + Commandtable->CFis.Ahci_CFis_FeaturesExp = CommandStructure.FeaturesExp; + + Commandtable->CFis.Ahci_CFis_SecNum = CommandStructure.LBALow; + Commandtable->CFis.Ahci_CFis_SecNumExp = CommandStructure.LBALowExp; + + Commandtable->CFis.Ahci_CFis_ClyLow = CommandStructure.LBAMid; + Commandtable->CFis.Ahci_CFis_ClyLowExp = CommandStructure.LBAMidExp; + + Commandtable->CFis.Ahci_CFis_ClyHigh = CommandStructure.LBAHigh; + Commandtable->CFis.Ahci_CFis_ClyHighExp = CommandStructure.LBAHighExp; + + Commandtable->CFis.Ahci_CFis_SecCount = (UINT8)(CommandStructure.SectorCount); + Commandtable->CFis.Ahci_CFis_SecCountExp = (UINT8)(CommandStructure.SectorCount >> 8); + + Commandtable->CFis.Ahci_CFis_DevHead = CommandStructure.Device; + Commandtable->CFis.Ahci_CFis_Control = CommandStructure.Control; + + CommandList->Ahci_Cmd_CFL = FIS_REGISTER_H2D_LENGTH / 4; + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: ReadWritePMPort +// +// Description: Read/Write routine to PM ports +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN UINT8 Port, +// IN UINT8 RegNum, +// IN OUT UINT32 *Data +// IN BOOLEAN READWRITE // TRUE for Write +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: StopController, ReadytoAcceptCmd, BuildCommandList, BuildCommandFIS, BuildAtapiCMD +// BuildPRDT, StartController, WaitforCommandComplete +// +// Notes: +// 1. Update Command Structure for READ/Write Port Multiplier command +// 2. Issue command +// 3. Check for errors. +// 4. Read the out data in case of READ. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +ReadWritePMPort ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN UINT8 Port, + IN UINT8 RegNum, + IN OUT UINT32 *Data, + IN BOOLEAN READWRITE +) +{ + EFI_STATUS Status; + COMMAND_STRUCTURE CommandStructure; + AHCI_RECEIVED_FIS *PortFISBaseAddr = (AHCI_RECEIVED_FIS *)(SataDevInterface->PortFISBaseAddr); + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)SataDevInterface->PortCommandTableBaseAddr; + + ZeroMemorySmm (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + + CommandStructure.Command = READ_PORT_MULTIPLIER; + + if (READWRITE) { + CommandStructure.SectorCount = (UINT16) (*Data & 0xFF); + CommandStructure.LBALow = (UINT8) (*Data >> 8); + CommandStructure.LBAMid = (UINT8)(*Data >> 16); + CommandStructure.LBAHigh = (UINT8)(*Data >> 24); + CommandStructure.Command = WRITE_PORT_MULTIPLIER; + } + + CommandStructure.Device = Port; + CommandStructure.Features = RegNum; + + Status = StopController(SataDevInterface,TRUE); + if (EFI_ERROR(Status)) return Status; + + Status = ReadytoAcceptCmd(SataDevInterface); + if (EFI_ERROR(Status)) { + StopController(SataDevInterface,FALSE); + return Status; + } + + BuildCommandList(SataDevInterface, CommandList, SataDevInterface->PortCommandTableBaseAddr); + BuildCommandFIS(SataDevInterface, CommandStructure, CommandList, Commandtable); + + // + // Data-in + // + CommandList->Ahci_Cmd_W = 0; + + // + // Update of Command Register + // + Commandtable->CFis.Ahci_CFis_C = 1; + + // + // Update the Port Address + // + CommandList->Ahci_Cmd_PMP = CONTROL_PORT; + Commandtable->CFis.AHci_CFis_PmPort = CONTROL_PORT; + + StartController(SataDevInterface, BIT00); + + Status = WaitforCommandComplete(SataDevInterface, NON_DATA_CMD, TIMEOUT_1SEC); + + // + // Stop Controller + // + StopController(SataDevInterface,FALSE); + + if (!READWRITE) { + *Data = 0; + if (!EFI_ERROR(Status)) { + *Data = PortFISBaseAddr->Ahci_Rfis[12] | + (PortFISBaseAddr->Ahci_Rfis[4] << 8) | + (PortFISBaseAddr->Ahci_Rfis[5] << 16) | + (PortFISBaseAddr->Ahci_Rfis[6] << 24); + } + } + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: AhciSmmExecuteDmaDataCommand +// +// Description: Exectue the DMA data command +// +// Input: +// IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, +// IN COMMAND_STRUCTURE CommandStructure, +// UINT8 PortNumber, +// UINT8 PMPortNumber, +// DEVICE_TYPE DeviceType, +// BOOLEAN READWRITE +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +AhciSmmExecuteDmaDataCommand ( + AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + COMMAND_STRUCTURE *CommandStructure, + UINT8 PortNumber, + UINT8 PMPortNumber, + DEVICE_TYPE DeviceType, + BOOLEAN READWRITE +) +{ + + EFI_STATUS Status; + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)SataDevInterface->PortCommandTableBaseAddr; + + SataDevInterface->PortNumber=PortNumber; + SataDevInterface->PMPortNumber=PMPortNumber; + SataDevInterface->DeviceType=DeviceType; + + Status = StopController(SataDevInterface,TRUE); + if (EFI_ERROR(Status)) return Status; + + Status = ReadytoAcceptCmd(SataDevInterface); + if (EFI_ERROR(Status)) { + StopController(SataDevInterface,FALSE); + return Status; + } + BuildCommandList(SataDevInterface, CommandList, SataDevInterface->PortCommandTableBaseAddr); + BuildCommandFIS(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildAtapiCMD(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildPRDT(SataDevInterface, *CommandStructure, CommandList, Commandtable); + + // Data-in + if (READWRITE) { + CommandList->Ahci_Cmd_W = 1; + } + else { + CommandList->Ahci_Cmd_W = 0; + } + Commandtable->CFis.Ahci_CFis_C = 1; + + StartController(SataDevInterface, BIT00); + + Status = WaitforCommandComplete(SataDevInterface, DMA_DATA_IN_CMD, + SataDevInterface->DeviceType == ATA? DMA_ATA_COMMAND_COMPLETE_TIMEOUT \ + : DMA_ATAPI_COMMAND_COMPLETE_TIMEOUT ); + + if (!EFI_ERROR(Status)){ + //Check if the required BYTES have been received + if (CommandList->Ahci_Cmd_PRDBC != CommandStructure->ByteCount){ + Status = EFI_DEVICE_ERROR; + } + } + // Stop Controller + StopController(SataDevInterface,FALSE); + + CommandStructure->ByteCount = CommandList->Ahci_Cmd_PRDBC; + + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: AhciSmmExecutePioDataCommand +// +// Description: Exectue the PIO data command +// +// Input: +// IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, +// IN COMMAND_STRUCTURE CommandStructure, +// UINT8 PortNumber, +// UINT8 PMPortNumber, +// DEVICE_TYPE DeviceType, +// BOOLEAN READWRITE +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +AhciSmmExecutePioDataCommand ( + AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + COMMAND_STRUCTURE *CommandStructure, + UINT8 PortNumber, + UINT8 PMPortNumber, + DEVICE_TYPE DeviceType, + BOOLEAN READWRITE + ) +{ + EFI_STATUS Status; + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)SataDevInterface->PortCommandTableBaseAddr; + + SataDevInterface->PortNumber=PortNumber; + SataDevInterface->PMPortNumber=PMPortNumber; + SataDevInterface->DeviceType=DeviceType; + + Status = StopController(SataDevInterface,TRUE); + if (EFI_ERROR(Status)) return Status; + + Status = ReadytoAcceptCmd(SataDevInterface); + if (EFI_ERROR(Status)) { + StopController(SataDevInterface,FALSE); + return Status; + } + + BuildCommandList(SataDevInterface, CommandList, SataDevInterface->PortCommandTableBaseAddr); + BuildCommandFIS(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildAtapiCMD(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildPRDT(SataDevInterface, *CommandStructure, CommandList, Commandtable); + + if (READWRITE) { + CommandList->Ahci_Cmd_W = 1; + } else { + CommandList->Ahci_Cmd_W = 0; + } + Commandtable->CFis.Ahci_CFis_C = 1; + + StartController(SataDevInterface, BIT00); + + + Status = WaitforCommandComplete(SataDevInterface, PIO_DATA_IN_CMD, + SataDevInterface->DeviceType == ATA? DMA_ATA_COMMAND_COMPLETE_TIMEOUT \ + : DMA_ATAPI_COMMAND_COMPLETE_TIMEOUT ); + + CommandStructure->ByteCount = CommandList->Ahci_Cmd_PRDBC; + + // + // Stop Controller + // + StopController(SataDevInterface,FALSE); + + return Status; +} + +// +//---------------------------------------------------------------------------- +// Procedure: AhciSmmExecuteNonDataCommand +// +// Description: Exectue the Non Data command +// +// Input: +// IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, +// IN COMMAND_STRUCTURE CommandStructure, +// UINT8 PortNumber, +// UINT8 PMPortNumber, +// DEVICE_TYPE DeviceType, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +AhciSmmExecuteNonDataCommand ( + AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + COMMAND_STRUCTURE CommandStructure, + UINT8 PortNumber, + UINT8 PMPortNumber, + DEVICE_TYPE DeviceType +) +{ + + EFI_STATUS Status; + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)SataDevInterface->PortCommandTableBaseAddr; + + SataDevInterface->PortNumber=PortNumber; + SataDevInterface->PMPortNumber=PMPortNumber; + SataDevInterface->DeviceType=DeviceType; + + Status = StopController(SataDevInterface,TRUE); + if (EFI_ERROR(Status)){ + return Status; + } + + Status = ReadytoAcceptCmd(SataDevInterface); + if (EFI_ERROR(Status)) { + StopController(SataDevInterface,FALSE); + return Status; + } + + BuildCommandList(SataDevInterface, CommandList, SataDevInterface->PortCommandTableBaseAddr); + BuildCommandFIS(SataDevInterface, CommandStructure, CommandList, Commandtable); + + // + // Data-in + // + CommandList->Ahci_Cmd_W = 0; + + // + // Update of Command Register + // + Commandtable->CFis.Ahci_CFis_C = 1; + + StartController(SataDevInterface, BIT00); + + Status = WaitforCommandComplete(SataDevInterface, NON_DATA_CMD, ATAPI_BUSY_CLEAR_TIMEOUT ); + + // + // Stop Controller + // + StopController(SataDevInterface,FALSE); + + return Status; +} +// +//---------------------------------------------------------------------------- +// Procedure: HandleAtapiError +// +// Description: Check for ATAPI Errors +// +// Input: +// IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: ExecutePacketCommand +// +// Notes: +// 1. Execute ATAPI Request Sense command. +// 2. Check for Device getting ready, Media Change, No Media and other errors. Update AtapiDevice->Atapi_Status +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +HandleAtapiError ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface + ) +{ + + EFI_STATUS Status; + UINT8 Data8 = 0; + COMMAND_STRUCTURE CommandStructure; + UINT32 AhciBaseAddr = (UINT32)(SataDevInterface->AhciBaseAddress); + UINT8 Port = SataDevInterface->PortNumber; + ATAPI_DEVICE *AtapiDevice = &SataDevInterface->AtapiDevice; + + AtapiDevice->Atapi_Status = DEVICE_ERROR; + + ZeroMemorySmm (SenseData, 256); + ZeroMemorySmm (&CommandStructure, sizeof(COMMAND_STRUCTURE)); + + CommandStructure.AtapiCmd.Ahci_Atapi_Command[0] = ATAPI_REQUEST_SENSE; + CommandStructure.AtapiCmd.Ahci_Atapi_Command[4] = 0xff; + + CommandStructure.ByteCount = 256; + CommandStructure.Buffer = SenseData; + + Status = AhciSmmExecutePacketCommand(SataDevInterface, &CommandStructure, 0, + Port,SataDevInterface->PMPortNumber,ATAPI); + + if (EFI_ERROR(Status)) { + Data8 = HBA_PORT_REG8 (AhciBaseAddr, Port, HBA_PORTS_TFD); + } + + // Check for DF and CHK + if (Data8 & (DF | CHK)) { + goto exit_HandleAtapiError_with_Reset; + } + + if (!EFI_ERROR(Status)){ + + AtapiDevice->Atapi_Status = DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; // Default Value + + if (((SenseData[2] & 0xf) == 2) && (SenseData[12] == 0x3a)) { + Status = EFI_NO_MEDIA; + AtapiDevice->Atapi_Status = MEDIUM_NOT_PRESENT; + } + if (((SenseData[2] & 0xf) == 2) && (SenseData[12] == 0x04) && (SenseData[13] == 0x01)) { + Status = EFI_MEDIA_CHANGED; + AtapiDevice->Atapi_Status = BECOMING_READY; + } + + if (((SenseData[2] & 0xf) == 6) && (SenseData[12] == 0x28)){ + Status = EFI_MEDIA_CHANGED; + AtapiDevice->Atapi_Status = MEDIA_CHANGED; + } + + if (((SenseData[2] & 0xf) == 7) && (SenseData[12] == 0x27)){ + Status = EFI_WRITE_PROTECTED; + AtapiDevice->Atapi_Status = WRITE_PROTECTED_MEDIA; + } + + if (((SenseData[2] & 0xf) == 6) && (SenseData[12] == 0x29)){ + AtapiDevice->Atapi_Status = POWER_ON_OR_DEVICE_RESET; + } + + if (((SenseData[2] & 0xf) == 5) && (SenseData[0] == 0x70)){ + AtapiDevice->Atapi_Status = ILLEGAL_REQUEST; + } + } + +exit_HandleAtapiError_with_Reset: + return Status; + +} + +// +//---------------------------------------------------------------------------- +// Procedure: AhciSmmExecutePacketCommand +// +// Description: Execute a Atapi Packet command +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// IN COMMAND_STRUCTURE *CommandStructure +// IN BOOLEAN READWRITE +// UINT8 PortNumber, +// UINT8 PMPortNumber, +// DEVICE_TYPE DeviceType +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: StopController, ReadytoAcceptCmd, BuildCommandList, BuildCommandFIS, BuildAtapiCMD +// BuildPRDT, StartController, WaitforCommandComplete +// +// Notes: +// 1. Stop the Controller +// 2. Check if the device is ready to accept a Command. +// 3. Build Command list +// 4. Start the Controller. +// 5. Wait till command completes. Check for errors. +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +AhciSmmExecutePacketCommand ( + AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN COMMAND_STRUCTURE *CommandStructure, + IN BOOLEAN READWRITE, + UINT8 PortNumber, + UINT8 PMPortNumber, + DEVICE_TYPE DeviceType + ) +{ + + EFI_STATUS Status; + AHCI_COMMAND_LIST *CommandList = (AHCI_COMMAND_LIST *) SataDevInterface->PortCommandListBaseAddr; + AHCI_COMMAND_TABLE *Commandtable = (AHCI_COMMAND_TABLE *)SataDevInterface->PortCommandTableBaseAddr; + UINT32 AhciBaseAddr = (UINT32)(SataDevInterface->AhciBaseAddress); + UINT8 Port = SataDevInterface->PortNumber; + UINT8 Data8; + ATAPI_DEVICE *AtapiDevice = &SataDevInterface->AtapiDevice; + + + SataDevInterface->PortNumber=PortNumber; + SataDevInterface->PMPortNumber=PMPortNumber; + SataDevInterface->DeviceType=DeviceType; + + CommandStructure->LBAMid = (UINT8)(CommandStructure->ByteCount); + CommandStructure->LBAHigh = (UINT8)(CommandStructure->ByteCount >> 8); + CommandStructure->Command = PACKET_COMMAND; + + Status = StopController( SataDevInterface,TRUE); + if (EFI_ERROR(Status)) return Status; + + Status = ReadytoAcceptCmd(SataDevInterface); + if (EFI_ERROR(Status)) { + StopController( SataDevInterface,FALSE); + return Status; + } + + BuildCommandList(SataDevInterface, CommandList, SataDevInterface->PortCommandTableBaseAddr); + BuildCommandFIS(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildAtapiCMD(SataDevInterface, *CommandStructure, CommandList, Commandtable); + BuildPRDT(SataDevInterface, *CommandStructure, CommandList, Commandtable); + + + if (READWRITE) { + CommandList->Ahci_Cmd_W = 1; + } + else { + CommandList->Ahci_Cmd_W = 0; + } + Commandtable->CFis.Ahci_CFis_C = 1; + + StartController( SataDevInterface, BIT00); + + Status = WaitforCommandComplete(SataDevInterface, PIO_DATA_IN_CMD, + SataDevInterface->DeviceType == ATA? DMA_ATA_COMMAND_COMPLETE_TIMEOUT \ + : DMA_ATAPI_COMMAND_COMPLETE_TIMEOUT ); + + + // Handle ATAPI device error + if (EFI_ERROR(Status) && SataDevInterface->DeviceType == ATAPI) { + Data8 = HBA_PORT_REG8 (AhciBaseAddr, Port, HBA_PORTS_TFD); + if (Data8 & CHK ){ + return HandleAtapiError(SataDevInterface); + } + } + + AtapiDevice->Atapi_Status = EFI_SUCCESS; + + CommandStructure->ByteCount = CommandList->Ahci_Cmd_PRDBC; + + // Stop Controller + StopController(SataDevInterface,FALSE); + + return Status; + +} + + +// +//---------------------------------------------------------------------------- +// Procedure: AhciSmmInitPortOnS3Resume +// +// Description: Initilize the Sata port on S3 resume +// +// Input: +// IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, +// UINT8 Port, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------------- +// +EFI_STATUS +AhciSmmInitPortOnS3Resume( + AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + UINT8 Port + ) +{ + UINT32 AhciBaseAddr=(UINT32)SataDevInterface->AhciBaseAddress; + // Return error if AhciBase Address is invalid + if(!AhciBaseAddr) { + return EFI_DEVICE_ERROR; + } + + // + //Set the Spin up device on the port + // + + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_SUD); + + WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_SSTS , + HBA_PORTS_SSTS_DET_MASK , + HBA_PORTS_SSTS_DET_PCE , + HBA_PRESENCE_DETECT_TIMEOUT); + + // + //Clear Error Regsiter + // + HBA_PORT_REG32_OR (AhciBaseAddr, Port, + HBA_PORTS_SERR, HBA_PORTS_ERR_CLEAR); // Clear Status register + + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_IS, HBA_PORTS_IS_CLEAR); + + // + //Set the FIS base address + // + gFisBaseAddress=HBA_PORT_REG32(AhciBaseAddr,Port,HBA_PORTS_FB); + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FB,SataDevInterface->PortFISBaseAddr); + + // Enable FIS Receive Enable + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_FRE); + + // Wait till FIS is running + WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_FR, + HBA_PORTS_CMD_FR, + HBA_FR_CLEAR_TIMEOUT); + + // Enable ST + HBA_PORT_REG32_OR (AhciBaseAddr, Port, HBA_PORTS_CMD, HBA_PORTS_CMD_ST); + + // Wait till CR list is running + WaitForMemSet(AhciBaseAddr, Port, HBA_PORTS_CMD, + HBA_PORTS_CMD_CR, + HBA_PORTS_CMD_CR, + HBA_FR_CLEAR_TIMEOUT); + + // + //Restore the FIS base address + // + HBA_PORT_WRITE_REG32(AhciBaseAddr,Port,HBA_PORTS_FB,gFisBaseAddress); + + return EFI_SUCCESS; + +} + +// +//---------------------------------------------------------------------------- +// +// Procedure: InSmmFunction +// +// Description: This function is called from SMM during SMM registration. +// +// Input: +// IN EFI_HANDLE ImageHandle +// IN EFI_SYSTEM_TABLE *SystemTable +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +// +EFI_STATUS InSmmFunction(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status; + UINT32 FisBaseAddress=0; + UINT32 PortCommandListBaseAddr=0; + EFI_SMM_SYSTEM_TABLE *mSmst; + + // + //Initilize the Ahci Base addres to 0 + // + AhciSmm.AhciBaseAddress=0; + + // + // Allocate memory for FIS. Should be aligned on 256 Bytes. Each Port will have it own FIS data area. + // + Status = pBS->AllocatePool (EfiReservedMemoryType, + 1 * RECEIVED_FIS_SIZE + 0x100, + (VOID**)&FisBaseAddress); + + ZeroMemorySmm ((VOID *)FisBaseAddress,1 * RECEIVED_FIS_SIZE + 0x100); + AhciSmm.PortFISBaseAddr =((FisBaseAddress & (~0xFF))+ 0x100); + + // + // Allocate memory for Command List (1KB aligned) and Command Table (128KB aligned). + // All the ports in the controller will share Command List and Command table data Area. + // + Status = pBS->AllocatePool (EfiReservedMemoryType, + COMMAND_LIST_SIZE_PORT * 2, + (VOID**)&PortCommandListBaseAddr); + + ZeroMemorySmm ((VOID *)PortCommandListBaseAddr, COMMAND_LIST_SIZE_PORT * 2); + + // + // Allocate memory for Sense Data + // + Status = pBS->AllocatePool (EfiReservedMemoryType, + 256, + (VOID**)&SenseData); + + AhciSmm.PortCommandListBaseAddr = (PortCommandListBaseAddr & (~0x3FF)) + 0x400; + AhciSmm.PortCommandTableBaseAddr = AhciSmm.PortCommandListBaseAddr + 0x80; + + AhciSmm.AhciSmmInitPortOnS3Resume=AhciSmmInitPortOnS3Resume; + AhciSmm.AhciSmmExecutePioDataCommand=AhciSmmExecutePioDataCommand; + AhciSmm.AhciSmmExecuteDmaDataCommand=AhciSmmExecuteDmaDataCommand; + AhciSmm.AhciSmmExecuteNonDataCommand=AhciSmmExecuteNonDataCommand; + AhciSmm.AhciSmmExecutePacketCommand=AhciSmmExecutePacketCommand; + + + Status = pBS->LocateProtocol(&gEfiSmmBaseProtocolGuid, NULL, &pSmmBase); + if (EFI_ERROR(Status)) { + return Status; + } + + pSmmBase->GetSmstLocation (pSmmBase, &mSmst); + + Status = mSmst->SmmInstallConfigurationTable( + mSmst, + &gAhciSmmProtocolGuid, + &AhciSmm, + sizeof(AHCI_BUS_SMM_PROTOCOL) + ); + + + ASSERT_EFI_ERROR(Status); + + return Status; +} + +// +//---------------------------------------------------------------------------- +// Procedure: AhciSmmDriverEntryPoint +// +// Description: AHCI Smm driver Entry Point +// +// Input: EFI_HANDLE ImageHandle, +// EFI_SYSTEM_TABLE *SystemTable +// +// Output: EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +//---------------------------------------------------------------------------- +// +EFI_STATUS AhciSmmDriverEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + InitAmiLib(ImageHandle, SystemTable); + return InitSmmHandler(ImageHandle, SystemTable, InSmmFunction, NULL); +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AhciSmm/AhciSmm.cif b/Core/EM/Ahci/AhciSmm/AhciSmm.cif new file mode 100644 index 0000000..9ff312d --- /dev/null +++ b/Core/EM/Ahci/AhciSmm/AhciSmm.cif @@ -0,0 +1,14 @@ + + name = "AhciSmm" + category = ModulePart + LocalRoot = "CORE\EM\Ahci\AhciSmm\" + RefName = "AhciSmm" +[files] +"AhciSmm.sdl" +"AhciSmm.mak" +"AhciSmm.dxs" +"AhciSmm.c" +"AhciSmm.h" +[parts] +"AhciSmmProtocols" + diff --git a/Core/EM/Ahci/AhciSmm/AhciSmm.dxs b/Core/EM/Ahci/AhciSmm/AhciSmm.dxs new file mode 100644 index 0000000..c9cad9c --- /dev/null +++ b/Core/EM/Ahci/AhciSmm/AhciSmm.dxs @@ -0,0 +1,87 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/AhciSmm/AhciSmm.dxs 6 2/11/11 4:11a Rameshr $ +// +// $Revision: 6 $ +// +// $Date: 2/11/11 4:11a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/AHCI/AhciSmm/AhciSmm.dxs $ +// +// 6 2/11/11 4:11a Rameshr +// [TAG] EIP53704 +// [Category] Improvement +// [Description] AMI headers update for Alaska Ahci Driver +// [Files] AhciSmm.mak +// AhciSmm.dxs +// AhciSmm.c +// AhciSmm.h +// +// 5 12/13/10 11:15a Krishnakumarg +// [TAG] EIP48678 +// [Category] Action Item +// [Description] AHCI module does not build without CSM +// [Solution] Remove dependecies on CSM that are required for AHCI +// module +// [Files] +// AhciSmm.c +// +// 4 5/07/10 12:40p Krishnakumarg +// Updated the AMI header. +// +// 3 12/09/09 12:32p Fasihm +// EIP#29827: Updated the dependency and added the LegayBoot to the +// dependents. +// +// 2 11/20/09 11:18a Fasihm +// EIP#29827:HDD Password can not be unlocked on AHCI mode when the system +// resume from S3. +// +// 1 4/28/09 6:39p Rameshr +// Initial Check-in +// +// +//********************************************************************** +// +// +// Name: AhciSmm.dxs +// +// Description: This file is the dependency file for the AhciSmm driver +// +// +//********************************************************************** + +#include + +DEPENDENCY_START + EFI_SMM_BASE_PROTOCOL_GUID +DEPENDENCY_END + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AhciSmm/AhciSmm.h b/Core/EM/Ahci/AhciSmm/AhciSmm.h new file mode 100644 index 0000000..81c3d8b --- /dev/null +++ b/Core/EM/Ahci/AhciSmm/AhciSmm.h @@ -0,0 +1,237 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/AHCI/AhciSmm/AhciSmm.h 8 11/24/14 11:56p Kapilporwal $ +// +// $Revision: 8 $ +// +// $Date: 11/24/14 11:56p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/AHCI/AhciSmm/AhciSmm.h $ +// +// 8 11/24/14 11:56p Kapilporwal +// [TAG] EIP191939 +// [Category] Improvement +// [Description] Issue about BIG_REAL_MODE_MMIO_ACCESS of AHCI module +// [Files] AI13.bin +// AHCIACC.ASM +// AhciInt13Dxe.c +// AhciInt13Dxe.dxs +// AhciInt13Smm.c +// AhciInt13Smm.cif +// AhciInt13Smm.dxs +// AhciInt13Smm.h +// AhciInt13Smm.mak +// AhciInt13Smm.sdl +// AInt13.c +// Aint13.cif +// AInt13.h +// AhciSmm.c +// AhciSmm.h +// AhciSmmProtocol.h +// +// 7 9/27/11 3:00a Rajeshms +// [TAG] EIP69295 +// [Category] Improvement +// [Description] The Timeout values used by IDE and AHCI drivers are +// made as SDL tokens, so that the timeout values can be varied. +// [Files] IdeBusBoard.c, CORE_DXE.sdl, AhciSmm.h, AhciBus.h, IDESMM.h, +// Ata.c, Atapi.c, IdeBus.c, IdeBus.h, IdeBusMaster.c, IdeBusBoard.h +// +// 6 3/15/11 4:12a Rameshr +// [TAG]- EIP 51884 +// [Category]- New Feature +// [Description]- Added packet command function in AhciSMM for sending +// command in SMM handler +// [Files]- AhciSmm.c, AhciSmm.h, AhciSmmProtocols.h +// +// 5 2/11/11 4:11a Rameshr +// [TAG] EIP53704 +// [Category] Improvement +// [Description] AMI headers update for Alaska Ahci Driver +// [Files] AhciSmm.mak +// AhciSmm.dxs +// AhciSmm.c +// AhciSmm.h +// +// 4 9/29/10 1:20p Mirk +// [TAG] EIP44641 +// [Synopsis] Calpella: Build error when Token INDEX_DATA_PORT_ACCESS = 1 +// in AhciSrc.sdl +// [Category] Defect +// [Severity] Normal +// [Resolution] Updated AhciSmm.h and AhciSmm.mak to resolve build errors. +// [Files] AhciSmm.h, AhciSmm.mak +// +// 3 5/07/10 2:30p Krishnakumarg +// Updated the date in AMI header +// +// 2 5/07/10 12:38p Krishnakumarg +// Updated the AMI header. +// +// 1 4/28/09 6:39p Rameshr +// Initial Check-in +// +// +//********************************************************************** + +// +//-------------------------------------------------------------------------- +// +// Name: AHCISmm.h +// +// Description: Smm function definition +// +//-------------------------------------------------------------------------- +// +#ifndef _EFI_AHCI_SMM_H_ +#define _EFI_AHCI_SMM_H_ + +#ifndef ATAPI_BUSY_CLEAR_TIMEOUT +#define ATAPI_BUSY_CLEAR_TIMEOUT 16000 // 16sec +#endif + +#ifndef DMA_ATA_COMMAND_COMPLETE_TIMEOUT +#define DMA_ATA_COMMAND_COMPLETE_TIMEOUT 5000 // 5Sec +#endif + +#ifndef DMA_ATAPI_COMMAND_COMPLETE_TIMEOUT +#define DMA_ATAPI_COMMAND_COMPLETE_TIMEOUT 16000 // 16Sec +#endif + +#define COMMAND_LIST_SIZE_PORT 0x800 +#define TIMEOUT_1SEC 1000 // 1sec Serial ATA 1.0 Sec 5.2 + + +#define PCI_CFG_ADDR(bus,dev,func,reg) \ + ((VOID*)(UINTN) (PCIEX_BASE_ADDRESS + ((bus) << 20) + ((dev) << 15) + ((func) << 12) + reg)) + + +EFI_STATUS +AhciSmmExecuteNonDataCommand ( + AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + COMMAND_STRUCTURE CommandStructure, + UINT8 PortNumber, + UINT8 PMPortNumber, + DEVICE_TYPE DeviceType +); + +EFI_STATUS +AhciSmmExecutePioDataCommand ( + AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + COMMAND_STRUCTURE *CommandStructure, + UINT8 PortNumber, + UINT8 PMPortNumber, + DEVICE_TYPE DeviceType, + BOOLEAN READWRITE + ); + +EFI_STATUS +AhciSmmExecuteDmaDataCommand ( + AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + COMMAND_STRUCTURE *CommandStructure, + UINT8 PortNumber, + UINT8 PMPortNumber, + DEVICE_TYPE DeviceType, + BOOLEAN READWRITE +); + +EFI_STATUS +AhciSmmInitPortOnS3Resume( + AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + UINT8 Port + ); + +EFI_STATUS +StartController ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN UINT32 CIBitMask +); + +EFI_STATUS +ReadWritePMPort ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN UINT8 Port, + IN UINT8 RegNum, + IN OUT UINT32 *Data, + IN BOOLEAN READWRITE +); +EFI_STATUS +AhciSmmExecutePacketCommand ( + IN AHCI_BUS_SMM_PROTOCOL *SataDevInterface, + IN COMMAND_STRUCTURE *CommandStructure, + IN BOOLEAN READWRITE, + UINT8 PortNumber, + UINT8 PMPortNumber, + DEVICE_TYPE DeviceType + ); + +#endif + +#if INDEX_DATA_PORT_ACCESS +UINT32 +ReadDataDword( + IN UINTN BaseAddr, + IN UINTN Index +); + +UINT16 +ReadDataWord( + IN UINTN BaseAddr, + IN UINTN Index +); + +UINT8 +ReadDataByte( + IN UINTN BaseAddr, + IN UINTN Index +); + +VOID +WriteDataDword( + IN UINTN BaseAddr, + IN UINTN Index, + IN UINTN Data +); + +VOID +WriteDataWord( + IN UINTN BaseAddr, + IN UINTN Index, + IN UINTN Data +); + +VOID +WriteDataByte( + IN UINTN BaseAddr, + IN UINTN Index, + IN UINTN Data +); +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Ahci/AhciSmm/AhciSmm.mak b/Core/EM/Ahci/AhciSmm/AhciSmm.mak new file mode 100644 index 0000000..80ef21a --- /dev/null +++ b/Core/EM/Ahci/AhciSmm/AhciSmm.mak @@ -0,0 +1,82 @@ +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** +#********************************************************************** +# $Header: /Alaska/SOURCE/Modules/AHCI/AhciSmm/AhciSmm.mak 4 2/11/11 4:11a Rameshr $ +# +# $Revision: 4 $ +# +# $Date: 2/11/11 4:11a $ +#********************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/AHCI/AhciSmm/AhciSmm.mak $ +# +# 4 2/11/11 4:11a Rameshr +# [TAG] EIP53704 +# [Category] Improvement +# [Description] AMI headers update for Alaska Ahci Driver +# [Files] AhciSmm.mak +# AhciSmm.dxs +# AhciSmm.c +# AhciSmm.h +# +# 3 9/29/10 1:20p Mirk +# [TAG] EIP44641 +# [Synopsis] Calpella: Build error when Token INDEX_DATA_PORT_ACCESS = 1 +# in AhciSrc.sdl +# [Category] Defect +# [Severity] Normal +# [Resolution] Updated AhciSmm.h and AhciSmm.mak to resolve build errors. +# [Files] AhciSmm.h, AhciSmm.mak +# +# 2 5/07/10 11:59a Krishnakumarg +# Updated the AMI header. +# +# 1 4/28/09 6:39p Rameshr +# Initial Check-in +# +# +#********************************************************************** +all : AhciSmm + +AhciSmm : $(BUILD_DIR)\AhciSmm.mak AhciSmmBin + +$(BUILD_DIR)\AhciSmm.mak : $(AHCI_SMM_DIR)\AhciSmm.cif $(AHCI_SMM_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(AHCI_SMM_DIR)\AhciSmm.cif $(CIF2MAK_DEFAULTS) $(AHCI_CSP_DIR)\AhciAccess.cif + +AHCI_SMM_INCLUDES=\ + /I$(AHCI_DIR)\ + +AhciSmmBin : $(AMIDXELIB) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\AhciSmm.mak all\ + GUID=BC3245BD-B982-4f55-9F79-056AD7E987C5\ + ENTRY_POINT=AhciSmmDriverEntryPoint\ + "MY_INCLUDES=$(AHCI_SMM_INCLUDES)"\ + TYPE=BS_DRIVER\ + COMPRESS=1 + +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** diff --git a/Core/EM/Ahci/AhciSmm/AhciSmm.sdl b/Core/EM/Ahci/AhciSmm/AhciSmm.sdl new file mode 100644 index 0000000..d187ae4 --- /dev/null +++ b/Core/EM/Ahci/AhciSmm/AhciSmm.sdl @@ -0,0 +1,24 @@ +TOKEN + Name = "AhciSmm_SUPPORT" + Value = "1" + Help = "Main switch to enable AhciSmm support in Project" + TokenType = Boolean + TargetMAK = Yes + Master = Yes +End + +PATH + Name = "AHCI_SMM_DIR" +End + +MODULE + Help = "Includes AhciSmm.mak to Project" + File = "AhciSmm.mak" +End + +ELINK + Name = "$(BUILD_DIR)\AhciSmm.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + diff --git a/Core/EM/Ahci/AhciSources.chm b/Core/EM/Ahci/AhciSources.chm new file mode 100644 index 0000000..4ae32b0 Binary files /dev/null and b/Core/EM/Ahci/AhciSources.chm differ diff --git a/Core/EM/Ahci/AhciSrc.cif b/Core/EM/Ahci/AhciSrc.cif new file mode 100644 index 0000000..9c3053e --- /dev/null +++ b/Core/EM/Ahci/AhciSrc.cif @@ -0,0 +1,19 @@ + + name = "AHCI" + category = eModule + LocalRoot = "Core\em\Ahci\" + RefName = "AHCI" +[files] +"AhciSrc.sdl" +"AhciSrc.mak" +"AhciBus.c" +"AhciController.c" +"AhciComponentName.c" +"AhciBus.h" +"AhciController.h" +"AhciSources.chm" +[parts] +"AINT13" +"ACSP" +"AhciSmm" + diff --git a/Core/EM/Ahci/AhciSrc.mak b/Core/EM/Ahci/AhciSrc.mak new file mode 100644 index 0000000..a22919f --- /dev/null +++ b/Core/EM/Ahci/AhciSrc.mak @@ -0,0 +1,102 @@ +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** + +#********************************************************************** +# $Header: /Alaska/SOURCE/Modules/AHCI/AhciSrc.mak 6 2/10/11 10:35a Rameshr $ +# +# $Revision: 6 $ +# +# $$ +#********************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/AHCI/AhciSrc.mak $ +# +# 6 2/10/11 10:35a Rameshr +# [TAG] EIP53704 +# [Category] Improvement +# [Description] AMI headers update for Alaska Ahci Driver +# [Files] AhciSrc.mak +# AhciBus.c +# AhciController.c +# AhciComponentName.c +# AhciBus.h +# AhciController.h +# +# 5 5/07/10 11:42a Krishnakumarg +# Coding standard update +# +# 4 5/28/08 9:36a Rameshraju +# Based on the SDL token index/data or MMIO method used to access the +# AHCI configuration space. +# +# 3 3/28/08 12:13p Michaela +# Fixed build issue related to component name change +# +# 2 3/02/08 8:16p Fasihm +# Removed the code not to build the cod files. +# +# 1 28/02/08 6:03p Anandakrishnanl +# AHCI Bus Driver initial check-in. +# +#********************************************************************** +# +# +# Name: AhciSrc.mak +# +# Description: +# +# +#********************************************************************** +all : Ahci + +Ahci : $(BUILD_DIR)\AhciSrc.mak AhciBin + +!IF "$(INDEX_DATA_PORT_ACCESS)"=="1" +$(BUILD_DIR)\AhciSrc.mak : $(AHCI_DIR)\$(@B).cif $(AHCI_DIR)\$(@B).mak $(BUILD_RULES) $(AHCI_CSP_DIR)\AhciAccess.cif + $(CIF2MAK) $(AHCI_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) $(AHCI_CSP_DIR)\AhciAccess.cif +!ELSE +$(BUILD_DIR)\AhciSrc.mak : $(AHCI_DIR)\$(@B).cif $(AHCI_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(AHCI_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) +!ENDIF + + +# "CFLAGS = $(CFLAGS) /FAscu /O1 /Fd$(BUILD_DIR)\ /Zi /Gm" \ +# "LFLAGS = $(LFLAGS) /MAP /DEBUG /PDB:$*.pdb" \ +# "CFLAGS = $(CFLAGS:/O1=) /FAscu /Fd$(BUILD_DIR)\ /Zi /Gm" \ +# "LFLAGS= $(LFLAGS) /MAP /DEBUG /PDB:$(BUILD_DIR)\AhciSrc.pdb "\ + +AhciBin: $(AMIDXELIB) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\AhciSrc.mak all\ + MAKEFILE=$(BUILD_DIR)\AhciSrc.mak \ + NAME=AHCI \ + GUID=8F5A2E02-538C-4D59-B920-C4786ACBC552\ + ENTRY_POINT=AhciBusEntryPoint \ + TYPE=BS_DRIVER \ + COMPRESS=1\ + +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** diff --git a/Core/EM/Ahci/AhciSrc.sdl b/Core/EM/Ahci/AhciSrc.sdl new file mode 100644 index 0000000..2fa93d7 --- /dev/null +++ b/Core/EM/Ahci/AhciSrc.sdl @@ -0,0 +1,105 @@ +TOKEN + Name = "AhciSrc_SUPPORT" + Value = "1" + Help = "Main switch to enable IdeBusSrc support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes + Master = Yes +End + +PATH + Name = "AHCI_DIR" + Path = "Core\Em\Ahci" +End + +PATH + Name = "AHCI_CSP_DIR" + Path = "CHIPSET\EM\AHCI" +End + +MODULE + Help = "Includes AhciSrc.mak to Project" + File = "AhciSrc.mak" +End + +ELINK + Name = "$(BUILD_DIR)\Ahci.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + +TOKEN + Name = "PORT_MULTIPLIER_SUPPORT" + Value = "0" + Help = "Switch to Enable/Disable PM Support" + TokenType = Boolean + TargetH = Yes + TargetEQU = Yes + TargetMAK = Yes +End + +TOKEN + Name = "INDEX_DATA_PORT_ACCESS" + Value = "0" + Help = "0-MMIO Access , 1- Index/Port access" + TokenType = Boolean + TargetH = Yes + TargetEQU = Yes + TargetMAK = Yes +End + +TOKEN + Name = "HDD_PASSWORD_SUPPORT_UNDER_RAIDMODE" + Value = "1" + Help = "0-HDD Password not support under Raid mode 1- Enabled" + TokenType = Boolean + TargetH = Yes + TargetEQU = Yes +End + +TOKEN + Name = "SUPPORT_ATAPI_IN_RAID_MODE" + Value = "1" + Help = "1-Under Raid mode , Atapi devices are handled by AhciBus driver. 0 - Raid option rom will handle the Atapi devices." + TokenType = Boolean + TargetH = Yes + TargetEQU = Yes +End + +TOKEN + Name = "DiPM_SUPPORT" + Value = "0" + Help = "Support Device Initiated Power Management" + TokenType = Boolean + TargetEQU = Yes + TargetH = Yes +End + +TOKEN + Name = "ENABLE_DIPM" + Value = "0" + Help = " 0 - Disable Device Initiated Power Management Feature. 1 - Enable DipM Feature" + TokenType = Boolean + TargetEQU = Yes + TargetH = Yes +End + +TOKEN + Name = "DEVICE_SLEEP_SUPPORT" + Value = "0" + Help = "Enable/Disable Token to support Device Sleep" + TokenType = Boolean + TargetEQU = Yes + TargetH = Yes +End + +TOKEN + Name = "ENABLE_DEVICE_SLEEP" + Value = "0" + Help = " 0 - Disable Device Sleep Feature. 1 - Enable Device Sleep Feature" + TokenType = Boolean + TargetEQU = Yes + TargetH = Yes +End diff --git a/Core/EM/Ahci/Aint13.cif b/Core/EM/Ahci/Aint13.cif new file mode 100644 index 0000000..4c93b5b --- /dev/null +++ b/Core/EM/Ahci/Aint13.cif @@ -0,0 +1,18 @@ + + name = "AHCI Int13" + category = ModulePart + LocalRoot = "Core\eM\Ahci" + RefName = "AINT13" +[files] +"Aint13.sdl" +"Aint13.mak" +"Aint13.inf" +"AInt13.h" +"AInt13.c" +"AInt13.dxs" +[parts] +"AHCI_INT13INIT_PROTOCOL" +"AHCI_BINARY" +"AHCI_INT13_CSP" +"AhciInt13Smm" + diff --git a/Core/EM/Ahci/Aint13.inf b/Core/EM/Ahci/Aint13.inf new file mode 100644 index 0000000..79226bb --- /dev/null +++ b/Core/EM/Ahci/Aint13.inf @@ -0,0 +1,5 @@ +[MODULE] +ModuleID = 1 +VendorID = 0 +DeviceID = 1 +File = Addon\AI13.BIN diff --git a/Core/EM/Ahci/Aint13.mak b/Core/EM/Ahci/Aint13.mak new file mode 100644 index 0000000..a6988fe --- /dev/null +++ b/Core/EM/Ahci/Aint13.mak @@ -0,0 +1,105 @@ +#//**********************************************************************// +#//**********************************************************************// +#//** **// +#//** (C)Copyright 1985-2013, American Megatrends, Inc. **// +#//** **// +#//** All Rights Reserved. **// +#//** **// +#//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **// +#//** **// +#//** Phone: (770)-246-8600 **// +#//** **// +#//**********************************************************************// +#//**********************************************************************// + +#************************************************************************// +# $Header: /Alaska/SOURCE/Modules/AHCI/INT13/Aint13.mak 7 8/28/13 12:38a Rameshr $ +# +# $Revision: 7 $ +# +# $Date: 8/28/13 12:38a $ +#************************************************************************// +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/AHCI/INT13/Aint13.mak $ +# +# 7 8/28/13 12:38a Rameshr +# [TAG] EIP134204 +# [Category] Improvement +# [Description] Build Error resolved if token INDEX_DATA_PORT_ACCESS is +# enabled. +# [Files] Aint13.mak +# +# 6 6/07/11 12:02p Olegi +# [TAG] EIP61801 +# [Category] Improvement +# [Description] Added dependency on LegacyBios protocol. +# +# 5 2/10/11 10:49a Rameshr +# [TAG] EIP53704 +# [Category] Improvement +# [Description] AMI headers update for Alaska Ahci Driver +# [Files] Aint13.mak +# AInt13.h +# AInt13.c +# +# 4 5/28/08 9:41a Rameshraju +# Updated the AMI Address. +# +# 3 3/28/08 12:14p Michaela +# updated copyright +# +# 2 28/02/08 6:12p Anandakrishnanl +# Added the flags in the Build process. +# +# 1 12/07/07 11:17a Olegi +# +#************************************************************************// + +all: AHCIINT13 AHCIINT13CSP + +!IF "$(INDEX_DATA_PORT_ACCESS)"=="1" +$(BUILD_DIR)\aint13.mak : $(AINT13_DIR)\aint13.cif $(AHCI_CSP_DIR)\ahcicsp.cif $(AHCI_CSP_DIR)\AhciAccess.cif $(AINT13_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(CIF2MAK_DEFAULTS) $(AINT13_DIR)\aint13.cif $(AHCI_CSP_DIR)\ahcicsp.cif $(AHCI_CSP_DIR)\AhciAccess.cif +!ELSE +$(BUILD_DIR)\aint13.mak: $(AINT13_DIR)\aint13.cif $(AHCI_CSP_DIR)\ahcicsp.cif $(AINT13_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(CIF2MAK_DEFAULTS) $(AINT13_DIR)\aint13.cif $(AHCI_CSP_DIR)\ahcicsp.cif +!ENDIF + +AHCIINT13: $(BUILD_DIR)\aint13.mak AHCIINT13BIN + +AHCI_OBJECTS = \ +$(BUILD_DIR)\$(AINT13_DIR)\aint13.obj \ +!IF "$(INDEX_DATA_PORT_ACCESS)"=="1" +$(BUILD_DIR)\$(AHCI_CSP_DIR)\AhciAccess.obj \ +!ENDIF +$(BUILD_DIR)\$(AHCI_CSP_DIR)\aint13csp.obj + +AHCIINT13BIN: $(AMIDXELIB) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\aint13.mak all\ + GUID=67820532-7613-4dd3-9ED7-3D9BE3A7DA63\ + "OBJECTS=$(AHCI_OBJECTS)"\ + ENTRY_POINT=Ai13EntryPoint\ + TYPE=BS_DRIVER\ + COMPRESS=1\ + DEPEX1=$(AINT13_DIR)\aint13.dxs \ + +AHCIINT13CSP: $(BUILD_DIR)\ahciacc.obj + +$(BUILD_DIR)\ahciacc.obj: $(AHCI_CSP_DIR)\ahciacc.asm + $(ASM) /c /nologo /Fo$(BUILD_DIR)\ /Fl$(BUILD_DIR)\ $(AHCI_CSP_DIR)\ahciacc.asm + +#//**********************************************************************// +#//**********************************************************************// +#//** **// +#//** (C)Copyright 1985-2013, American Megatrends, Inc. **// +#//** **// +#//** All Rights Reserved. **// +#//** **// +#//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **// +#//** **// +#//** Phone: (770)-246-8600 **// +#//** **// +#//**********************************************************************// +#//**********************************************************************// diff --git a/Core/EM/Ahci/Aint13.sdl b/Core/EM/Ahci/Aint13.sdl new file mode 100644 index 0000000..4a51110 --- /dev/null +++ b/Core/EM/Ahci/Aint13.sdl @@ -0,0 +1,67 @@ +TOKEN + Name = "AINT13_SUPPORT" + Value = "1" + Help = "Main switch to enable AHCI Int13 support in the project." + TokenType = Boolean + TargetMAK = Yes + TargetH = Yes + Master = Yes + Token = "CSM_SUPPORT" "=" "1" +End + + +TOKEN + Name = "AHCI_CONTROLLER_COUNT" + Value = "1" + Help = "The controller count can range from 1-6" + TokenType = Integer + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes + Range = "1-6" +End + +TOKEN + Name = "AI13_BINARY_VERSION" + Value = "5714" + Help = "Version of AI13.bin. Higher 2 digits represent CSM version and lower 2 digits represent AI13.bin build number" + TokenType = Integer + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes +End + +PATH + Name = "AINT13_DIR" +End + +MODULE + Help = "Includes Aint13.mak" + File = "Aint13.mak" +End + +ELINK + Name = "AhciApiModuleStart" + Parent = "CsmOem16Functions" + ProcID = 07h + SrcFile = "$(AHCI_CSP_DIR)\ahciacc.asm" + InvokeOrder = AfterParent +End + +ELINK + Name = "$(AINT13_DIR)\aint13.inf" + Parent = "CSM_CUSTOM_INFS" + InvokeOrder = AfterParent +End + +ELINK + Name = "$(BUILD_DIR)\ahciacc.obj" + Parent = "CSM_OEM16_OBJS" + InvokeOrder = AfterParent +End + +ELINK + Name = "$(BUILD_DIR)\aint13.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End -- cgit v1.2.3