diff options
Diffstat (limited to 'Core/EM/Ahci/AhciBus.c')
-rw-r--r-- | Core/EM/Ahci/AhciBus.c | 4477 |
1 files changed, 4477 insertions, 0 deletions
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. +// +// +// +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: AhciBus.c +// +// Description: Provides AHCI Block IO protocol +// +//<AMI_FHDR_END> +//********************************************************************** + +#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 + +}; + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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. +// +//<AMI_PHDR_END> +//********************************************************************** +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; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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 +// +//<AMI_PHDR_END> +//********************************************************************** +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; + +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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. +// +//<AMI_PHDR_END> +//********************************************************************** +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; +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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. +// +//<AMI_PHDR_END> +//********************************************************************** +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; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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. +// +//<AMI_PHDR_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; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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 +// +//<AMI_PHDR_END> +//********************************************************************** +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; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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 +// +//<AMI_PHDR_END> +//********************************************************************** +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; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// 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. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +CheckPortImplemented ( + IN AHCI_BUS_PROTOCOL *AhciBusInterface, + IN UINT8 Port +) +{ + + if (AhciBusInterface->HBAPortImplemented & (1<< Port)) return EFI_SUCCESS; + + return EFI_NOT_FOUND; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// 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. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// 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. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// 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 +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ConfigureSataPort +// +// Description: Configure Sata Port settings +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface, +// +// Output: +// EFI_SUCCESS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// 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. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// 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. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// 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 +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InitializeDipm +// +// Description: Initialize Dipm in the device and controller +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// VOID +// +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InitializeDeviceSleep +// +// Description: Initialize Device Sleep in the device and controller +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// VOID +// +// +// Notes: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// 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 +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// 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: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// 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: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: ReturnMSBset +// +// Description: Returns the MOST significant Bit set. +// +// Input: +// IN UINT32 Data +// +// Output: +// UINT8 +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//<AMI_PHDR_END> +//********************************************************************** +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; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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. +// +//<AMI_PHDR_END> +//********************************************************************** +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; + +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: GetEnumOddType +// +// Description: Get the Enum value for ODD type found on profile +// +// Input: +// +// UINT16 Oddtype +// Output: +// ODD_TYPE EnumValue +// +// Modified: +// +// Referrals: +// +// Notes: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; + } + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: InitSataDiskInfo +// +// Description: Initializes SATA DiskInfo Interface +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: AllocatePool +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +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; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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. +// +//<AMI_PHDR_END> +//********************************************************************** +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 +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: InitMiscConfig +// +// Description: Initialize misc IDE configurations. +// +// Input: +// IN SATA_DEVICE_INTERFACE *SataDevInterface +// +// Output: +// None +// +//<AMI_PHDR_END> +//********************************************************************** +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 + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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 +// +//<AMI_PHDR_END> +//********************************************************************** +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 +//********************************************************************** +//<AMI_PHDR_START> +// +// 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 +// +//<AMI_PHDR_END> +//********************************************************************** +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 + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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 +// +//<AMI_PHDR_END> +//********************************************************************** +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; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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. +// +// +//<AMI_PHDR_END> +//********************************************************************** +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; + } +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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. +// +// +//<AMI_PHDR_END> +//********************************************************************** +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; + +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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. +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +DiskInfoSenseData( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT VOID *SenseData, + OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber + ) + +{ + + return EFI_NOT_FOUND; + +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// 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 +// +//<AMI_PHDR_END> +//********************************************************************** +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 ** +//** ** +//********************************************************************** +//********************************************************************** |