From 878ddf1fc3540a715f63594ed22b6929e881afb4 Mon Sep 17 00:00:00 2001 From: bbahnsen Date: Fri, 21 Apr 2006 22:54:32 +0000 Subject: Initial import. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524 --- EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c | 224 ++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h | 118 + .../Bus/Pci/IdeBus/Dxe/DriverConfiguration.c | 378 ++ .../Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c | 225 ++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c | 3690 ++++++++++++++++++++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c | 2591 ++++++++++++++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml | 74 + EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c | 1964 +++++++++++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h | 1806 ++++++++++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c | 1400 ++++++++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h | 439 +++ EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd | 45 + EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa | 90 + EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd | 44 + EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa | 86 + EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h | 879 +++++ 16 files changed, 14053 insertions(+) create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa create mode 100644 EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h (limited to 'EdkModulePkg/Bus/Pci/IdeBus') diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c new file mode 100644 index 0000000000..8008527dd1 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c @@ -0,0 +1,224 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.c + +Abstract: + +--*/ + +#include "IDEBus.h" + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName = { + IDEBusComponentNameGetDriverName, + IDEBusComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mIDEBusDriverNameTable[] = { + { "eng", (CHAR16 *) L"PCI IDE/ATAPI Bus Driver" }, + { NULL , NULL } +}; + +STATIC EFI_UNICODE_STRING_TABLE mIDEBusControllerNameTable[] = { + { "eng", (CHAR16 *) L"PCI IDE/ATAPI Controller" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +IDEBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + DriverName - A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gIDEBusComponentName.SupportedLanguages, + mIDEBusDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +IDEBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language + specified by Language from the point of view of the + driver specified by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + // + // Get the controller context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiCallerIdGuid, + NULL, + gIDEBusDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (ChildHandle == NULL) { + return LookupUnicodeString ( + Language, + gIDEBusComponentName.SupportedLanguages, + mIDEBusControllerNameTable, + ControllerName + ); + } + + // + // Get the child context + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + gIDEBusDriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlockIo); + + return LookupUnicodeString ( + Language, + gIDEBusComponentName.SupportedLanguages, + IdeBlkIoDevice->ControllerNameTable, + ControllerName + ); +} + +VOID +AddName ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr + ) +/*++ + + Routine Description: + Add the component name for the IDE/ATAPI device + + Arguments: + IdeBlkIoDevicePtr - A pointer to the IDE_BLK_IO_DEV instance. + + Returns: + +--*/ +{ + UINTN StringIndex; + CHAR16 ModelName[41]; + + // + // Add Component Name for the IDE/ATAPI device that was discovered. + // + IdeBlkIoDevicePtr->ControllerNameTable = NULL; + for (StringIndex = 0; StringIndex < 41; StringIndex++) { + ModelName[StringIndex] = IdeBlkIoDevicePtr->ModelName[StringIndex]; + } + + AddUnicodeString ( + "eng", + gIDEBusComponentName.SupportedLanguages, + &IdeBlkIoDevicePtr->ControllerNameTable, + ModelName + ); +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h new file mode 100644 index 0000000000..f6c3feb436 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h @@ -0,0 +1,118 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ComponentName.h + +Abstract: + + +Revision History +--*/ + +#ifndef _IDE_BUS_COMPONENT_NAME_H +#define _IDE_BUS_COMPONENT_NAME_H + + +#ifndef EFI_SIZE_REDUCTION_APPLIED + +#define ADD_NAME(x) AddName ((x)); + +extern EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName; + +#else + +#define ADD_NAME(x) + +#endif + + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +IDEBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Language - TODO: add argument description + DriverName - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ControllerHandle - TODO: add argument description + ChildHandle - TODO: add argument description + Language - TODO: add argument description + ControllerName - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +AddName ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevicePtr - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c new file mode 100644 index 0000000000..b8f71fdc8d --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c @@ -0,0 +1,378 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DriverConfiguration.c + +Abstract: + +--*/ + +#include "IDEBus.h" + +CHAR16 *OptionString[4] = { + L"Enable Primary Master (Y/N)? -->", + L"Enable Primary Slave (Y/N)? -->", + L"Enable Secondary Master (Y/N)? -->", + L"Enable Secondary Slave (Y/N)? -->" +}; +// +// EFI Driver Configuration Functions +// +EFI_STATUS +IDEBusDriverConfigurationSetOptions ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ); + +EFI_STATUS +IDEBusDriverConfigurationOptionsValid ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL + ); + +EFI_STATUS +IDEBusDriverConfigurationForceDefaults ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN UINT32 DefaultType, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ); + +// +// EFI Driver Configuration Protocol +// +EFI_DRIVER_CONFIGURATION_PROTOCOL gIDEBusDriverConfiguration = { + IDEBusDriverConfigurationSetOptions, + IDEBusDriverConfigurationOptionsValid, + IDEBusDriverConfigurationForceDefaults, + "eng" +}; + +EFI_STATUS +GetResponse ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + None + +Returns: + + EFI_ABORTED - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + EFI_NOT_FOUND - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + + while (TRUE) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (!EFI_ERROR (Status)) { + if (Key.ScanCode == SCAN_ESC) { + return EFI_ABORTED; + } + + switch (Key.UnicodeChar) { + + // + // fall through + // + case L'y': + case L'Y': + gST->ConOut->OutputString (gST->ConOut, L"Y\n"); + return EFI_SUCCESS; + + // + // fall through + // + case L'n': + case L'N': + gST->ConOut->OutputString (gST->ConOut, L"N\n"); + return EFI_NOT_FOUND; + } + + } + } +} + +EFI_STATUS +IDEBusDriverConfigurationSetOptions ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ) +/*++ + + Routine Description: + Allows the user to set controller specific options for a controller that a + driver is currently managing. + + Arguments: + This - A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL + instance. + ControllerHandle - The handle of the controller to set options on. + ChildHandle - The handle of the child controller to set options on. + This is an optional parameter that may be NULL. + It will be NULL for device drivers, and for a bus drivers + that wish to set options for the bus controller. + It will not be NULL for a bus driver that wishes to set + options for one of its child controllers. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the user interface + that should be presented to the user, and it must match + one of the languages specified in SupportedLanguages. + The number of languages supported by a driver is up to + the driver writer. + ActionRequired - A pointer to the action that the calling agent is + required to perform when this function returns. + See "Related Definitions" for a list of the actions that + the calling agent is required to perform prior to + accessing ControllerHandle again. + + Returns: + EFI_SUCCESS - The driver specified by This successfully set the + configuration options for the controller specified + by ControllerHandle.. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a + valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ActionRequired is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support + setting configuration options for the controller + specified by ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + EFI_DEVICE_ERROR - A device error occurred while attempt to set the + configuration options for the controller specified + by ControllerHandle and ChildHandle. + EFI_OUT_RESOURCES - There are not enough resources available to set the + configuration options for the controller specified + by ControllerHandle and ChildHandle. + +--*/ +{ + EFI_STATUS Status; + UINT8 Value; + UINT8 NewValue; + UINTN DataSize; + UINTN Index; + UINT32 Attributes; + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + *ActionRequired = EfiDriverConfigurationActionNone; + + DataSize = sizeof (Value); + Status = gRT->GetVariable ( + L"Configuration", + &gEfiCallerIdGuid, + &Attributes, + &DataSize, + &Value + ); + + gST->ConOut->OutputString (gST->ConOut, L"IDE Bus Driver Configuration\n"); + gST->ConOut->OutputString (gST->ConOut, L"===============================\n"); + + NewValue = 0; + for (Index = 0; Index < 4; Index++) { + gST->ConOut->OutputString (gST->ConOut, OptionString[Index]); + + Status = GetResponse (); + if (Status == EFI_ABORTED) { + return EFI_SUCCESS; + } + + if (!EFI_ERROR (Status)) { + NewValue |= (UINT8) (1 << Index); + } + } + + if (EFI_ERROR (Status) || (NewValue != Value)) { + gRT->SetVariable ( + L"Configuration", + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (NewValue), + &NewValue + ); + + *ActionRequired = EfiDriverConfigurationActionRestartController; + } else { + *ActionRequired = EfiDriverConfigurationActionNone; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +IDEBusDriverConfigurationOptionsValid ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL + ) +/*++ + + Routine Description: + Tests to see if a controller's current configuration options are valid. + + Arguments: + This - A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL + instance. + ControllerHandle - The handle of the controller to test if it's current + configuration options are valid. + ChildHandle - The handle of the child controller to test if it's + current + configuration options are valid. This is an optional + parameter that may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers that + wish to test the configuration options for the bus + controller. It will not be NULL for a bus driver that + wishes to test configuration options for one of + its child controllers. + + Returns: + EFI_SUCCESS - The controller specified by ControllerHandle and + ChildHandle that is being managed by the driver + specified by This has a valid set of configuration + options. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_UNSUPPORTED - The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + EFI_DEVICE_ERROR - The controller specified by ControllerHandle and + ChildHandle that is being managed by the driver + specified by This has an invalid set of + configuration options. + +--*/ +{ + EFI_STATUS Status; + UINT8 Value; + UINTN DataSize; + UINT32 Attributes; + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + DataSize = sizeof (Value); + Status = gRT->GetVariable ( + L"Configuration", + &gEfiCallerIdGuid, + &Attributes, + &DataSize, + &Value + ); + if (EFI_ERROR (Status) || Value > 0x0f) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +IDEBusDriverConfigurationForceDefaults ( + IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN UINT32 DefaultType, + OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired + ) +/*++ + + Routine Description: + Forces a driver to set the default configuration options for a controller. + + Arguments: + This - A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL + instance. + ControllerHandle - The handle of the controller to force default + configuration options on. + ChildHandle - The handle of the child controller to force default + configuration options on This is an optional parameter + that may be NULL. It will be NULL for device drivers. + It will also be NULL for a bus drivers that wish to + force default configuration options for the bus + controller. It will not be NULL for a bus driver that + wishes to force default configuration options for one + of its child controllers. + DefaultType - The type of default configuration options to force on + the controller specified by ControllerHandle and + ChildHandle. See Table 9-1 for legal values. + A DefaultType of 0x00000000 must be supported + by this protocol. + ActionRequired - A pointer to the action that the calling agent + is required to perform when this function returns. + + + Returns: + EFI_SUCCESS - The driver specified by This successfully forced + the default configuration options on the + controller specified by ControllerHandle and + ChildHandle. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a + valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ActionRequired is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support + forcing the default configuration options on + the controller specified by ControllerHandle + and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support + the configuration type specified by DefaultType. + EFI_DEVICE_ERROR - A device error occurred while attempt to force + the default configuration options on the controller + specified by ControllerHandle and ChildHandle. + EFI_OUT_RESOURCES - There are not enough resources available to force + the default configuration options on the controller + specified by ControllerHandle and ChildHandle. + +--*/ +{ + UINT8 Value; + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + Value = 0x0f; + gRT->SetVariable ( + L"Configuration", + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (Value), + &Value + ); + *ActionRequired = EfiDriverConfigurationActionRestartController; + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c new file mode 100644 index 0000000000..ce3be14234 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c @@ -0,0 +1,225 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + DriverDiagnostics.c + +Abstract: + +--*/ + +#include "IDEBus.h" + +#define IDE_BUS_DIAGNOSTIC_ERROR L"PCI IDE/ATAPI Driver Diagnostics Failed" + +// +// EFI Driver Diagnostics Functions +// +EFI_STATUS +IDEBusDriverDiagnosticsRunDiagnostics ( + IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType, + IN CHAR8 *Language, + OUT EFI_GUID **ErrorType, + OUT UINTN *BufferSize, + OUT CHAR16 **Buffer + ); + +// +// EFI Driver Diagnostics Protocol +// +EFI_DRIVER_DIAGNOSTICS_PROTOCOL gIDEBusDriverDiagnostics = { + IDEBusDriverDiagnosticsRunDiagnostics, + "eng" +}; + +EFI_STATUS +IDEBusDriverDiagnosticsRunDiagnostics ( + IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType, + IN CHAR8 *Language, + OUT EFI_GUID **ErrorType, + OUT UINTN *BufferSize, + OUT CHAR16 **Buffer + ) +/*++ + + Routine Description: + Runs diagnostics on a controller. + + Arguments: + This - A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOL + instance. + ControllerHandle - The handle of the controller to run diagnostics on. + ChildHandle - The handle of the child controller to run diagnostics on + This is an optional parameter that may be NULL. It will + be NULL for device drivers. It will also be NULL for a + bus drivers that wish to run diagnostics on the bus + controller. It will not be NULL for a bus driver that + wishes to run diagnostics on one of its child + controllers. + DiagnosticType - Indicates type of diagnostics to perform on the + controller specified by ControllerHandle and ChildHandle. + See "Related Definitions" for the list of supported + types. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language in which the optional + error message should be returned in Buffer, and it must + match one of the languages specified in + SupportedLanguages. The number of languages supported by + a driver is up to the driver writer. + ErrorType - A GUID that defines the format of the data returned in + Buffer. + BufferSize - The size, in bytes, of the data returned in Buffer. + Buffer - A buffer that contains a Null-terminated Unicode string + plus some additional data whose format is defined by + ErrorType. Buffer is allocated by this function with + AllocatePool(), and it is the caller's responsibility + to free it with a call to FreePool(). + + Returns: + EFI_SUCCESS - The controller specified by ControllerHandle and + ChildHandle passed the diagnostic. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ErrorType is NULL. + EFI_INVALID_PARAMETER - BufferType is NULL. + EFI_INVALID_PARAMETER - Buffer is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support + running diagnostics for the controller specified + by ControllerHandle and ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + type of diagnostic specified by DiagnosticType. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + EFI_OUT_OF_RESOURCES - There are not enough resources available to complete + the diagnostics. + EFI_OUT_OF_RESOURCES - There are not enough resources available to return + the status information in ErrorType, BufferSize, + and Buffer. + EFI_DEVICE_ERROR - The controller specified by ControllerHandle and + ChildHandle did not pass the diagnostic. + +--*/ +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + IDE_BLK_IO_DEV *IdeBlkIoDevice; + UINT32 VendorDeviceId; + VOID *BlockBuffer; + + *ErrorType = NULL; + *BufferSize = 0; + + if (ChildHandle == NULL) { + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiCallerIdGuid, + NULL, + gIDEBusDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + gIDEBusDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Use services of PCI I/O Protocol to test the PCI IDE/ATAPI Controller + // The following test simply reads the Device ID and Vendor ID. + // It should never fail. A real test would perform more advanced + // diagnostics. + // + + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, 1, &VendorDeviceId); + if (EFI_ERROR (Status) || VendorDeviceId == 0xffffffff) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + } + + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo, + gIDEBusDriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo); + + // + // Use services available from IdeBlkIoDevice to test the IDE/ATAPI device + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + IdeBlkIoDevice->BlkMedia.BlockSize, + (VOID **) &BlockBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = IdeBlkIoDevice->BlkIo.ReadBlocks ( + &IdeBlkIoDevice->BlkIo, + IdeBlkIoDevice->BlkMedia.MediaId, + 0, + IdeBlkIoDevice->BlkMedia.BlockSize, + BlockBuffer + ); + + if (EFI_ERROR (Status)) { + *ErrorType = &gEfiCallerIdGuid; + *BufferSize = sizeof (IDE_BUS_DIAGNOSTIC_ERROR); + + Status = gBS->AllocatePool ( + EfiBootServicesData, + (UINTN) (*BufferSize), + (VOID **) Buffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + EfiCopyMem (*Buffer, IDE_BUS_DIAGNOSTIC_ERROR, *BufferSize); + + Status = EFI_DEVICE_ERROR; + } + + gBS->FreePool (BlockBuffer); + + return Status; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c new file mode 100644 index 0000000000..88e81c0ada --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c @@ -0,0 +1,3690 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ata.c + +Abstract: + +Revision History + + 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including + update - ATAIdentity() func + update - AtaBlockIoReadBlocks() func + update - AtaBlockIoWriteBlocks() func + add - AtaAtapi6Identify() func + add - AtaReadSectorsExt() func + add - AtaWriteSectorsExt() func + add - AtaPioDataInExt() func + add - AtaPioDataOutExt() func + +--*/ + +#include "idebus.h" + + +EFI_STATUS +AtaReadSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN OUT VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ); + +EFI_STATUS +AtaWriteSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ); + +EFI_STATUS +AtaPioDataInExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN OUT VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ); + +EFI_STATUS +AtaPioDataOutExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ); + +EFI_STATUS +ATAIdentify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + ATAIdentify + + + Purpose: + This function is called by DiscoverIdeDevice() during its device + identification. It sends out the ATA Identify Command to the + specified device. Only ATA device responses to this command. If + the command succeeds, it returns the Identify data structure which + contains information about the device. This function extracts the + information it needs to fill the IDE_BLK_IO_DEV data structure, + including device type, media block size, media capacity, and etc. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. + + + Returns: + EFI_SUCCESS + Identify ATA device successfully. + + EFI_DEVICE_ERROR + ATA Identify Device Command failed or device is not + ATA device. + + + Notes: + parameter IdeDev will be updated in this function. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_IDENTIFY_DATA *AtaIdentifyPointer; + UINT32 Capacity; + UINT8 DeviceSelect; + + // + // AtaIdentifyPointer is used for accommodating returned IDENTIFY data of + // the ATA Identify command + // + AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA)); + + // + // use ATA PIO Data In protocol to send ATA Identify command + // and receive data from device + // + DeviceSelect = 0; + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + Status = AtaPioDataIn ( + IdeDev, + (VOID *) AtaIdentifyPointer, + sizeof (EFI_IDENTIFY_DATA), + IDENTIFY_DRIVE_CMD, + DeviceSelect, + 0, + 0, + 0, + 0 + ); + // + // If ATA Identify command succeeds, then according to the received + // IDENTIFY data, + // identify the device type ( ATA or not ). + // If ATA device, fill the information in IdeDev. + // If not ATA device, return IDE_DEVICE_ERROR + // + if (!EFI_ERROR (Status)) { + + IdeDev->pIdData = AtaIdentifyPointer; + + // + // Print ATA Module Name + // + PrintAtaModuleName (IdeDev); + + // + // bit 15 of pAtaIdentify->config is used to identify whether device is + // ATA device or ATAPI device. + // if 0, means ATA device; if 1, means ATAPI device. + // + if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) { + // + // Detect if support S.M.A.R.T. If yes, enable it as default + // + AtaSMARTSupport (IdeDev); + + // + // Check whether this device needs 48-bit addressing (ATAPI-6 ata device) + // + Status = AtaAtapi6Identify (IdeDev); + if (!EFI_ERROR (Status)) { + // + // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify() + // + return EFI_SUCCESS; + } + // + // This is a hard disk <= 120GB capacity, treat it as normal hard disk + // + IdeDev->Type = IdeHardDisk; + + // + // Block Media Information: + // Media->LogicalPartition , Media->WriteCaching will be filled + // in the DiscoverIdeDevcie() function. + // + IdeDev->BlkIo.Media->IoAlign = 4; + IdeDev->BlkIo.Media->MediaId = 1; + IdeDev->BlkIo.Media->RemovableMedia = FALSE; + IdeDev->BlkIo.Media->MediaPresent = TRUE; + IdeDev->BlkIo.Media->ReadOnly = FALSE; + IdeDev->BlkIo.Media->BlockSize = 0x200; + + // + // Calculate device capacity + // + Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) | + AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ; + IdeDev->BlkIo.Media->LastBlock = Capacity - 1; + + return EFI_SUCCESS; + + } + } + + gBS->FreePool (AtaIdentifyPointer); + // + // Make sure the pIdData will not be freed again. + // + IdeDev->pIdData = NULL; + + return EFI_DEVICE_ERROR; +} + + +EFI_STATUS +AtaAtapi6Identify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + + AtaAtapi6Identify + + Purpose: + + This function is called by ATAIdentify() to identity whether this disk + supports ATA/ATAPI6 48bit addressing, ie support >120G capacity + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + + EFI_SUCCESS - The disk specified by IdeDev is a Atapi6 supported one + and 48-bit addressing must be used + + EFI_UNSUPPORTED - The disk dosn't not support Atapi6 or it supports but + the capacity is below 120G, 48bit addressing is not + needed + + Notes: + + This function must be called after DEVICE_IDENTITY command has been + successfully returned +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + UINT8 Index; + EFI_LBA TmpLba; + EFI_LBA Capacity; + EFI_IDENTIFY_DATA *Atapi6IdentifyStruct; + + if (IdeDev->pIdData == NULL) { + return EFI_UNSUPPORTED; + } + + Atapi6IdentifyStruct = IdeDev->pIdData; + + if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & bit10) == 0) { + // + // The device dosn't support 48 bit addressing + // + return EFI_UNSUPPORTED; + } + + // + // 48 bit address feature set is supported, get maximum capacity + // + Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0]; + for (Index = 1; Index < 4; Index++) { + // + // Lower byte goes first: word[100] is the lowest word, word[103] is highest + // + TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index]; + Capacity |= LShiftU64 (TmpLba, 16 * Index); + } + + if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) { + // + // Capacity exceeds 120GB. 48-bit addressing is really needed + // + IdeDev->Type = Ide48bitAddressingHardDisk; + + // + // Fill block media information:Media->LogicalPartition , + // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function. + // + IdeDev->BlkIo.Media->IoAlign = 4; + IdeDev->BlkIo.Media->MediaId = 1; + IdeDev->BlkIo.Media->RemovableMedia = FALSE; + IdeDev->BlkIo.Media->MediaPresent = TRUE; + IdeDev->BlkIo.Media->ReadOnly = FALSE; + IdeDev->BlkIo.Media->BlockSize = 0x200; + IdeDev->BlkIo.Media->LastBlock = Capacity - 1; + + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +VOID +PrintAtaModuleName ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + PrintAtaModuleName + + + Purpose: + This function is called by ATAIdentify() or ATAPIIdentify() + to print device's module name. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + no returns. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + if (IdeDev->pIdData == NULL) { + return ; + } + + SwapStringChars (IdeDev->ModelName, IdeDev->pIdData->AtaData.ModelName, 40); + IdeDev->ModelName[40] = 0x00; +} + +EFI_STATUS +AtaPioDataIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN UINT8 Head, + IN UINT8 SectorCount, + IN UINT8 SectorNumber, + IN UINT8 CylinderLsb, + IN UINT8 CylinderMsb + ) +/*++ + Name: + AtaPioDataIn + + + Purpose: + This function is used to send out ATA commands conforms to the + PIO Data In Protocol. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + buffer contained data transferred from device to host. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINT8 IN AtaCommand + value of the Command Register + + UINT8 IN Head + value of the Head/Device Register + + UINT8 IN SectorCount + value of the Sector Count Register + + UINT8 IN SectorNumber + value of the Sector Number Register + + UINT8 IN CylinderLsb + value of the low byte of the Cylinder Register + + UINT8 IN CylinderMsb + value of the high byte of the Cylinder Register + + + Returns: + EFI_SUCCESS + send out the ATA command and device send required + data successfully. + + EFI_DEVICE_ERROR + command sent failed. + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: AtaCommand - add argument and description to function comment +// TODO: Head - add argument and description to function comment +// TODO: SectorCount - add argument and description to function comment +// TODO: SectorNumber - add argument and description to function comment +// TODO: CylinderLsb - add argument and description to function comment +// TODO: CylinderMsb - add argument and description to function comment +{ + UINTN WordCount; + UINTN Increment; + UINT16 *Buffer16; + EFI_STATUS Status; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // e0:1110,0000-- bit7 and bit5 are reserved bits. + // bit6 set means LBA mode + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head) + ); + + // + // All ATAPI device's ATA commands can be issued regardless of the + // state of the DRDY + // + if (IdeDev->Type == IdeHardDisk) { + + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + // + // set all the command parameters + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (AtaCommand == SET_FEATURES_CMD) { + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03); + } + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb); + + // + // send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + Buffer16 = (UINT16 *) Buffer; + + // + // According to PIO data in protocol, host can perform a series of reads to + // the data register after each time device set DRQ ready; + // The data size of "a series of read" is command specific. + // For most ATA command, data size received from device will not exceed + // 1 sector, hence the data size for "a series of read" can be the whole data + // size of one command request. + // For ATA command such as Read Sector command, the data size of one ATA + // command request is often larger than 1 sector, according to the + // Read Sector command, the data size of "a series of read" is exactly 1 + // sector. + // Here for simplification reason, we specify the data size for + // "a series of read" to 1 sector (256 words) if data size of one ATA command + // request is larger than 256 words. + // + Increment = 256; + + // + // used to record bytes of currently transfered data + // + WordCount = 0; + + while (WordCount < ByteCount / 2) { + // + // Poll DRQ bit set, data transfer can be performed only when DRQ is ready. + // + Status = DRQReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = CheckErrorStatus (IdeDev); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Get the byte count for one series of read + // + if ((WordCount + Increment) > ByteCount / 2) { + Increment = ByteCount / 2 - WordCount; + } + + IDEReadPortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + Increment, + Buffer16 + ); + + WordCount += Increment; + Buffer16 += Increment; + + } + + DRQClear (IdeDev, ATATIMEOUT); + + return CheckErrorStatus (IdeDev); +} + +EFI_STATUS +AtaPioDataOut ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN UINT8 Head, + IN UINT8 SectorCount, + IN UINT8 SectorNumber, + IN UINT8 CylinderLsb, + IN UINT8 CylinderMsb + ) +/*++ + Name: + AtaPioDataOut + + + Purpose: + This function is used to send out ATA commands conforms to the + PIO Data Out Protocol. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + buffer contained data transferred from host to device. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINT8 IN AtaCommand + value of the Command Register + + UINT8 IN Head + value of the Head/Device Register + + UINT8 IN SectorCount + value of the Sector Count Register + + UINT8 IN SectorNumber + value of the Sector Number Register + + UINT8 IN CylinderLsb + value of the low byte of the Cylinder Register + + UINT8 IN CylinderMsb + value of the high byte of the Cylinder Register + + + Returns: + EFI_SUCCESS + send out the ATA command and device received required + data successfully. + + EFI_DEVICE_ERROR + command sent failed. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: AtaCommand - add argument and description to function comment +// TODO: Head - add argument and description to function comment +// TODO: SectorCount - add argument and description to function comment +// TODO: SectorNumber - add argument and description to function comment +// TODO: CylinderLsb - add argument and description to function comment +// TODO: CylinderMsb - add argument and description to function comment +{ + UINTN WordCount; + UINTN Increment; + UINT16 *Buffer16; + EFI_STATUS Status; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // select device via Head/Device register. + // Before write Head/Device register, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // e0:1110,0000-- bit7 and bit5 are reserved bits. + // bit6 set means LBA mode + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head) + ); + + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // set all the command parameters + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb); + + // + // send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + Buffer16 = (UINT16 *) Buffer; + + // + // According to PIO data out protocol, host can perform a series of + // writes to the data register after each time device set DRQ ready; + // The data size of "a series of read" is command specific. + // For most ATA command, data size written to device will not exceed 1 sector, + // hence the data size for "a series of write" can be the data size of one + // command request. + // For ATA command such as Write Sector command, the data size of one + // ATA command request is often larger than 1 sector, according to the + // Write Sector command, the data size of "a series of read" is exactly + // 1 sector. + // Here for simplification reason, we specify the data size for + // "a series of write" to 1 sector (256 words) if data size of one ATA command + // request is larger than 256 words. + // + Increment = 256; + WordCount = 0; + + while (WordCount < ByteCount / 2) { + + // + // DRQReady2-- read Alternate Status Register to determine the DRQ bit + // data transfer can be performed only when DRQ is ready. + // + Status = DRQReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = CheckErrorStatus (IdeDev); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Check the remaining byte count is less than 512 bytes + // + if ((WordCount + Increment) > ByteCount / 2) { + Increment = ByteCount / 2 - WordCount; + } + // + // perform a series of write without check DRQ ready + // + + IDEWritePortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + Increment, + Buffer16 + ); + WordCount += Increment; + Buffer16 += Increment; + + } + + DRQClear (IdeDev, ATATIMEOUT); + + return CheckErrorStatus (IdeDev); +} + +EFI_STATUS +CheckErrorStatus ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + CheckErrorStatus + + + Purpose: + This function is used to analyze the Status Register and print out + some debug information and if there is ERR bit set in the Status + Register, the Error Register's value is also be parsed and print out. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + No err information in the Status Register. + + EFI_DEVICE_ERROR + Any err information in the Status Register. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + UINT8 StatusRegister; + +//#ifdef EFI_DEBUG + + UINT8 ErrorRegister; + +//#endif + + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + DEBUG_CODE ( + + if (StatusRegister & DWF) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Write Fault\n", + StatusRegister) + ); + } + + if (StatusRegister & CORR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Corrected Data\n", + StatusRegister) + ); + } + + if (StatusRegister & ERR) { + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + + if (ErrorRegister & BBK_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n", + ErrorRegister) + ); + } + + if (ErrorRegister & UNC_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n", + ErrorRegister) + ); + } + + if (ErrorRegister & MC_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Media Change\n", + ErrorRegister) + ); + } + + if (ErrorRegister & ABRT_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Abort\n", + ErrorRegister) + ); + } + + if (ErrorRegister & TK0NF_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n", + ErrorRegister) + ); + } + + if (ErrorRegister & AMNF_ERR) { + DEBUG ( + (EFI_D_BLKIO, + "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n", + ErrorRegister) + ); + } + + } + ); + + if ((StatusRegister & (ERR | DWF | CORR)) == 0) { + return EFI_SUCCESS; + } + + return EFI_DEVICE_ERROR; + +} + +EFI_STATUS +AtaReadSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + AtaReadSectors + + + Purpose: + This function is called by the AtaBlkIoReadBlocks() to perform + reading from media in block unit. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the destination buffer for the data. + + EFI_LBA IN Lba + The starting logical block address to read from + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + return status is fully dependent on the return status + of AtaPioDataIn() function. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: Lba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + EFI_STATUS Status; + UINTN BlocksRemaining; + UINT32 Lba32; + UINT8 Lba0; + UINT8 Lba1; + UINT8 Lba2; + UINT8 Lba3; + UINT8 AtaCommand; + UINT8 SectorCount8; + UINT16 SectorCount; + UINTN ByteCount; + VOID *Buffer; + + Buffer = DataBuffer; + + // + // Using ATA Read Sector(s) command (opcode=0x20) with PIO DATA IN protocol + // + AtaCommand = READ_SECTORS_CMD; + + + BlocksRemaining = NumberOfBlocks; + + Lba32 = (UINT32) Lba; + + Status = EFI_SUCCESS; + + while (BlocksRemaining > 0) { + + // + // in ATA-3 spec, LBA is in 28 bit width + // + Lba0 = (UINT8) Lba32; + Lba1 = (UINT8) (Lba32 >> 8); + Lba2 = (UINT8) (Lba32 >> 16); + // + // low 4 bit of Lba3 stands for LBA bit24~bit27. + // + Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f); + + if (BlocksRemaining >= 0x100) { + + // + // SectorCount8 is sent to Sector Count register, 0x00 means 256 + // sectors to be read + // + SectorCount8 = 0x00; + // + // SectorCount is used to record the number of sectors to be read + // + SectorCount = 256; + } else { + + SectorCount8 = (UINT8) BlocksRemaining; + SectorCount = (UINT16) BlocksRemaining; + } + + // + // ByteCount is the number of bytes that will be read + // + ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); + + // + // call AtaPioDataIn() to send Read Sector Command and receive data read + // + Status = AtaPioDataIn ( + IdeDev, + Buffer, + (UINT32) ByteCount, + AtaCommand, + Lba3, + SectorCount8, + Lba0, + Lba1, + Lba2 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba32 += SectorCount; + Buffer = ((UINT8 *) Buffer + ByteCount); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtaWriteSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *BufferData, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + AtaWriteSectors + + + Purpose: + This function is called by the AtaBlkIoWriteBlocks() to perform + writing onto media in block unit. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. + + VOID IN *BufferData + A pointer to the source buffer for the data. + + EFI_LBA IN Lba + The starting logical block address to write onto + the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + + Returns: + return status is fully dependent on the return status + of AtaPioDataOut() function. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: BufferData - add argument and description to function comment +// TODO: Lba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + EFI_STATUS Status; + UINTN BlocksRemaining; + UINT32 Lba32; + UINT8 Lba0; + UINT8 Lba1; + UINT8 Lba2; + UINT8 Lba3; + UINT8 AtaCommand; + UINT8 SectorCount8; + UINT16 SectorCount; + UINTN ByteCount; + VOID *Buffer; + + Buffer = BufferData; + + // + // Using Write Sector(s) command (opcode=0x30) with PIO DATA OUT protocol + // + AtaCommand = WRITE_SECTORS_CMD; + + BlocksRemaining = NumberOfBlocks; + + Lba32 = (UINT32) Lba; + + Status = EFI_SUCCESS; + + while (BlocksRemaining > 0) { + + Lba0 = (UINT8) Lba32; + Lba1 = (UINT8) (Lba32 >> 8); + Lba2 = (UINT8) (Lba32 >> 16); + Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f); + + if (BlocksRemaining >= 0x100) { + + // + // SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors + // to be written + // + SectorCount8 = 0x00; + // + // SectorCount is used to record the number of sectors to be written + // + SectorCount = 256; + } else { + + SectorCount8 = (UINT8) BlocksRemaining; + SectorCount = (UINT16) BlocksRemaining; + } + + ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); + + Status = AtaPioDataOut ( + IdeDev, + Buffer, + (UINT32) ByteCount, + AtaCommand, + Lba3, + SectorCount8, + Lba0, + Lba1, + Lba2 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba32 += SectorCount; + Buffer = ((UINT8 *) Buffer + ByteCount); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtaSoftReset ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtaSoftReset + + Purpose: + This function is used to implement the Soft Reset on the specified + device. But, the ATA Soft Reset mechanism is so strong a reset method + that it will force resetting on both devices connected to the + same cable. + It is called by IdeBlkIoReset(), a interface function of Block + I/O protocol. + This function can also be used by the ATAPI device to perform reset when + ATAPI Reset command is failed. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + Returns: + EFI_SUCCESS + Soft reset completes successfully. + + EFI_DEVICE_ERROR + Any step during the reset process is failed. + Notes: + The registers initial values after ATA soft reset are different + to the ATA device and ATAPI device. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + + UINT8 DeviceControl; + + DeviceControl = 0; + // + // set SRST bit to initiate soft reset + // + DeviceControl |= SRST; + + // + // disable Interrupt + // + DeviceControl |= bit1; + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + gBS->Stall (10); + + // + // Enable interrupt to support UDMA, and clear SRST bit + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + // + // slave device needs at most 31s to clear BSY + // + if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaBlkIoReadBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + Name: + AtaBlkIoReadBlocks + + + Purpose: + This function is the ATA implementation for ReadBlocks in the + Block I/O Protocol interface. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeBlkIoDevice + Indicates the calling context. + + UINT32 IN MediaId + The media id that the read request is for. + + EFI_LBA IN LBA + The starting logical block address to read from + on the device. + + UINTN IN BufferSize + The size of the Buffer in bytes. This must be a + multiple of the intrinsic block size of the device. + + VOID OUT *Buffer + A pointer to the destination buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the memory that data is read into. + + Returns: + EFI_SUCCESS + Read Blocks successfully. + + EFI_DEVICE_ERROR + Read Blocks failed. + + EFI_NO_MEDIA + There is no media in the device. + + EFI_MEDIA_CHANGE + The MediaId is not for the current media. + + EFI_BAD_BUFFER_SIZE + The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + + EFI_INVALID_PARAMETER + The read request contains LBAs that are not valid, + or the data buffer is not valid. + + Notes: + If Read Block error because of device error, this function will call + AtaSoftReset() function to reset device. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeBlkIoDevice - add argument and description to function comment +// TODO: MediaId - add argument and description to function comment +// TODO: LBA - add argument and description to function comment +// TODO: BufferSize - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: EFI_MEDIA_CHANGED - add return value to function comment +{ + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + EFI_STATUS Status; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + Status = EFI_SUCCESS; + + // + // Get the intrinsic block size + // + Media = IdeBlkIoDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + + NumberOfBlocks = BufferSize / BlockSize; + + if (MediaId != Media->MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (!(Media->MediaPresent)) { + return EFI_NO_MEDIA; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) { + // + // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism + // + Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + } + } else { + // + // For ATA-3 compatible device, use ATA-3 read block mechanism + // Notice DMA operation can only handle 32bit address + // + if ((UINTN) Buffer <= 0xFFFFFFFF) { + Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + } + + if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) { + Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + } + } + + if (EFI_ERROR (Status)) { + AtaSoftReset (IdeBlkIoDevice); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +AtaBlkIoWriteBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + Name: + AtaBlkIoWriteBlocks + + + Purpose: + This function is the ATA implementation for WriteBlocks in the + Block I/O Protocol interface. + + Parameters: + IDE_BLK_IO_DEV IN *IdeBlkIoDevice + Indicates the calling context. + + UINT32 IN MediaId + The media id that the write request is for. + + EFI_LBA IN LBA + The starting logical block address to write onto + the device. + + UINTN IN BufferSize + The size of the Buffer in bytes. This must be a + multiple of the intrinsic block size of the device. + + VOID OUT *Buffer + A pointer to the source buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the memory that data is + written from. + + + Returns: + EFI_SUCCESS + Write Blocks successfully. + + EFI_DEVICE_ERROR + Write Blocks failed. + + EFI_NO_MEDIA + There is no media in the device. + + EFI_MEDIA_CHANGE + The MediaId is not for the current media. + + EFI_BAD_BUFFER_SIZE + The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + + EFI_INVALID_PARAMETER + The write request contains LBAs that are not valid, + or the data buffer is not valid. + + Notes: + If Write Block error because of device error, this function will call + AtaSoftReset() function to reset device. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeBlkIoDevice - add argument and description to function comment +// TODO: MediaId - add argument and description to function comment +// TODO: LBA - add argument and description to function comment +// TODO: BufferSize - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: EFI_MEDIA_CHANGED - add return value to function comment +{ + + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + EFI_STATUS Status; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + Status = EFI_SUCCESS; + + // + // Get the intrinsic block size + // + Media = IdeBlkIoDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + NumberOfBlocks = BufferSize / BlockSize; + + if (MediaId != Media->MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) { + // + // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism + // + Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + } + } else { + // + // For ATA-3 compatible device, use ATA-3 write block mechanism + // + Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) { + Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + } + } + + if (EFI_ERROR (Status)) { + AtaSoftReset (IdeBlkIoDevice); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaReadSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaReadSectorsExt + + Purpose: + + This function is called by the AtaBlkIoReadBlocks() to perform + reading from media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the destination buffer for the data. + + EFI_LBA IN StartLba + The starting logical block address to read from + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + return status is fully dependent on the return status + of AtaPioDataInExt() function. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + EFI_STATUS Status; + UINTN BlocksRemaining; + EFI_LBA Lba64; + UINT8 AtaCommand; + UINT16 SectorCount; + UINT32 ByteCount; + VOID *Buffer; + + // + // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol + // + AtaCommand = READ_SECTORS_EXT_CMD; + Buffer = DataBuffer; + BlocksRemaining = NumberOfBlocks; + Lba64 = StartLba; + Status = EFI_SUCCESS; + + while (BlocksRemaining > 0) { + + if (BlocksRemaining >= 0x10000) { + // + // SectorCount is used to record the number of sectors to be read + // Max 65536 sectors can be transfered at a time. + // + SectorCount = 0xffff; + } else { + SectorCount = (UINT16) BlocksRemaining; + } + + // + // ByteCount is the number of bytes that will be read + // + ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); + + // + // call AtaPioDataInExt() to send Read Sector Command and receive data read + // + Status = AtaPioDataInExt ( + IdeDev, + Buffer, + ByteCount, + AtaCommand, + Lba64, + SectorCount + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba64 += SectorCount; + Buffer = ((UINT8 *) Buffer + ByteCount); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtaWriteSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaWriteSectorsExt + + Purpose: + + This function is called by the AtaBlkIoWriteBlocks() to perform + writing onto media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the source buffer for the data. + + EFI_LBA IN Lba + The starting logical block address to write onto + the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + return status is fully dependent on the return status + of AtaPioDataOutExt() function. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_LBA Lba64; + UINTN BlocksRemaining; + UINT8 AtaCommand; + UINT16 SectorCount; + UINT32 ByteCount; + VOID *Buffer; + + // + // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol + // + AtaCommand = WRITE_SECTORS_EXT_CMD; + Lba64 = StartLba; + Buffer = DataBuffer; + BlocksRemaining = NumberOfBlocks; + + Status = EFI_SUCCESS; + + while (BlocksRemaining > 0) { + + if (BlocksRemaining >= 0x10000) { + // + // SectorCount is used to record the number of sectors to be written. + // Max 65536 sectors can be transfered at a time. + // + SectorCount = 0xffff; + } else { + SectorCount = (UINT16) BlocksRemaining; + } + + // + // ByteCount is the number of bytes that will be written + // + ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize); + + // + // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command + // + Status = AtaPioDataOutExt ( + IdeDev, + Buffer, + ByteCount, + AtaCommand, + Lba64, + SectorCount + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba64 += SectorCount; + Buffer = ((UINT8 *) Buffer + ByteCount); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtaPioDataInExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN OUT VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ) +/*++ + Name: + + AtaPioDataInExt + + Purpose: + + This function is used to send out ATA commands conforms to the + PIO Data In Protocol, supporting ATA/ATAPI-6 standard + + Comparing with ATA-3 data in protocol, we have two differents here: + 1. Do NOT wait for DRQ clear before sending command into IDE device.(the + wait will frequently fail... cause writing function return error) + + 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly + slow down writing performance by 100 times!) + + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN OUT *Buffer + buffer contained data transferred from device to host. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINT8 IN AtaCommand + value of the Command Register + + EFI_LBA IN StartLba + the start LBA of this transaction + + UINT16 IN SectorCount + the count of sectors to be transfered + + Returns: + + EFI_SUCCESS + send out the ATA command and device send required + data successfully. + + EFI_DEVICE_ERROR + command sent failed. + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: AtaCommand - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: SectorCount - add argument and description to function comment +{ + UINT8 DevSel; + UINT8 SectorCount8; + UINT8 LbaLow; + UINT8 LbaMid; + UINT8 LbaHigh; + UINTN WordCount; + UINTN Increment; + UINT16 *Buffer16; + EFI_STATUS Status; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device, set bit6 as 1 to indicate LBA mode is used + // + DevSel = (UINT8) (IdeDev->Device << 4); + DevSel |= 0x40; + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + DevSel + ); + + // + // Wait for DRDY singnal asserting. ATAPI device needn't wait + // + if ( (IdeDev->Type == IdeHardDisk) || + (IdeDev->Type == Ide48bitAddressingHardDisk)) { + + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + // + // Fill feature register if needed + // + if (AtaCommand == SET_FEATURES_CMD) { + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03); + } + + // + // Fill the sector count register, which is a two-byte FIFO. Need write twice. + // + SectorCount8 = (UINT8) (SectorCount >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + SectorCount8 = (UINT8) SectorCount; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + // + // Fill the start LBA registers, which are also two-byte FIFO + // + LbaLow = (UINT8) RShiftU64 (StartLba, 24); + LbaMid = (UINT8) RShiftU64 (StartLba, 32); + LbaHigh = (UINT8) RShiftU64 (StartLba, 40); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + LbaLow = (UINT8) StartLba; + LbaMid = (UINT8) RShiftU64 (StartLba, 8); + LbaHigh = (UINT8) RShiftU64 (StartLba, 16); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + // + // Send command via Command Register, invoking the processing of this command + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + Buffer16 = (UINT16 *) Buffer; + + // + // According to PIO data in protocol, host can perform a series of reads to + // the data register after each time device set DRQ ready; + // + + // + // 256 words + // + Increment = 256; + + // + // used to record bytes of currently transfered data + // + WordCount = 0; + + while (WordCount < ByteCount / 2) { + // + // Poll DRQ bit set, data transfer can be performed only when DRQ is ready. + // + Status = DRQReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = CheckErrorStatus (IdeDev); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Get the byte count for one series of read + // + if ((WordCount + Increment) > ByteCount / 2) { + Increment = ByteCount / 2 - WordCount; + } + + IDEReadPortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + Increment, + Buffer16 + ); + + WordCount += Increment; + Buffer16 += Increment; + + } + + return CheckErrorStatus (IdeDev); +} + +EFI_STATUS +AtaPioDataOutExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ) +/*++ + Name: + + AtaPioDataOutExt + + Purpose: + + This function is used to send out ATA commands conforms to the + PIO Data Out Protocol, supporting ATA/ATAPI-6 standard + + Comparing with ATA-3 data out protocol, we have two differents here: + 1. Do NOT wait for DRQ clear before sending command into IDE device.(the + wait will frequently fail... cause writing function return error) + + 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly + slow down writing performance by 100 times!) + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + buffer contained data transferred from host to device. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINT8 IN AtaCommand + value of the Command Register + + EFI_LBA IN StartLba + the start LBA of this transaction + + UINT16 IN SectorCount + the count of sectors to be transfered + + Returns: + + EFI_SUCCESS + send out the ATA command and device receive required + data successfully. + + EFI_DEVICE_ERROR + command sent failed. + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: AtaCommand - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: SectorCount - add argument and description to function comment +{ + UINT8 DevSel; + UINT8 SectorCount8; + UINT8 LbaLow; + UINT8 LbaMid; + UINT8 LbaHigh; + UINTN WordCount; + UINTN Increment; + UINT16 *Buffer16; + EFI_STATUS Status; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device. Set bit6 as 1 to indicate LBA mode is used + // + DevSel = (UINT8) (IdeDev->Device << 4); + DevSel |= 0x40; + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + DevSel + ); + + // + // Wait for DRDY singnal asserting. + // + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Fill feature register if needed + // + if (AtaCommand == SET_FEATURES_CMD) { + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03); + } + + // + // Fill the sector count register, which is a two-byte FIFO. Need write twice. + // + SectorCount8 = (UINT8) (SectorCount >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + SectorCount8 = (UINT8) SectorCount; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + // + // Fill the start LBA registers, which are also two-byte FIFO + // + LbaLow = (UINT8) RShiftU64 (StartLba, 24); + LbaMid = (UINT8) RShiftU64 (StartLba, 32); + LbaHigh = (UINT8) RShiftU64 (StartLba, 40); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + LbaLow = (UINT8) StartLba; + LbaMid = (UINT8) RShiftU64 (StartLba, 8); + LbaHigh = (UINT8) RShiftU64 (StartLba, 16); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + // + // Send command via Command Register, invoking the processing of this command + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + Buffer16 = (UINT16 *) Buffer; + + // + // According to PIO Data Out protocol, host can perform a series of writes to + // the data register after each time device set DRQ ready; + // + Increment = 256; + + // + // used to record bytes of currently transfered data + // + WordCount = 0; + + while (WordCount < ByteCount / 2) { + // + // Poll DRQ bit set, data transfer can be performed only when DRQ is ready. + // + Status = DRQReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = CheckErrorStatus (IdeDev); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Write data into device by one series of writing to data register + // + if ((WordCount + Increment) > ByteCount / 2) { + Increment = ByteCount / 2 - WordCount; + } + + IDEWritePortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + Increment, + Buffer16 + ); + + WordCount += Increment; + Buffer16 += Increment; + + } + // + // while + // + + return CheckErrorStatus (IdeDev); +} + + +VOID +AtaSMARTSupport ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtaSMARTSupport + + Purpose: + + Enable SMART of the disk if supported + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. + + Returns: + + NONE +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + EFI_STATUS Status; + BOOLEAN SMARTSupported; + UINT8 Device; + EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer; + UINT8 DeviceSelect; + UINT8 LBAMid; + UINT8 LBAHigh; + + // + // Detect if the device supports S.M.A.R.T. + // + if ((IdeDev->pIdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) { + // + // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one) + // + return ; + } else { + if ((IdeDev->pIdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) { + // + // S.M.A.R.T is not supported by the device + // + SMARTSupported = FALSE; + } else { + SMARTSupported = TRUE; + } + } + + if (!SMARTSupported) { + // + // Report nonsupport status code + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED) + ); + } else { + // + // Enable this feature + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE) + ); + + Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); + Status = AtaNonDataCommandIn ( + IdeDev, + ATA_SMART_CMD, + Device, + ATA_SMART_ENABLE_OPERATION, + 0, + 0, + ATA_CONSTANT_4F, + ATA_CONSTANT_C2 + ); + // + // Detect if this feature is enabled + // + TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA)); + + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + Status = AtaPioDataIn ( + IdeDev, + (VOID *) TmpAtaIdentifyPointer, + sizeof (EFI_IDENTIFY_DATA), + IDENTIFY_DRIVE_CMD, + DeviceSelect, + 0, + 0, + 0, + 0 + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (TmpAtaIdentifyPointer); + return ; + } + + // + // Check if the feature is enabled + // + if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) { + // + // Read status data + // + AtaNonDataCommandIn ( + IdeDev, + ATA_SMART_CMD, + Device, + ATA_SMART_RETURN_STATUS, + 0, + 0, + ATA_CONSTANT_4F, + ATA_CONSTANT_C2 + ); + LBAMid = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb); + LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb); + + if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) { + // + // The threshold exceeded condition is not detected by the device + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD) + ); + + } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) { + // + // The threshold exceeded condition is detected by the device + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD) + ); + } + + } else { + // + // Report disabled status code + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED) + ); + } + + gBS->FreePool (TmpAtaIdentifyPointer); + } + + return ; +} + +EFI_STATUS +AtaCommandIssueExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + Send ATA Ext command into device with NON_DATA protocol + +Arguments: + + IdeDev - Standard IDE device private data structure + AtaCommand - The ATA command to be sent + Device - The value in Device register + Feature - The value in Feature register + SectorCount - The value in SectorCount register + LbaAddress - The LBA address in 48-bit mode + +Returns: + + EFI_SUCCESS - Reading succeed + EFI_DEVICE_ERROR - Error executing commands on this device + +--*/ +{ + EFI_STATUS Status; + UINT8 SectorCount8; + UINT8 Feature8; + UINT8 LbaLow; + UINT8 LbaMid; + UINT8 LbaHigh; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility) + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + + // + // ATA commands for ATA device must be issued when DRDY is set + // + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Pass parameter into device register block + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + // + // Fill the feature register, which is a two-byte FIFO. Need write twice. + // + Feature8 = (UINT8) (Feature >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); + + Feature8 = (UINT8) Feature; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); + + // + // Fill the sector count register, which is a two-byte FIFO. Need write twice. + // + SectorCount8 = (UINT8) (SectorCount >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + SectorCount8 = (UINT8) SectorCount; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + // + // Fill the start LBA registers, which are also two-byte FIFO + // + LbaLow = (UINT8) RShiftU64 (LbaAddress, 24); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + LbaLow = (UINT8) LbaAddress; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + + LbaMid = (UINT8) RShiftU64 (LbaAddress, 32); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + LbaMid = (UINT8) RShiftU64 (LbaAddress, 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + + LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + // + // Work around for Segate 160G disk writing + // + gBS->Stall (1800); + + // + // Send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + // + // Stall at least 400ns + // + gBS->Stall (100); + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaCommandIssue ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + Send ATA Ext command into device with NON_DATA protocol + +Arguments: + + IdeDev - Standard IDE device private data structure + AtaCommand - The ATA command to be sent + Device - The value in Device register + Feature - The value in Feature register + SectorCount - The value in SectorCount register + LbaAddress - The LBA address in 48-bit mode + +Returns: + + EFI_SUCCESS - Reading succeed + EFI_DEVICE_ERROR - Error executing commands on this device + +--*/ +{ + EFI_STATUS Status; + UINT8 SectorCount8; + UINT8 Feature8; + UINT8 Lba0; + UINT8 Lba1; + UINT8 Lba2; + UINT8 Lba3; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility) + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + + // + // ATA commands for ATA device must be issued when DRDY is set + // + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Lba0 = (UINT8) LbaAddress; + Lba1 = (UINT8) RShiftU64 (LbaAddress, 8); + Lba2 = (UINT8) RShiftU64 (LbaAddress, 16); + Lba3 = (UINT8) RShiftU64 (LbaAddress, 24); + Device |= Lba3; + + // + // Pass parameter into device register block + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + // + // Fill the feature register, which is a two-byte FIFO. Need write twice. + // + Feature8 = (UINT8) Feature; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); + + // + // Fill the sector count register, which is a two-byte FIFO. Need write twice. + // + SectorCount8 = (UINT8) SectorCount; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + // + // Fill the start LBA registers, which are also two-byte FIFO + // + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2); + + // + // Send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + // + // Stall at least 400ns + // + gBS->Stall (100); + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaUdmaReadExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaUdmaReadExt + + Purpose: + + This function is called by the AtaBlkIoReadBlocks() to perform + reading from media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the destination buffer for the data. + + EFI_LBA IN StartLba + The starting logical block address to read from + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + The device status of UDMA operation. If the operation is + successful, return EFI_SUCCESS. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_DMA_PRD *PrdAddr; + IDE_DMA_PRD *UsedPrdAddr; + IDE_DMA_PRD *TempPrdAddr; + UINT8 RegisterValue; + UINT8 Device; + UINT64 IoPortForBmic; + UINT64 IoPortForBmis; + UINT64 IoPortForBmid; + EFI_STATUS Status; + UINTN PrdTableNum; + UINTN ByteCount; + UINTN ByteAvailable; + UINT8 *PrdBuffer; + UINTN RemainBlockNum; + UINT8 DeviceControl; + + // + // Channel and device differential. Select device. + // + Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); + + // + // Enable interrupt to support UDMA and Select device + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + if (IdePrimary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET; + } else { + if (IdeSecondary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET; + } else { + return EFI_UNSUPPORTED; + } + } + + RemainBlockNum = NumberOfBlocks; + while (RemainBlockNum > 0) { + + if (RemainBlockNum >= MAX_DMA_EXT_COMMAND_SECTORS) { + // + // SectorCount is used to record the number of sectors to be read + // Max 65536 sectors can be transfered at a time. + // + NumberOfBlocks = MAX_DMA_EXT_COMMAND_SECTORS; + RemainBlockNum -= MAX_DMA_EXT_COMMAND_SECTORS; + } else { + NumberOfBlocks = (UINT16) RemainBlockNum; + RemainBlockNum = 0; + } + + // + // Calculate the number of PRD table to make sure the memory region + // not cross 64K boundary + // + ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + PrdTableNum = ((ByteCount >> 16) + 1) + 1; + + // + // Build PRD table + // + PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD))); + + // + // To make sure PRD is allocated in one 64K page + // + if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000); + } else { + if ((UINTN) PrdAddr & 0x03) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC); + } else { + UsedPrdAddr = PrdAddr; + } + } + + // + // Build the PRD table + // + PrdBuffer = DataBuffer; + TempPrdAddr = UsedPrdAddr; + while (TRUE) { + + ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF); + + if (ByteCount <= ByteAvailable) { + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteCount; + TempPrdAddr->EndOfTable = 0x8000; + break; + } + + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteAvailable; + + ByteCount -= ByteAvailable; + PrdBuffer += ByteAvailable; + TempPrdAddr++; + } + + // + // Set the base address to BMID register + // + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmid, + 1, + &UsedPrdAddr + ); + + // + // Set BMIC register to identify the operation direction + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_nREAD; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Read BMIS register and clear ERROR and INTR bit + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + RegisterValue |= BMIS_INTERRUPT | BMIS_ERROR; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + // + // Issue READ DMA EXT command + // + Status = AtaCommandIssueExt ( + IdeDev, + READ_DMA_EXT_CMD, + Device, + 0, + (UINT16) NumberOfBlocks, + StartLba + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_START; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Check the INTERRUPT and ERROR bit of BMIS + // + while (TRUE) { + + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) { + if (RegisterValue & BMIS_ERROR) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + break; + } + + gBS->Stall (1000); + } + + gBS->FreePool (PrdAddr); + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue &= ~((UINT8) BMIC_START); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + if (RegisterValue & BMIS_ERROR) { + return EFI_DEVICE_ERROR; + } + + DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + StartLba += NumberOfBlocks; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaUdmaRead ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaUdmaRead + + Purpose: + + This function is called by the AtaBlkIoReadBlocks() to perform + reading from media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the destination buffer for the data. + + EFI_LBA IN StartLba + The starting logical block address to read from + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + The device status of UDMA operation. If the operation is + successful, return EFI_SUCCESS. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_DMA_PRD *PrdAddr; + IDE_DMA_PRD *UsedPrdAddr; + IDE_DMA_PRD *TempPrdAddr; + UINT8 RegisterValue; + UINT8 Device; + UINT64 IoPortForBmic; + UINT64 IoPortForBmis; + UINT64 IoPortForBmid; + EFI_STATUS Status; + UINTN PrdTableNum; + UINTN ByteCount; + UINTN ByteAvailable; + UINT8 *PrdBuffer; + UINTN RemainBlockNum; + UINT8 DeviceControl; + + // + // Channel and device differential + // + Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); + + // + // Enable interrupt to support UDMA and Select device + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + if (IdePrimary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET; + } else { + if (IdeSecondary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET; + } else { + return EFI_UNSUPPORTED; + } + } + + RemainBlockNum = NumberOfBlocks; + while (RemainBlockNum > 0) { + + if (RemainBlockNum >= MAX_DMA_COMMAND_SECTORS) { + // + // SectorCount is used to record the number of sectors to be read + // Max 256 sectors can be transfered at a time. + // + NumberOfBlocks = MAX_DMA_COMMAND_SECTORS; + RemainBlockNum -= MAX_DMA_COMMAND_SECTORS; + } else { + NumberOfBlocks = (UINT16) RemainBlockNum; + RemainBlockNum = 0; + } + + // + // Calculate the number of PRD table to make sure the memory region + // not cross 64K boundary + // + ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + PrdTableNum = ((ByteCount >> 16) + 1) + 1; + + // + // Build PRD table + // + PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD))); + // + // To make sure PRD is allocated in one 64K page + // + if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000); + } else { + if ((UINTN) PrdAddr & 0x03) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC); + } else { + UsedPrdAddr = PrdAddr; + } + } + + // + // Build the PRD table + // + PrdBuffer = DataBuffer; + TempPrdAddr = UsedPrdAddr; + while (TRUE) { + + ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF); + + if (ByteCount <= ByteAvailable) { + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteCount; + TempPrdAddr->EndOfTable = 0x8000; + break; + } + + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteAvailable; + + ByteCount -= ByteAvailable; + PrdBuffer += ByteAvailable; + TempPrdAddr++; + } + + // + // Set the base address to BMID register + // + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmid, + 1, + &UsedPrdAddr + ); + + // + // Set BMIC register to identify the operation direction + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_nREAD; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Read BMIS register and clear ERROR and INTR bit + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + // + // Issue READ DMA command + // + Status = AtaCommandIssue ( + IdeDev, + READ_DMA_CMD, + Device, + 0, + (UINT16) NumberOfBlocks, + StartLba + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_START; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Check the INTERRUPT and ERROR bit of BMIS + // + while (TRUE) { + + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) { + if (RegisterValue & BMIS_ERROR) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + break; + } + + gBS->Stall (1000); + } + + gBS->FreePool (PrdAddr); + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue &= ~((UINT8) BMIC_START); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + if (RegisterValue & BMIS_ERROR) { + return EFI_DEVICE_ERROR; + } + + DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + StartLba += NumberOfBlocks; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaUdmaWriteExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaUdmaWriteExt + + Purpose: + + This function is called by the AtaBlkIoWriteBlocks() to perform + writing to media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the source buffer for the data. + + EFI_LBA IN StartLba + The starting logical block address to write to + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + The device status of UDMA operation. If the operation is + successful, return EFI_SUCCESS. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_DMA_PRD *PrdAddr; + IDE_DMA_PRD *UsedPrdAddr; + IDE_DMA_PRD *TempPrdAddr; + UINT8 RegisterValue; + UINT8 Device; + UINT64 IoPortForBmic; + UINT64 IoPortForBmis; + UINT64 IoPortForBmid; + EFI_STATUS Status; + UINTN PrdTableNum; + UINTN ByteCount; + UINTN ByteAvailable; + UINT8 *PrdBuffer; + UINTN RemainBlockNum; + UINT8 DeviceControl; + + // + // Channel and device differential + // + Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); + + // + // Enable interrupt to support UDMA and Select device + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + if (IdePrimary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET; + } else { + if (IdeSecondary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET; + } else { + return EFI_UNSUPPORTED; + } + } + + RemainBlockNum = NumberOfBlocks; + while (RemainBlockNum > 0) { + + if (RemainBlockNum >= MAX_DMA_EXT_COMMAND_SECTORS) { + // + // SectorCount is used to record the number of sectors to be read + // Max 65536 sectors can be transfered at a time. + // + NumberOfBlocks = MAX_DMA_EXT_COMMAND_SECTORS; + RemainBlockNum -= MAX_DMA_EXT_COMMAND_SECTORS; + } else { + NumberOfBlocks = (UINT16) RemainBlockNum; + RemainBlockNum = 0; + } + + // + // Calculate the number of PRD table to make sure the memory region + // not cross 64K boundary + // + ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + PrdTableNum = ((ByteCount >> 16) + 1) + 1; + + // + // Build PRD table + // + PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD))); + // + // To make sure PRD is allocated in one 64K page + // + if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000); + } else { + if ((UINTN) PrdAddr & 0x03) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC); + } else { + UsedPrdAddr = PrdAddr; + } + } + + // + // Build the PRD table + // + PrdBuffer = DataBuffer; + TempPrdAddr = UsedPrdAddr; + while (TRUE) { + + ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF); + + if (ByteCount <= ByteAvailable) { + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteCount; + TempPrdAddr->EndOfTable = 0x8000; + break; + } + + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteAvailable; + + ByteCount -= ByteAvailable; + PrdBuffer += ByteAvailable; + TempPrdAddr++; + } + + // + // Set the base address to BMID register + // + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmid, + 1, + &UsedPrdAddr + ); + + // + // Set BMIC register to identify the operation direction + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + // + // 0000 1000 + // + RegisterValue &= ~((UINT8) BMIC_nREAD); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Read BMIS register and clear ERROR and INTR bit + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + // + // Issue WRITE DMA EXT command + // + Status = AtaCommandIssueExt ( + IdeDev, + WRITE_DMA_EXT_CMD, + Device, + 0, + (UINT16) NumberOfBlocks, + StartLba + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_START; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Check the INTERRUPT and ERROR bit of BMIS + // + while (TRUE) { + + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) { + if (RegisterValue & BMIS_ERROR) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + break; + } + + gBS->Stall (1000); + } + + gBS->FreePool (PrdAddr); + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue &= ~((UINT8) BMIC_START); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + StartLba += NumberOfBlocks; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaUdmaWrite ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + + AtaUdmaWrite + + Purpose: + + This function is called by the AtaBlkIoWriteBlocks() to perform + writing to media in block unit. The function has been enhanced to + support >120GB access and transfer at most 65536 blocks per command + + Parameters: + + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *DataBuffer + A pointer to the source buffer for the data. + + EFI_LBA IN StartLba + The starting logical block address to write to + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + + The device status of UDMA operation. If the operation is + successful, return EFI_SUCCESS. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DataBuffer - add argument and description to function comment +// TODO: StartLba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_DMA_PRD *PrdAddr; + IDE_DMA_PRD *UsedPrdAddr; + IDE_DMA_PRD *TempPrdAddr; + UINT8 RegisterValue; + UINT8 Device; + UINT64 IoPortForBmic; + UINT64 IoPortForBmis; + UINT64 IoPortForBmid; + EFI_STATUS Status; + UINTN PrdTableNum; + UINTN ByteCount; + UINTN ByteAvailable; + UINT8 *PrdBuffer; + UINTN RemainBlockNum; + UINT8 DeviceControl; + + // + // Channel and device differential + // + Device = (UINT8) ((IdeDev->Device << 4) | 0xe0); + + // + // Enable interrupt to support UDMA + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + if (IdePrimary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET; + } else { + if (IdeSecondary == IdeDev->Channel) { + IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET; + IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET; + IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET; + } else { + return EFI_UNSUPPORTED; + } + } + + RemainBlockNum = NumberOfBlocks; + while (RemainBlockNum > 0) { + + if (RemainBlockNum >= MAX_DMA_COMMAND_SECTORS) { + // + // SectorCount is used to record the number of sectors to be read + // Max 256 sectors can be transfered at a time. + // + NumberOfBlocks = MAX_DMA_COMMAND_SECTORS; + RemainBlockNum -= MAX_DMA_COMMAND_SECTORS; + } else { + NumberOfBlocks = (UINT16) RemainBlockNum; + RemainBlockNum = 0; + } + + // + // Calculate the number of PRD table to make sure the memory region + // not cross 64K boundary + // + ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + PrdTableNum = ((ByteCount >> 16) + 1) + 1; + + // + // Build PRD table + // + PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD))); + + // + // To make sure PRD is allocated in one 64K page + // + if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000); + } else { + if ((UINTN) PrdAddr & 0x03) { + UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC); + } else { + UsedPrdAddr = PrdAddr; + } + } + + // + // Build the PRD table + // + PrdBuffer = DataBuffer; + TempPrdAddr = UsedPrdAddr; + while (TRUE) { + + ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF); + + if (ByteCount <= ByteAvailable) { + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteCount; + TempPrdAddr->EndOfTable = 0x8000; + break; + } + + TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer); + TempPrdAddr->ByteCount = (UINT16) ByteAvailable; + + ByteCount -= ByteAvailable; + PrdBuffer += ByteAvailable; + TempPrdAddr++; + } + + // + // Set the base address to BMID register + // + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmid, + 1, + &UsedPrdAddr + ); + + // + // Set BMIC register to identify the operation direction + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + // + // 0000 1000 + // + RegisterValue &= ~((UINT8) BMIC_nREAD); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Read BMIS register and clear ERROR and INTR bit + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + + // + // Issue WRITE DMA command + // + Status = AtaCommandIssue ( + IdeDev, + WRITE_DMA_CMD, + Device, + 0, + (UINT16) NumberOfBlocks, + StartLba + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue |= BMIC_START; + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + // + // Check the INTERRUPT and ERROR bit of BMIS + // + while (TRUE) { + + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmis, + 1, + &RegisterValue + ); + if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) { + if (RegisterValue & BMIS_ERROR) { + gBS->FreePool (PrdAddr); + return EFI_DEVICE_ERROR; + } + break; + } + + gBS->Stall (1000); + } + + gBS->FreePool (PrdAddr); + + // + // Set START bit of BMIC register + // + IdeDev->PciIo->Io.Read ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + RegisterValue &= ~((UINT8) BMIC_START); + + IdeDev->PciIo->Io.Write ( + IdeDev->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + IoPortForBmic, + 1, + &RegisterValue + ); + + DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize; + StartLba += NumberOfBlocks; + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c new file mode 100644 index 0000000000..fa004e3d7f --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c @@ -0,0 +1,2591 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + atapi.c + +Abstract: + + +Revision History +--*/ + +#include "idebus.h" + +STATIC +EFI_STATUS +LS120GetMediaStatus ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + LS120GetMediaStatus + + Purpose: + This function is used to get the current status of the media residing + in the LS-120 drive or ZIP drive. The media status is returned in the + Error Status. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + The media status is achieved successfully and the media + can be read/written. + + EFI_DEVICE_ERROR + Get Media Status Command is failed. + + EFI_NO_MEDIA + There is no media in the drive. + + EFI_WRITE_PROTECTED + The media is writing protected. + + Notes: + This function must be called after the LS120EnableMediaStatus() + with second parameter set to TRUE + (means enable media status notification) is called. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + UINT8 DeviceSelect; + UINT8 StatusValue; + EFI_STATUS EfiStatus; + // + // Poll Alternate Register for BSY clear within timeout. + // + EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (EfiStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device via Device/Head Register. + // + DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); + + // + // Poll Alternate Register for DRDY set within timeout. + // After device is selected, DRDY set indicates the device is ready to + // accept command. + // + EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (EfiStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // Get Media Status Command is sent + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA); + + // + // BSY bit will clear after command is complete. + // + EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (EfiStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // the media status is returned by the command in the ERROR register + // + StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + + if (StatusValue & bit1) { + return EFI_NO_MEDIA; + } + + if (StatusValue & bit6) { + return EFI_WRITE_PROTECTED; + } else { + return EFI_SUCCESS; + } +} + +STATIC +EFI_STATUS +LS120EnableMediaStatus ( + IN IDE_BLK_IO_DEV *IdeDev, + IN BOOLEAN Enable + ) +/*++ + Name: + LS120EnableMediaStatus + + Purpose: + This function is used to send Enable Media Status Notification Command + or Disable Media Status Notification Command. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + BOOLEAN IN Enable + a flag that indicates whether enable or disable media + status notification. + + Returns: + EFI_SUCCESS + If command completes successfully. + + EFI_DEVICE_ERROR + If command failed. + + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Enable - add argument and description to function comment +{ + UINT8 DeviceSelect; + EFI_STATUS Status; + + // + // Poll Alternate Register for BSY clear within timeout. + // + Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device via Device/Head Register. + // + DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); + + // + // Poll Alternate Register for DRDY set within timeout. + // After device is selected, DRDY set indicates the device is ready to + // accept command. + // + Status = DRDYReady2 (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (Enable) { + // + // 0x95: Enable media status notification + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95); + } else { + // + // 0x31: Disable media status notification + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31); + } + // + // Set Feature Command is sent + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF); + + // + // BSY bit will clear after command is complete. + // + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ATAPIIdentify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + ATAPIIdentify + + + Purpose: + This function is called by DiscoverIdeDevice() during its device + identification. + + Its main purpose is to get enough information for the device media + to fill in the Media data structure of the Block I/O Protocol interface. + + There are 5 steps to reach such objective: + + 1. Sends out the ATAPI Identify Command to the specified device. + Only ATAPI device responses to this command. If the command succeeds, + it returns the Identify data structure which filled with information + about the device. Since the ATAPI device contains removable media, + the only meaningful information is the device module name. + + 2. Sends out ATAPI Inquiry Packet Command to the specified device. + This command will return inquiry data of the device, which contains + the device type information. + + 3. Allocate sense data space for future use. We don't detect the media + presence here to improvement boot performance, especially when CD + media is present. The media detection will be performed just before + each BLK_IO read/write + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + Identify ATAPI device successfully. + + EFI_DEVICE_ERROR + ATAPI Identify Device Command failed or device type + is not supported by this IDE driver. + + Notes: + Parameter "IdeDev" will be updated in this function. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +{ + EFI_IDENTIFY_DATA *AtapiIdentifyPointer; + UINT8 DeviceSelect; + EFI_STATUS Status; + + // + // device select bit + // + DeviceSelect = 0; + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + + AtapiIdentifyPointer = AllocatePool (sizeof (EFI_IDENTIFY_DATA)); + if (AtapiIdentifyPointer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Send ATAPI Identify Command to get IDENTIFY data. + // + Status = AtaPioDataIn ( + IdeDev, + (VOID *) AtapiIdentifyPointer, + sizeof (EFI_IDENTIFY_DATA), + ATAPI_IDENTIFY_DEVICE_CMD, + DeviceSelect, + 0, + 0, + 0, + 0 + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (AtapiIdentifyPointer); + return EFI_DEVICE_ERROR; + } + + IdeDev->pIdData = AtapiIdentifyPointer; + PrintAtaModuleName (IdeDev); + + // + // Send ATAPI Inquiry Packet Command to get INQUIRY data. + // + Status = AtapiInquiry (IdeDev); + if (EFI_ERROR (Status)) { + gBS->FreePool (IdeDev->pIdData); + // + // Make sure the pIdData will not be freed again. + // + IdeDev->pIdData = NULL; + return EFI_DEVICE_ERROR; + } + // + // Get media removable info from INQUIRY data. + // + IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80); + + // + // Identify device type via INQUIRY data. + // + switch (IdeDev->pInquiryData->peripheral_type & 0x1f) { + + // + // Magnetic Disk + // + case 0x00: + + // + // device is LS120 or ZIP drive. + // + IdeDev->Type = IdeMagnetic; + + IdeDev->BlkIo.Media->MediaId = 0; + // + // Give initial value + // + IdeDev->BlkIo.Media->MediaPresent = FALSE; + + IdeDev->BlkIo.Media->LastBlock = 0; + IdeDev->BlkIo.Media->BlockSize = 0x200; + break; + + // + // CD-ROM + // + case 0x05: + + IdeDev->Type = IdeCdRom; + IdeDev->BlkIo.Media->MediaId = 0; + // + // Give initial value + // + IdeDev->BlkIo.Media->MediaPresent = FALSE; + + IdeDev->BlkIo.Media->LastBlock = 0; + IdeDev->BlkIo.Media->BlockSize = 0x800; + IdeDev->BlkIo.Media->ReadOnly = TRUE; + break; + + // + // Tape + // + case 0x01: + + // + // WORM + // + case 0x04: + + // + // Optical + // + case 0x07: + + default: + IdeDev->Type = IdeUnknown; + gBS->FreePool (IdeDev->pIdData); + gBS->FreePool (IdeDev->pInquiryData); + // + // Make sure the pIdData and pInquiryData will not be freed again. + // + IdeDev->pIdData = NULL; + IdeDev->pInquiryData = NULL; + return EFI_DEVICE_ERROR; + } + + // + // original sense data numbers + // + IdeDev->SenseDataNumber = 20; + + IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (REQUEST_SENSE_DATA)); + if (IdeDev->SenseData == NULL) { + gBS->FreePool (IdeDev->pIdData); + gBS->FreePool (IdeDev->pInquiryData); + // + // Make sure the pIdData and pInquiryData will not be freed again. + // + IdeDev->pIdData = NULL; + IdeDev->pInquiryData = NULL; + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtapiInquiry ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtapiInquiry + + Purpose: + Sends out ATAPI Inquiry Packet Command to the specified device. + This command will return INQUIRY data of the device. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + Inquiry command completes successfully. + + EFI_DEVICE_ERROR + Inquiry command failed. + Notes: + Parameter "IdeDev" will be updated in this function. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + INQUIRY_DATA *InquiryData; + + // + // prepare command packet for the ATAPI Inquiry Packet Command. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.Inquiry.opcode = INQUIRY; + Packet.Inquiry.page_code = 0; + Packet.Inquiry.allocation_length = sizeof (INQUIRY_DATA); + + InquiryData = AllocatePool (sizeof (INQUIRY_DATA)); + if (InquiryData == NULL) { + return EFI_DEVICE_ERROR; + } + + // + // Send command packet and get requested Inquiry data. + // + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) InquiryData, + sizeof (INQUIRY_DATA), + ATAPITIMEOUT + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (InquiryData); + return EFI_DEVICE_ERROR; + } + + IdeDev->pInquiryData = InquiryData; + + return EFI_SUCCESS; +} + +EFI_STATUS +AtapiPacketCommandIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATAPI_PACKET_COMMAND *Packet, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN UINTN TimeOut + ) +/*++ + Name: + AtapiPacketCommandIn + + Purpose: + This function is used to send out ATAPI commands conforms to the + Packet Command with PIO Data In Protocol. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + ATAPI_PACKET_COMMAND IN *Packet + pointer pointing to ATAPI_PACKET_COMMAND data structure + which contains the contents of the command. + + UINT16 IN *Buffer + buffer contained data transferred from device to host. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINTN IN TimeOut + this parameter is used to specify the timeout + value for the PioReadWriteData() function. + + Returns: + EFI_SUCCESS + send out the ATAPI packet command successfully + and device sends data successfully. + + EFI_DEVICE_ERROR + the device failed to send data. + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Packet - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: TimeOut - add argument and description to function comment +{ + UINT16 *CommandIndex; + EFI_STATUS Status; + UINT32 Count; + + // + // Set all the command parameters by fill related registers. + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select device via Device/Head Register. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000) + ); + + // + // No OVL; No DMA + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00); + + // + // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device + // determine how many data should be transferred. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderLsb, + (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff) + ); + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderMsb, + (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8) + ); + + // + // DEFAULT_CTL:0x0a (0000,1010) + // Disable interrupt + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL); + + // + // Send Packet command to inform device + // that the following data bytes are command packet. + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD); + + Status = DRQReady (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Send out command packet + // + CommandIndex = Packet->Data16; + for (Count = 0; Count < 6; Count++, CommandIndex++) { + + IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex); + gBS->Stall (10); + } + + // + // call PioReadWriteData() function to get + // requested transfer data form device. + // + return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut); +} + +EFI_STATUS +AtapiPacketCommandOut ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATAPI_PACKET_COMMAND *Packet, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN UINTN TimeOut + ) +/*++ + Name: + AtapiPacketCommandOut + + Purpose: + This function is used to send out ATAPI commands conforms to the + Packet Command with PIO Data Out Protocol. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + ATAPI_PACKET_COMMAND IN *Packet + pointer pointing to ATAPI_PACKET_COMMAND data structure + which contains the contents of the command. + + VOID IN *Buffer + buffer contained data transferred from host to device. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + UINTN IN TimeOut + this parameter is used to specify the timeout + value for the PioReadWriteData() function. + + Returns: + EFI_SUCCESS + send out the ATAPI packet command successfully + and device received data successfully. + + EFI_DEVICE_ERROR + the device failed to send data. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Packet - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: TimeOut - add argument and description to function comment +{ + UINT16 *CommandIndex; + EFI_STATUS Status; + UINT32 Count; + + // + // set all the command parameters + // Before write to all the following registers, BSY and DRQ must be 0. + // + Status = DRQClear2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select device via Device/Head Register. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000) + ); + + // + // No OVL; No DMA + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00); + + // + // set the transfersize to MAX_ATAPI_BYTE_COUNT to + // let the device determine how many data should be transferred. + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderLsb, + (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff) + ); + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->CylinderMsb, + (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8) + ); + + // + // DEFAULT_CTL:0x0a (0000,1010) + // Disable interrupt + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL); + + // + // Send Packet command to inform device + // that the following data bytes are command packet. + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD); + + Status = DRQReady2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Send out command packet + // + CommandIndex = Packet->Data16; + for (Count = 0; Count < 6; Count++, CommandIndex++) { + IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex); + gBS->Stall (10); + } + + // + // call PioReadWriteData() function to send requested transfer data to device. + // + return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut); +} + +EFI_STATUS +PioReadWriteData ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN BOOLEAN Read, + IN UINTN TimeOut + ) +/*++ + Name: + PioReadWriteData + + Purpose: + This function is called by either AtapiPacketCommandIn() or + AtapiPacketCommandOut(). It is used to transfer data between + host and device. The data direction is specified by the fourth + parameter. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + buffer contained data transferred between host and device. + + UINT32 IN ByteCount + data size in byte unit of the buffer. + + BOOLEAN IN Read + flag used to determine the data transfer direction. + Read equals 1, means data transferred from device to host; + Read equals 0, means data transferred from host to device. + + UINTN IN TimeOut + timeout value for wait DRQ ready before each data + stream's transfer. + + Returns: + EFI_SUCCESS + data is transferred successfully. + + EFI_DEVICE_ERROR + the device failed to transfer data. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: ByteCount - add argument and description to function comment +// TODO: Read - add argument and description to function comment +// TODO: TimeOut - add argument and description to function comment +{ + // + // required transfer data in word unit. + // + UINT32 RequiredWordCount; + + // + // actual transfer data in word unit. + // + UINT32 ActualWordCount; + UINT32 WordCount; + EFI_STATUS Status; + UINT16 *PtrBuffer; + + // + // containing status byte read from Status Register. + // + UINT8 StatusRegister; + + // + // No data transfer is premitted. + // + if (ByteCount == 0) { + return EFI_SUCCESS; + } + // + // for performance, we assert the ByteCount is an even number + // which is actually a resonable assumption + ASSERT((ByteCount%2) == 0); + + PtrBuffer = Buffer; + RequiredWordCount = ByteCount / 2; + // + // ActuralWordCount means the word count of data really transferred. + // + ActualWordCount = 0; + + while (ActualWordCount < RequiredWordCount) { + + // + // before each data transfer stream, the host should poll DRQ bit ready, + // to see whether indicates device is ready to transfer data. + // + Status = DRQReady2 (IdeDev, TimeOut); + if (EFI_ERROR (Status)) { + return CheckErrorStatus (IdeDev); + } + + // + // read Status Register will clear interrupt + // + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // get current data transfer size from Cylinder Registers. + // + WordCount = + ( + (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8) | + IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb) + ) & 0xffff; + WordCount /= 2; + + WordCount = EFI_MIN (WordCount, (RequiredWordCount - ActualWordCount)); + + if (Read) { + IDEReadPortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + WordCount, + PtrBuffer + ); + } else { + IDEWritePortWMultiple ( + IdeDev->PciIo, + IdeDev->IoPort->Data, + WordCount, + PtrBuffer + ); + } + + PtrBuffer += WordCount; + ActualWordCount += WordCount; + } + + // + // After data transfer is completed, normally, DRQ bit should clear. + // + Status = DRQClear2 (IdeDev, ATAPITIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // read status register to check whether error happens. + // + return CheckErrorStatus (IdeDev); +} + +EFI_STATUS +AtapiTestUnitReady ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtapiTestUnitReady + + Purpose: + Sends out ATAPI Test Unit Ready Packet Command to the specified device + to find out whether device is accessible. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + device is accessible. + + EFI_DEVICE_ERROR + device is not accessible. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + + // + // fill command packet + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.TestUnitReady.opcode = TEST_UNIT_READY; + + // + // send command packet + // + Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT); + return Status; +} + +EFI_STATUS +AtapiRequestSense ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT UINTN *SenseCounts + ) +/*++ + Name: + AtapiRequestSense + + Purpose: + Sends out ATAPI Request Sense Packet Command to the specified device. + This command will return all the current Sense data in the device. + This function will pack all the Sense data in one single buffer. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINT16 OUT **SenseBuffers + allocated in this function, and freed by the calling function. + This buffer is used to accommodate all the sense data returned + by the device. + + UINTN OUT *BufUnit + record the unit size of the sense data block in the SenseBuffers, + + UINTN OUT *BufNumbers + record the number of units in the SenseBuffers. + + Returns: + EFI_SUCCESS + Request Sense command completes successfully. + + EFI_DEVICE_ERROR + Request Sense command failed. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: SenseCounts - add argument and description to function comment +{ + EFI_STATUS Status; + REQUEST_SENSE_DATA *Sense; + UINT16 *Ptr; + BOOLEAN FetchSenseData; + ATAPI_PACKET_COMMAND Packet; + + *SenseCounts = 0; + + ZeroMem (IdeDev->SenseData, sizeof (REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber)); + // + // fill command packet for Request Sense Packet Command + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.RequestSence.opcode = REQUEST_SENSE; + Packet.RequestSence.allocation_length = sizeof (REQUEST_SENSE_DATA); + + // + // initialize pointer + // + Ptr = (UINT16 *) IdeDev->SenseData; + // + // request sense data from device continuously until no sense data + // exists in the device. + // + for (FetchSenseData = TRUE; FetchSenseData;) { + + Sense = (REQUEST_SENSE_DATA *) Ptr; + + // + // send out Request Sense Packet Command and get one Sense data form device + // + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + Ptr, + sizeof (REQUEST_SENSE_DATA), + ATAPITIMEOUT + ); + // + // failed to get Sense data + // + if (EFI_ERROR (Status)) { + if (*SenseCounts == 0) { + return EFI_DEVICE_ERROR; + } else { + return EFI_SUCCESS; + } + } + + (*SenseCounts)++; + // + // We limit MAX sense data count to 20 in order to avoid dead loop. Some + // incompatible ATAPI devices don't retrive NO_SENSE when there is no media. + // In this case, dead loop occurs if we don't have a gatekeeper. 20 is + // supposed to be large enough for any ATAPI device. + // + if ((Sense->sense_key != SK_NO_SENSE) && ((*SenseCounts) < 20)) { + // + // Ptr is word-based pointer + // + Ptr += sizeof (REQUEST_SENSE_DATA) / 2; + + } else { + // + // when no sense key, skip out the loop + // + FetchSenseData = FALSE; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtapiReadCapacity ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtapiReadCapacity + + Purpose: + Sends out ATAPI Read Capacity Packet Command to the specified device. + This command will return the information regarding the capacity of the + media in the device. + + Current device status will impact device's response to the Read Capacity + Command. For example, if the device once reset, the Read Capacity + Command will fail. The Sense data record the current device status, so + if the Read Capacity Command failed, the Sense data must be requested + and be analyzed to determine if the Read Capacity Command should retry. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + Read Capacity Command finally completes successfully. + + EFI_DEVICE_ERROR + Read Capacity Command failed because of device error. + + Notes: + parameter "IdeDev" will be updated in this function. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: EFI_NOT_READY - add return value to function comment +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + + // + // used for capacity data returned from ATAPI device + // + READ_CAPACITY_DATA Data; + READ_FORMAT_CAPACITY_DATA FormatData; + + ZeroMem (&Data, sizeof (Data)); + ZeroMem (&FormatData, sizeof (FormatData)); + + if (IdeDev->Type == IdeCdRom) { + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.Inquiry.opcode = READ_CAPACITY; + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) &Data, + sizeof (READ_CAPACITY_DATA), + ATAPITIMEOUT + ); + + } else { + // + // Type == IdeMagnetic + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY; + Packet.ReadFormatCapacity.allocation_length_lo = 12; + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) &FormatData, + sizeof (READ_FORMAT_CAPACITY_DATA), + ATAPITIMEOUT + ); + } + + if (!EFI_ERROR (Status)) { + + if (IdeDev->Type == IdeCdRom) { + + IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) | + (Data.LastLba2 << 16) | + (Data.LastLba1 << 8) | + Data.LastLba0; + + if (IdeDev->BlkIo.Media->LastBlock != 0) { + + IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) | + (Data.BlockSize2 << 16) | + (Data.BlockSize1 << 8) | + Data.BlockSize0; + + IdeDev->BlkIo.Media->MediaPresent = TRUE; + } else { + IdeDev->BlkIo.Media->MediaPresent = FALSE; + return EFI_DEVICE_ERROR; + } + + IdeDev->BlkIo.Media->ReadOnly = TRUE; + + // + // Because the user data portion in the sector of the Data CD supported + // is always 0x800 + // + IdeDev->BlkIo.Media->BlockSize = 0x800; + } + + if (IdeDev->Type == IdeMagnetic) { + + if (FormatData.DesCode == 3) { + IdeDev->BlkIo.Media->MediaPresent = FALSE; + IdeDev->BlkIo.Media->LastBlock = 0; + } else { + + IdeDev->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) | + (FormatData.LastLba2 << 16) | + (FormatData.LastLba1 << 8) | + FormatData.LastLba0; + if (IdeDev->BlkIo.Media->LastBlock != 0) { + IdeDev->BlkIo.Media->LastBlock--; + + IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) | + (FormatData.BlockSize1 << 8) | + FormatData.BlockSize0; + + IdeDev->BlkIo.Media->MediaPresent = TRUE; + } else { + IdeDev->BlkIo.Media->MediaPresent = FALSE; + // + // Return EFI_NOT_READY operation succeeds but returned capacity is 0 + // + return EFI_NOT_READY; + } + + IdeDev->BlkIo.Media->BlockSize = 0x200; + + } + } + + return EFI_SUCCESS; + + } else { + + return EFI_DEVICE_ERROR; + } +} + +EFI_STATUS +AtapiDetectMedia ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT BOOLEAN *MediaChange + ) +/*++ + Name: + AtapiDetectMedia + + Purpose: + Used before read/write blocks from/to ATAPI device media. + Since ATAPI device media is removable, it is necessary to detect + whether media is present and get current present media's + information, and if media has been changed, Block I/O Protocol + need to be reinstalled. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + BOOLEAN OUT *MediaChange + return value that indicates if the media of the device has been + changed. + + Returns: + EFI_SUCCESS + media found successfully. + + EFI_DEVICE_ERROR + any error encounters during media detection. + + EFI_NO_MEDIA + media not found. + + Notes: + parameter IdeDev may be updated in this function. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: MediaChange - add argument and description to function comment +{ + EFI_STATUS Status; + EFI_STATUS ReadCapacityStatus; + EFI_BLOCK_IO_MEDIA OldMediaInfo; + UINTN SenseCounts; + UINTN RetryIndex; + UINTN RetryTimes; + UINTN MaximumRetryTimes; + UINTN ReadyWaitFactor; + BOOLEAN NeedRetry; + // + // a flag used to determine whether need to perform Read Capacity command. + // + BOOLEAN NeedReadCapacity; + BOOLEAN WriteProtected; + + // + // init + // + CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (OldMediaInfo)); + // OldMediaInfo = *(IdeDev->BlkIo.Media); + *MediaChange = FALSE; + ReadCapacityStatus = EFI_DEVICE_ERROR; + + // + // if there is no media, or media is not changed, + // the request sense command will detect faster than read capacity command. + // read capacity command can be bypassed, thus improve performance. + // + + // + // Test Unit Ready command is used to detect whether device is accessible, + // the device will produce corresponding Sense data. + // + for (RetryIndex = 0; RetryIndex < 2; RetryIndex++) { + + Status = AtapiTestUnitReady (IdeDev); + if (!EFI_ERROR (Status)) { + // + // skip the loop if test unit command succeeds. + // + break; + } + + Status = AtapiSoftReset (IdeDev); + + if (EFI_ERROR (Status)) { + AtaSoftReset (IdeDev); + } + } + + SenseCounts = 0; + NeedReadCapacity = TRUE; + + // + // at most retry 5 times + // + MaximumRetryTimes = 5; + RetryTimes = 1; + + for (RetryIndex = 0; + (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes); + RetryIndex++) { + + Status = AtapiRequestSense (IdeDev, &SenseCounts); + + if (!EFI_ERROR (Status)) { + // + // if first time there is no Sense Key, no need to read capacity any more + // + if (!HaveSenseKey (IdeDev->SenseData, SenseCounts) && + (IdeDev->BlkIo.Media->MediaPresent)) { + + if (RetryIndex == 0) { + NeedReadCapacity = FALSE; + } + + } else { + // + // No Media + // + if (IsNoMedia (IdeDev->SenseData, SenseCounts)) { + NeedReadCapacity = FALSE; + IdeDev->BlkIo.Media->MediaPresent = FALSE; + IdeDev->BlkIo.Media->LastBlock = 0; + } else { + // + // Media Changed + // + if (IsMediaChange (IdeDev->SenseData, SenseCounts)) { + NeedReadCapacity = TRUE; + IdeDev->BlkIo.Media->MediaId++; + } + // + // Media Error + // + if (IsMediaError (IdeDev->SenseData, SenseCounts)) { + return EFI_DEVICE_ERROR; + } + } + } + } else { + // + // retry once more, if request sense command met errors. + // + RetryTimes++; + } + } + + if (NeedReadCapacity) { + // + // at most retry 5 times + // + MaximumRetryTimes = 5; + // + // initial retry twice + // + RetryTimes = 2; + ReadyWaitFactor = 2; + + for (RetryIndex = 0; + (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes); + RetryIndex++) { + + ReadCapacityStatus = AtapiReadCapacity (IdeDev); + + SenseCounts = 0; + + if (!EFI_ERROR (ReadCapacityStatus)) { + // + // Read Capacity succeeded + // + break; + + } else { + + if (ReadCapacityStatus == EFI_NOT_READY) { + // + // If device not ready, wait here... waiting time increases by retry + // times. + // + gBS->Stall (ReadyWaitFactor * 2000 * STALL_1_MILLI_SECOND); + ReadyWaitFactor++; + // + // retry once more + // + RetryTimes++; + continue; + } + + // + // Other errors returned, requery sense data + // + Status = AtapiRequestSense (IdeDev, &SenseCounts); + + // + // If Request Sense data failed, reset the device and retry. + // + if (EFI_ERROR (Status)) { + + Status = AtapiSoftReset (IdeDev); + + // + // if ATAPI soft reset fail, + // use stronger reset mechanism -- ATA soft reset. + // + if (EFI_ERROR (Status)) { + AtaSoftReset (IdeDev); + } + // + // retry once more + // + RetryTimes++; + continue; + } + + // + // No Media + // + if (IsNoMedia (IdeDev->SenseData, SenseCounts)) { + + IdeDev->BlkIo.Media->MediaPresent = FALSE; + IdeDev->BlkIo.Media->LastBlock = 0; + return EFI_NO_MEDIA; + } + + if (IsMediaError (IdeDev->SenseData, SenseCounts)) { + return EFI_DEVICE_ERROR; + } + + // + // Media Changed + // + if (IsMediaChange (IdeDev->SenseData, SenseCounts)) { + IdeDev->BlkIo.Media->MediaId++; + } + + if (!IsDriveReady (IdeDev->SenseData, SenseCounts, &NeedRetry)) { + + // + // Drive not ready: if NeedRetry, then retry once more; + // else return error + // + if (NeedRetry) { + // + // Stall 1 second to wait for drive becoming ready + // + gBS->Stall (1000 * STALL_1_MILLI_SECOND); + // + // reset retry variable to zero, + // to make it retry for "drive in progress of becoming ready". + // + RetryIndex = 0; + continue; + } else { + AtapiSoftReset (IdeDev); + return EFI_DEVICE_ERROR; + } + } + // + // if read capacity fail not for above reasons, retry once more + // + RetryTimes++; + } + + } + + // + // tell whether the readcapacity process is successful or not in the end + // + if (EFI_ERROR (ReadCapacityStatus)) { + return EFI_DEVICE_ERROR; + } + } + + // + // the following code is to check the write-protected for LS120 media + // + if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) { + + Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected); + if (!EFI_ERROR (Status)) { + + if (WriteProtected) { + + IdeDev->BlkIo.Media->ReadOnly = TRUE; + } else { + + IdeDev->BlkIo.Media->ReadOnly = FALSE; + } + + } + } + + if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) { + // + // Media change information got from the device + // + *MediaChange = TRUE; + } + + if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) { + *MediaChange = TRUE; + IdeDev->BlkIo.Media->MediaId += 1; + } + + if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) { + *MediaChange = TRUE; + IdeDev->BlkIo.Media->MediaId += 1; + } + + if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) { + *MediaChange = TRUE; + IdeDev->BlkIo.Media->MediaId += 1; + } + + if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) { + if (IdeDev->BlkIo.Media->MediaPresent) { + // + // when change from no media to media present, reset the MediaId to 1. + // + IdeDev->BlkIo.Media->MediaId = 1; + } else { + // + // when no media, reset the MediaId to zero. + // + IdeDev->BlkIo.Media->MediaId = 0; + } + + *MediaChange = TRUE; + } + + // + // if any change on current existing media, + // the Block I/O protocol need to be reinstalled. + // + if (*MediaChange) { + gBS->ReinstallProtocolInterface ( + IdeDev->Handle, + &gEfiBlockIoProtocolGuid, + &IdeDev->BlkIo, + &IdeDev->BlkIo + ); + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +AtapiReadSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + AtapiReadSectors + + Purpose: + This function is called by the AtapiBlkIoReadBlocks() to perform + read from media in block unit. + + The main command used to access media here is READ(10) Command. + READ(10) Command requests that the ATAPI device media transfer + specified data to the host. Data is transferred in block(sector) + unit. The maximum number of blocks that can be transferred once is + 65536. This is the main difference between READ(10) and READ(12) + Command. The maximum number of blocks in READ(12) is 2 power 32. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + A pointer to the destination buffer for the data. + + EFI_LBA IN Lba + The starting logical block address to read from + on the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + return status is fully dependent on the return status + of AtapiPacketCommandIn() function. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: Lba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + + ATAPI_PACKET_COMMAND Packet; + READ10_CMD *Read10Packet; + EFI_STATUS Status; + UINTN BlocksRemaining; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + UINT16 SectorCount; + VOID *PtrBuffer; + UINT16 MaxBlock; + UINTN TimeOut; + + // + // fill command packet for Read(10) command + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Read10Packet = &Packet.Read10; + Lba32 = (UINT32) Lba; + PtrBuffer = Buffer; + + BlockSize = IdeDev->BlkIo.Media->BlockSize; + + // + // limit the data bytes that can be transferred by one Read(10) Command + // + MaxBlock = (UINT16) (65536 / BlockSize); + + BlocksRemaining = NumberOfBlocks; + + Status = EFI_SUCCESS; + while (BlocksRemaining > 0) { + + if (BlocksRemaining <= MaxBlock) { + + SectorCount = (UINT16) BlocksRemaining; + } else { + + SectorCount = MaxBlock; + } + + // + // fill the Packet data structure + // + + Read10Packet->opcode = READ_10; + + // + // Lba0 ~ Lba3 specify the start logical block address of the data transfer. + // Lba0 is MSB, Lba3 is LSB + // + Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); + Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); + Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); + Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); + + // + // TranLen0 ~ TranLen1 specify the transfer length in block unit. + // TranLen0 is MSB, TranLen is LSB + // + Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); + Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); + + ByteCount = SectorCount * BlockSize; + + if (IdeDev->Type == IdeCdRom) { + TimeOut = CDROMLONGTIMEOUT; + } else { + TimeOut = ATAPILONGTIMEOUT; + } + + Status = AtapiPacketCommandIn ( + IdeDev, + &Packet, + (UINT16 *) PtrBuffer, + ByteCount, + TimeOut + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba32 += SectorCount; + PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize; + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtapiWriteSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + Name: + AtapiWriteSectors + + Purpose: + This function is called by the AtapiBlkIoWriteBlocks() to perform + write onto media in block unit. + The main command used to access media here is Write(10) Command. + Write(10) Command requests that the ATAPI device media transfer + specified data to the host. Data is transferred in block (sector) + unit. The maximum number of blocks that can be transferred once is + 65536. + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + VOID IN *Buffer + A pointer to the source buffer for the data. + + EFI_LBA IN Lba + The starting logical block address to write onto + the device media. + + UINTN IN NumberOfBlocks + The number of transfer data blocks. + + Returns: + return status is fully dependent on the return status + of AtapiPacketCommandOut() function. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: Lba - add argument and description to function comment +// TODO: NumberOfBlocks - add argument and description to function comment +{ + + ATAPI_PACKET_COMMAND Packet; + READ10_CMD *Read10Packet; + + EFI_STATUS Status; + UINTN BlocksRemaining; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + UINT16 SectorCount; + VOID *PtrBuffer; + UINT16 MaxBlock; + + // + // fill command packet for Write(10) command + // Write(10) command packet has the same data structure as + // Read(10) command packet, + // so here use the Read10Packet data structure + // for the Write(10) command packet. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Read10Packet = &Packet.Read10; + + Lba32 = (UINT32) Lba; + PtrBuffer = Buffer; + + BlockSize = IdeDev->BlkIo.Media->BlockSize; + + // + // limit the data bytes that can be transferred by one Read(10) Command + // + MaxBlock = (UINT16) (65536 / BlockSize); + + BlocksRemaining = NumberOfBlocks; + + Status = EFI_SUCCESS; + while (BlocksRemaining > 0) { + + if (BlocksRemaining >= MaxBlock) { + SectorCount = MaxBlock; + } else { + SectorCount = (UINT16) BlocksRemaining; + } + + // + // Command code is WRITE_10. + // + Read10Packet->opcode = WRITE_10; + + // + // Lba0 ~ Lba3 specify the start logical block address of the data transfer. + // Lba0 is MSB, Lba3 is LSB + // + Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); + Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); + Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); + Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); + + // + // TranLen0 ~ TranLen1 specify the transfer length in block unit. + // TranLen0 is MSB, TranLen is LSB + // + Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); + Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); + + ByteCount = SectorCount * BlockSize; + + Status = AtapiPacketCommandOut ( + IdeDev, + &Packet, + (UINT16 *) PtrBuffer, + ByteCount, + ATAPILONGTIMEOUT + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Lba32 += SectorCount; + PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize); + BlocksRemaining -= SectorCount; + } + + return Status; +} + +EFI_STATUS +AtapiSoftReset ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Name: + AtapiSoftReset + + Purpose: + This function is used to implement the Soft Reset on the specified + ATAPI device. Different from the AtaSoftReset(), here reset is a ATA + Soft Reset Command special for ATAPI device, and it only take effects + on the specified ATAPI device, not on the whole IDE bus. + Since the ATAPI soft reset is needed when device is in exceptional + condition (such as BSY bit is always set ), I think the Soft Reset + command should be sent without waiting for the BSY clear and DRDY + set. + This function is called by IdeBlkIoReset(), + a interface function of Block I/O protocol. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + Returns: + EFI_SUCCESS + Soft reset completes successfully. + + EFI_DEVICE_ERROR + Any step during the reset process is failed. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +{ + UINT8 Command; + UINT8 DeviceSelect; + EFI_STATUS Status; + + // + // for ATAPI device, no need to wait DRDY ready after device selecting. + // (bit7 and bit5 are both set to 1 for backward compatibility) + // + DeviceSelect = (UINT8) (((bit7 | bit5) | (IdeDev->Device << 4))); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect); + + Command = ATAPI_SOFT_RESET_CMD; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command); + + // + // BSY cleared is the only status return to the host by the device + // when reset is completed. + // slave device needs at most 31s to clear BSY + // + Status = WaitForBSYClear (IdeDev, 31000); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // stall 5 seconds to make the device status stable + // + gBS->Stall (5000000); + + return EFI_SUCCESS; +} + +EFI_STATUS +AtapiBlkIoReadBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + Name: + AtapiBlkIoReadBlocks + + Purpose: + This function is the ATAPI implementation for ReadBlocks in the + Block I/O Protocol interface. + + Parameters: + IDE_BLK_IO_DEV IN *IdeBlkIoDev + Indicates the calling context. + + UINT32 IN MediaId + The media id that the read request is for. + + EFI_LBA IN LBA + The starting logical block address to read from + on the device. + + UINTN IN BufferSize + The size of the Buffer in bytes. This must be a + multiple of the intrinsic block size of the device. + + VOID OUT *Buffer + A pointer to the destination buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the memory that data is read into. + + Returns: + EFI_SUCCESS + Read Blocks successfully. + + EFI_DEVICE_ERROR + Read Blocks failed. + + EFI_NO_MEDIA + There is no media in the device. + + EFI_MEDIA_CHANGED + The MediaId is not for the current media. + + EFI_BAD_BUFFER_SIZE + The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + + EFI_INVALID_PARAMETER + The read request contains LBAs that are not valid, + or the data buffer is not valid. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeBlkIoDevice - add argument and description to function comment +// TODO: MediaId - add argument and description to function comment +// TODO: LBA - add argument and description to function comment +// TODO: BufferSize - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +{ + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + EFI_STATUS Status; + + BOOLEAN MediaChange; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + // + // ATAPI device media is removable, so it is a must + // to detect media first before read operation + // + MediaChange = FALSE; + Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange); + if (EFI_ERROR (Status)) { + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + + return Status; + } + // + // Get the intrinsic block size + // + Media = IdeBlkIoDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_NO_MEDIA; + + } + + if ((MediaId != Media->MediaId) || MediaChange) { + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_MEDIA_CHANGED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + // + // if all the parameters are valid, then perform read sectors command + // to transfer data from device to host. + // + Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Read blocks succeeded + // + + // + // save the first block to the cache for performance + // + if (LBA == 0 && !IdeBlkIoDevice->Cache) { + IdeBlkIoDevice->Cache = AllocatePool (BlockSize); + if (IdeBlkIoDevice != NULL) { + CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize); + } + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +AtapiBlkIoWriteBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + Name: + AtapiBlkIoWriteBlocks + + Purpose: + This function is the ATAPI implementation for WriteBlocks in the + Block I/O Protocol interface. + + Parameters: + EFI_BLOCK_IO IN *This + Indicates the calling context. + + UINT32 IN MediaId + The media id that the write request is for. + + EFI_LBA IN LBA + The starting logical block address to write onto + the device. + + UINTN IN BufferSize + The size of the Buffer in bytes. This must be a + multiple of the intrinsic block size of the device. + + VOID OUT *Buffer + A pointer to the source buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the memory that data is + written from. + + Returns: + EFI_SUCCESS + Write Blocks successfully. + + EFI_DEVICE_ERROR + Write Blocks failed. + + EFI_NO_MEDIA + There is no media in the device. + + EFI_MEDIA_CHANGE + The MediaId is not for the current media. + + EFI_BAD_BUFFER_SIZE + The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + + EFI_INVALID_PARAMETER + The write request contains LBAs that are not valid, + or the data buffer is not valid. + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeBlkIoDevice - add argument and description to function comment +// TODO: MediaId - add argument and description to function comment +// TODO: LBA - add argument and description to function comment +// TODO: BufferSize - add argument and description to function comment +// TODO: Buffer - add argument and description to function comment +// TODO: EFI_MEDIA_CHANGED - add return value to function comment +// TODO: EFI_WRITE_PROTECTED - add return value to function comment +{ + + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + EFI_STATUS Status; + BOOLEAN MediaChange; + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + // + // ATAPI device media is removable, + // so it is a must to detect media first before write operation + // + MediaChange = FALSE; + Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange); + if (EFI_ERROR (Status)) { + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return Status; + } + + // + // Get the intrinsic block size + // + Media = IdeBlkIoDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_NO_MEDIA; + } + + if ((MediaId != Media->MediaId) || MediaChange) { + + if (LBA == 0 && IdeBlkIoDevice->Cache) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + return EFI_MEDIA_CHANGED; + } + + if (Media->ReadOnly) { + return EFI_WRITE_PROTECTED; + } + + if (BufferSize % BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (LBA > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + // + // if all the parameters are valid, + // then perform write sectors command to transfer data from host to device. + // + Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; + +} + +// +// The following functions are a set of helper functions, +// which are used to parse sense key returned by the device. +// + +BOOLEAN +IsNoMedia ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + REQUEST_SENSE_DATA *SensePointer; + UINTN Index; + BOOLEAN NoMedia; + + NoMedia = FALSE; + SensePointer = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + // + // Sense Key is SK_NOT_READY (0x2), + // Additional Sense Code is ASC_NO_MEDIA (0x3A) + // + if ((SensePointer->sense_key == SK_NOT_READY) && + (SensePointer->addnl_sense_code == ASC_NO_MEDIA)) { + + NoMedia = TRUE; + } + + SensePointer++; + } + + return NoMedia; +} + +BOOLEAN +IsMediaError ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + Name: + IsMediaError + + Purpose: + Test if the device meets a media error after media changed + + Parameters: + EQUEST_SENSE_DATA IN *SenseData + pointer pointing to ATAPI device sense data list. + UINTN IN SenseCounts + sense data number of the list + + Returns: + TRUE + Device meets a media error + + FALSE + No media error +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: SenseData - add argument and description to function comment +// TODO: SenseCounts - add argument and description to function comment +{ + REQUEST_SENSE_DATA *SensePointer; + UINTN Index; + BOOLEAN IsError; + + IsError = FALSE; + SensePointer = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + switch (SensePointer->sense_key) { + + case SK_MEDIUM_ERROR: + // + // Sense Key is SK_MEDIUM_ERROR (0x3) + // + switch (SensePointer->addnl_sense_code) { + case ASC_MEDIA_ERR1: + case ASC_MEDIA_ERR2: + case ASC_MEDIA_ERR3: + case ASC_MEDIA_ERR4: + IsError = TRUE; + break; + + default: + break; + } + + break; + + case SK_NOT_READY: + // + // Sense Key is SK_NOT_READY (0x2) + // + switch (SensePointer->addnl_sense_code) { + // + // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6) + // + case ASC_MEDIA_UPSIDE_DOWN: + IsError = TRUE; + break; + + default: + break; + } + break; + + default: + break; + } + + SensePointer++; + } + + return IsError; +} + +BOOLEAN +IsMediaChange ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + REQUEST_SENSE_DATA *SensePointer; + UINTN Index; + BOOLEAN IsMediaChange; + + IsMediaChange = FALSE; + SensePointer = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + // + // Sense Key is SK_UNIT_ATTENTION (0x6) + // + if ((SensePointer->sense_key == SK_UNIT_ATTENTION) && + (SensePointer->addnl_sense_code == ASC_MEDIA_CHANGE)) { + + IsMediaChange = TRUE; + } + + SensePointer++; + } + + return IsMediaChange; +} + +BOOLEAN +IsDriveReady ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts, + OUT BOOLEAN *NeedRetry + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + NeedRetry - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + REQUEST_SENSE_DATA *SensePointer; + UINTN Index; + BOOLEAN IsReady; + + IsReady = TRUE; + *NeedRetry = FALSE; + SensePointer = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + switch (SensePointer->sense_key) { + + case SK_NOT_READY: + // + // Sense Key is SK_NOT_READY (0x2) + // + switch (SensePointer->addnl_sense_code) { + case ASC_NOT_READY: + // + // Additional Sense Code is ASC_NOT_READY (0x4) + // + switch (SensePointer->addnl_sense_code_qualifier) { + case ASCQ_IN_PROGRESS: + // + // Additional Sense Code Qualifier is ASCQ_IN_PROGRESS (0x1) + // + IsReady = FALSE; + *NeedRetry = TRUE; + break; + + default: + IsReady = FALSE; + *NeedRetry = FALSE; + break; + } + break; + + default: + break; + } + break; + + default: + break; + } + + SensePointer++; + } + + return IsReady; +} + +BOOLEAN +HaveSenseKey ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + BOOLEAN Have; + + Have = TRUE; + + // + // if first sense key in the Sense Data Array is SK_NO_SENSE, + // it indicates there is no more sense key in the Sense Data Array. + // + if (SenseData->sense_key == SK_NO_SENSE) { + Have = FALSE; + } + + return Have; +} + +EFI_STATUS +IsLS120orZipWriteProtected ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT BOOLEAN *WriteProtected + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + WriteProtected - TODO: add argument description + +Returns: + + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_DEVICE_ERROR - TODO: Add description for return value + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + EFI_STATUS Status; + + *WriteProtected = FALSE; + + Status = LS120EnableMediaStatus (IdeDev, TRUE); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // the Get Media Status Command is only valid + // if a Set Features/Enable Media Status Command has been priviously issued. + // + if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) { + + *WriteProtected = TRUE; + } else { + + *WriteProtected = FALSE; + } + + // + // After Get Media Status Command completes, + // Set Features/Disable Media Command should be sent. + // + Status = LS120EnableMediaStatus (IdeDev, FALSE); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml new file mode 100644 index 0000000000..3a33a2b3a9 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c new file mode 100644 index 0000000000..d318fd23df --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c @@ -0,0 +1,1964 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ide.c + +Abstract: + + +Revision History +--*/ + +#include "idebus.h" + +BOOLEAN SlaveDeviceExist = FALSE; +BOOLEAN MasterDeviceExist = FALSE; + +UINT8 +IDEReadPortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + UINT8 Data; + + Data = 0; + // + // perform 1-byte data read from register + // + PciIo->Io.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + 1, + &Data + ); + return Data; +} + +VOID +IDEReadPortWMultiple ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINTN Count, + IN VOID *Buffer + ) +/*++ + +Routine Description: + Reads multiple words of data from the IDE data port. + Call the IO abstraction once to do the complete read, + not one word at a time + + +Arguments: + PciIo - Pointer to the EFI_PCI_IO instance + Port - IO port to read + Count - No. of UINT16's to read + Buffer - Pointer to the data buffer for read + +++*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Returns:' +{ + UINT16 *AlignedBuffer; + UINT16 *WorkingBuffer; + UINTN Size; + + // + // Prepare an 16-bit alligned working buffer. CpuIo will return failure and + // not perform actual I/O operations if buffer pointer passed in is not at + // natural boundary. The "Buffer" argument is passed in by user and may not + // at 16-bit natural boundary. + // + Size = sizeof (UINT16) * Count; + + gBS->AllocatePool ( + EfiBootServicesData, + Size + 1, + (VOID**)&WorkingBuffer + ); + + AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1))); + + // + // Perform UINT16 data read from FIFO + // + PciIo->Io.Read ( + PciIo, + EfiPciIoWidthFifoUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + Count, + (UINT16*)AlignedBuffer + ); + + // + // Copy data to user buffer + // + CopyMem (Buffer, (UINT16*)AlignedBuffer, Size); + gBS->FreePool (WorkingBuffer); +} + +VOID +IDEWritePortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT8 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // perform 1-byte data write to register + // + PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + 1, + &Data + ); + +} + +VOID +IDEWritePortW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT16 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // perform 1-word data write to register + // + PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + 1, + &Data + ); +} + +VOID +IDEWritePortWMultiple ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINTN Count, + IN VOID *Buffer + ) +/*++ + +Routine Description: + Write multiple words of data to the IDE data port. + Call the IO abstraction once to do the complete read, + not one word at a time + + +Arguments: + PciIo - Pointer to the EFI_PCI_IO instance + Port - IO port to read + Count - No. of UINT16's to read + Buffer - Pointer to the data buffer for read + +++*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Returns:' +{ + UINT16 *AlignedBuffer; + UINT32 *WorkingBuffer; + UINTN Size; + + // + // Prepare an 16-bit alligned working buffer. CpuIo will return failure and + // not perform actual I/O operations if buffer pointer passed in is not at + // natural boundary. The "Buffer" argument is passed in by user and may not + // at 16-bit natural boundary. + // + Size = sizeof (UINT16) * Count; + + gBS->AllocatePool ( + EfiBootServicesData, + Size + 1, + (VOID **) &WorkingBuffer + ); + + AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1))); + + // + // Copy data from user buffer to working buffer + // + CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size); + + // + // perform UINT16 data write to the FIFO + // + PciIo->Io.Write ( + PciIo, + EfiPciIoWidthFifoUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) Port, + Count, + (UINT16 *) AlignedBuffer + ); + + gBS->FreePool (WorkingBuffer); +} + +BOOLEAN +BadIdeDeviceCheck ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + // + // check whether all registers return 0xff, + // if so, deem the channel is disabled. + // +#ifdef EFI_DEBUG + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Data) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Head) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command) != 0xff) { + return FALSE; + } + + if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus) != 0xff) { + return FALSE; + } + + return TRUE; + +#else + + return FALSE; + +#endif +} + +// +// GetIdeRegistersBaseAddr +// +EFI_STATUS +GetIdeRegistersBaseAddr ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr + ) +/*++ + +Routine Description: + Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode, + use fixed addresses. In Native-PCI mode, get base addresses from BARs in + the PCI IDE controller's Configuration Space. + + The steps to get IDE IO port registers' base addresses for each channel + as follows: + + 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE + controller's Configuration Space to determine the operating mode. + + 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below. + ___________________________________________ + | | Command Block | Control Block | + | Channel | Registers | Registers | + |___________|_______________|_______________| + | Primary | 1F0h - 1F7h | 3F6h - 3F7h | + |___________|_______________|_______________| + | Secondary | 170h - 177h | 376h - 377h | + |___________|_______________|_______________| + + Table 1. Compatibility resource mappings + + b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs + in IDE controller's PCI Configuration Space, shown in the Table 2 below. + ___________________________________________________ + | | Command Block | Control Block | + | Channel | Registers | Registers | + |___________|___________________|___________________| + | Primary | BAR at offset 0x10| BAR at offset 0x14| + |___________|___________________|___________________| + | Secondary | BAR at offset 0x18| BAR at offset 0x1C| + |___________|___________________|___________________| + + Table 2. BARs for Register Mapping + Note: Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for + primary, 0374h for secondary. So 2 bytes extra offset should be + added to the base addresses read from BARs. + + For more details, please refer to PCI IDE Controller Specification and Intel + ICH4 Datasheet. + +Arguments: + PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance + IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to + receive IDE IO port registers' base addresses + +Returns: + +--*/ +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + PCI_TYPE00 PciData; + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + 0, + sizeof (PciData), + &PciData + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) { + IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0; + IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6; + IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr = + (UINT16)((PciData.Device.Bar[4] & 0x0000fff0)); + } else { + // + // The BARs should be of IO type + // + if ((PciData.Device.Bar[0] & bit0) == 0 || + (PciData.Device.Bar[1] & bit0) == 0) { + return EFI_UNSUPPORTED; + } + + IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = + (UINT16) (PciData.Device.Bar[0] & 0x0000fff8); + IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = + (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2); + IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr = + (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0)); + } + + if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) { + IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170; + IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376; + IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr = + (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0)); + } else { + // + // The BARs should be of IO type + // + if ((PciData.Device.Bar[2] & bit0) == 0 || + (PciData.Device.Bar[3] & bit0) == 0) { + return EFI_UNSUPPORTED; + } + + IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = + (UINT16) (PciData.Device.Bar[2] & 0x0000fff8); + IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = + (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2); + IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr = + (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0)); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +ReassignIdeResources ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + This function is used to requery IDE resources. The IDE controller will + probably switch between native and legacy modes during the EFI->CSM->OS + transfer. We do this everytime before an BlkIo operation to ensure its + succeess. + +Arguments: + IdeDev - The BLK_IO private data which specifies the IDE device + +++*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Returns:' +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel]; + UINT16 CommandBlockBaseAddr; + UINT16 ControlBlockBaseAddr; + + // + // Requery IDE IO port registers' base addresses in case of the switch of + // native and legacy modes + // + Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr); + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS)); + CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr; + ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr; + + IdeDev->IoPort->Data = CommandBlockBaseAddr; + (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01); + IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02); + IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03); + IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04); + IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05); + IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06); + + (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07); + (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr; + IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01); + IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0); + + IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr; + return EFI_SUCCESS; +} + +EFI_STATUS +CheckPowerMode ( + IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Routine Description: + + Read SATA registers to detect SATA disks + + Arguments: + + IdeDev - The BLK_IO private data which specifies the IDE device + +++*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Returns:' +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + UINT8 ErrorRegister; + EFI_STATUS Status; + + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + + // + // Wait 31 seconds for BSY clear. BSY should be in clear state if there exists + // a device (initial state). Normally, BSY is also in clear state if there is + // no device + // + Status = WaitForBSYClear (IdeDev, 31000); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // select device, read error register + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + Status = DRDYReady (IdeDev, 200); + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister == 0x01) || (ErrorRegister == 0x81)) { + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } +} + +// +// DiscoverIdeDevice +// +EFI_STATUS +DiscoverIdeDevice ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + Routine Description: + + Detect if there is disk connected to this port + + Arguments: + + IdeDev - The BLK_IO private data which specifies the IDE device + +++*/ +// TODO: function comment should end with '--*/' +// TODO: function comment is missing 'Returns:' +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + BOOLEAN SataFlag; + + SataFlag = FALSE; + // + // This extra detection is for SATA disks + // + Status = CheckPowerMode (IdeDev); + if (Status == EFI_SUCCESS) { + SataFlag = TRUE; + } + + // + // If a channel has not been checked, check it now. Then set it to "checked" state + // After this step, all devices in this channel have been checked. + // + Status = DetectIDEController (IdeDev); + + if ((EFI_ERROR (Status)) && !SataFlag) { + return EFI_NOT_FOUND; + } + + // + // Device exists. test if it is an ATA device + // + Status = ATAIdentify (IdeDev); + if (EFI_ERROR (Status)) { + // + // if not ATA device, test if it is an ATAPI device + // + Status = ATAPIIdentify (IdeDev); + if (EFI_ERROR (Status)) { + // + // if not ATAPI device either, return error. + // + return EFI_NOT_FOUND; + } + } + + // + // Init Block I/O interface + // + IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION; + IdeDev->BlkIo.Reset = IDEBlkIoReset; + IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks; + IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks; + IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks; + + IdeDev->BlkMedia.LogicalPartition = FALSE; + IdeDev->BlkMedia.WriteCaching = FALSE; + + // + // Init Disk Info interface + // + gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID)); + IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry; + IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify; + IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData; + IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde; + + return EFI_SUCCESS; +} + +EFI_STATUS +DetectIDEController ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + + Name: DetectIDEController + + + Purpose: + This function is called by DiscoverIdeDevice(). It is used for detect + whether the IDE device exists in the specified Channel as the specified + Device Number. + + There is two IDE channels: one is Primary Channel, the other is + Secondary Channel.(Channel is the logical name for the physical "Cable".) + Different channel has different register group. + + On each IDE channel, at most two IDE devices attach, + one is called Device 0 (Master device), the other is called Device 1 + (Slave device). The devices on the same channel co-use the same register + group, so before sending out a command for a specified device via command + register, it is a must to select the current device to accept the command + by set the device number in the Head/Device Register. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + + Returns: + TRUE + successfully detects device. + + FALSE + any failure during detection process will return this + value. + + + Notes: +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +{ + EFI_STATUS Status; + UINT8 ErrorReg; + UINT8 StatusReg; + UINT8 InitStatusReg; + EFI_STATUS DeviceStatus; + + // + // Slave device has been detected with master device. + // + if ((IdeDev->Device) == 1) { + if (SlaveDeviceExist) { + // + // If master not exists but slave exists, slave have to wait a while + // + if (!MasterDeviceExist) { + // + // if single slave can't be detected, add delay 4s here. + // + gBS->Stall (4000000); + } + + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } + } + + // + // Select slave device + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((1 << 4) | 0xe0) + ); + gBS->Stall (100); + + // + // Save the init slave status register + // + InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // Select master back + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((0 << 4) | 0xe0) + ); + gBS->Stall (100); + // + // Send ATA Device Execut Diagnostic command. + // This command should work no matter DRDY is ready or not + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90); + + Status = WaitForBSYClear (IdeDev, 3500); + + ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + + // + // Master Error register is 0x01. D0 passed, D1 passed or not present. + // Master Error register is 0x81. D0 passed, D1 failed. Return. + // Master Error register is other value. D0 failed, D1 passed or not present.. + // + if (ErrorReg == 0x01) { + MasterDeviceExist = TRUE; + DeviceStatus = EFI_SUCCESS; + } else if (ErrorReg == 0x81) { + + MasterDeviceExist = TRUE; + DeviceStatus = EFI_SUCCESS; + SlaveDeviceExist = FALSE; + + return DeviceStatus; + } else { + MasterDeviceExist = FALSE; + DeviceStatus = EFI_NOT_FOUND; + } + + // + // Master Error register is not 0x81, Go on check Slave + // + + // + // select slave + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((1 << 4) | 0xe0) + ); + + gBS->Stall (300); + ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + + // + // Slave Error register is not 0x01, D1 failed. Return. + // + if (ErrorReg != 0x01) { + SlaveDeviceExist = FALSE; + return DeviceStatus; + } + + StatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // Most ATAPI devices don't set DRDY bit, so test with a slow but accurate + // "ATAPI TEST UNIT READY" command + // + if (((StatusReg & DRDY) == 0) && ((InitStatusReg & DRDY) == 0)) { + Status = AtapiTestUnitReady (IdeDev); + + // + // Still fail, Slave doesn't exist. + // + if (EFI_ERROR (Status)) { + SlaveDeviceExist = FALSE; + return DeviceStatus; + } + } + + // + // Error reg is 0x01 and DRDY is ready, + // or ATAPI test unit ready success, + // or init Slave status DRDY is ready + // Slave exists. + // + SlaveDeviceExist = TRUE; + + return DeviceStatus; + +} + +EFI_STATUS +DRQClear ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: DRQClear + + + Purpose: + This function is used to poll for the DRQ bit clear in the Status + Register. DRQ is cleared when the device is finished transferring data. + So this function is called after data transfer is finished. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ clear. + + Returns: + EFI_SUCCESS + DRQ bit clear within the time out. + + EFI_TIMEOUT + DRQ bit not clear within the time out. + + + Notes: + Read Status Register will clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +{ + UINT32 Delay; + UINT8 StatusRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // wait for BSY == 0 and DRQ == 0 + // + if ((StatusRegister & (DRQ | BSY)) == 0) { + break; + } + + if ((StatusRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DRQClear2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: DRQClear2 + + + Purpose: + This function is used to poll for the DRQ bit clear in the Alternate + Status Register. DRQ is cleared when the device is finished + transferring data. So this function is called after data transfer + is finished. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ clear. + + Returns: + EFI_SUCCESS + DRQ bit clear within the time out. + + EFI_TIMEOUT + DRQ bit not clear within the time out. + + + Notes: + Read Alternate Status Register will not clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +{ + UINT32 Delay; + UINT8 AltRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + + AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus); + + // + // wait for BSY == 0 and DRQ == 0 + // + if ((AltRegister & (DRQ | BSY)) == 0) { + break; + } + + if ((AltRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DRQReady ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: DRQReady + + + Purpose: + This function is used to poll for the DRQ bit set in the + Status Register. + DRQ is set when the device is ready to transfer data. So this function + is called after the command is sent to the device and before required + data is transferred. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure,used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + + Returns: + EFI_SUCCESS + DRQ bit set within the time out. + + EFI_TIMEOUT + DRQ bit not set within the time out. + + EFI_ABORTED + DRQ bit not set caused by the command abort. + + Notes: + Read Status Register will clear interrupt status. + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +{ + UINT32 Delay; + UINT8 StatusRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + // + // read Status Register will clear interrupt + // + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + + // + // BSY==0,DRQ==1 + // + if ((StatusRegister & (BSY | DRQ)) == DRQ) { + break; + } + + if ((StatusRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DRQReady2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: DRQReady2 + + + Purpose: + This function is used to poll for the DRQ bit set in the + Alternate Status Register. DRQ is set when the device is ready to + transfer data. So this function is called after the command + is sent to the device and before required data is transferred. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + Returns: + EFI_SUCCESS + DRQ bit set within the time out. + + EFI_TIMEOUT + DRQ bit not set within the time out. + + EFI_ABORTED + DRQ bit not set caused by the command abort. + + Notes: + Read Alternate Status Register will not clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +{ + UINT32 Delay; + UINT8 AltRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + + do { + // + // Read Alternate Status Register will not clear interrupt status + // + AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus); + // + // BSY == 0 , DRQ == 1 + // + if ((AltRegister & (BSY | DRQ)) == DRQ) { + break; + } + + if ((AltRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +WaitForBSYClear ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: + WaitForBSYClear + + + Purpose: + This function is used to poll for the BSY bit clear in the + Status Register. BSY is clear when the device is not busy. + Every command must be sent after device is not busy. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + Returns: + EFI_SUCCESS + BSY bit clear within the time out. + + EFI_TIMEOUT + BSY bit not clear within the time out. + + + Notes: + Read Status Register will clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +{ + UINT32 Delay; + UINT8 StatusRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + if ((StatusRegister & BSY) == 0x00) { + break; + } + + // + // Stall for 30 us + // + gBS->Stall (30); + + Delay--; + + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} +// +// WaitForBSYClear2 +// +EFI_STATUS +WaitForBSYClear2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + Name: + WaitForBSYClear2 + + + Purpose: + This function is used to poll for the BSY bit clear in the + Alternate Status Register. BSY is clear when the device is not busy. + Every command must be sent after device is not busy. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + Returns: + EFI_SUCCESS + BSY bit clear within the time out. + + EFI_TIMEOUT + BSY bit not clear within the time out. + + + Notes: + Read Alternate Status Register will not clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: TimeoutInMilliSeconds - add argument and description to function comment +{ + UINT32 Delay; + UINT8 AltRegister; + + Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus); + if ((AltRegister & BSY) == 0x00) { + break; + } + + gBS->Stall (30); + + Delay--; + + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +// +// DRDYReady +// +EFI_STATUS +DRDYReady ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN DelayInMilliSeconds + ) +/*++ + Name: + DRDYReady + + + Purpose: + This function is used to poll for the DRDY bit set in the + Status Register. DRDY bit is set when the device is ready + to accept command. Most ATA commands must be sent after + DRDY set except the ATAPI Packet Command. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + Returns: + EFI_SUCCESS + DRDY bit set within the time out. + + EFI_TIMEOUT + DRDY bit not set within the time out. + + + Notes: + Read Status Register will clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DelayInMilliSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +{ + UINT32 Delay; + UINT8 StatusRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + // + // BSY == 0 , DRDY == 1 + // + if ((StatusRegister & (DRDY | BSY)) == DRDY) { + break; + } + + if ((StatusRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + gBS->Stall (15); + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +// +// DRDYReady2 +// +EFI_STATUS +DRDYReady2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN DelayInMilliSeconds + ) +/*++ + Name: + DRDYReady2 + + + Purpose: + This function is used to poll for the DRDY bit set in the + Alternate Status Register. DRDY bit is set when the device is ready + to accept command. Most ATA commands must be sent after + DRDY set except the ATAPI Packet Command. + + + Parameters: + IDE_BLK_IO_DEV IN *IdeDev + pointer pointing to IDE_BLK_IO_DEV data structure, used + to record all the information of the IDE device. + + UINTN IN TimeoutInMilliSeconds + used to designate the timeout for the DRQ ready. + + Returns: + EFI_SUCCESS + DRDY bit set within the time out. + + EFI_TIMEOUT + DRDY bit not set within the time out. + + + Notes: + Read Alternate Status Register will clear interrupt status. +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: IdeDev - add argument and description to function comment +// TODO: DelayInMilliSeconds - add argument and description to function comment +// TODO: EFI_ABORTED - add return value to function comment +{ + UINT32 Delay; + UINT8 AltRegister; + UINT8 ErrorRegister; + + Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1); + do { + AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus); + // + // BSY == 0 , DRDY == 1 + // + if ((AltRegister & (DRDY | BSY)) == DRDY) { + break; + } + + if ((AltRegister & (BSY | ERR)) == ERR) { + + ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error); + if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) { + return EFI_ABORTED; + } + } + + gBS->Stall (30); + + Delay--; + } while (Delay); + + if (Delay == 0) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +// +// SwapStringChars +// +VOID +SwapStringChars ( + IN CHAR8 *Destination, + IN CHAR8 *Source, + IN UINT32 Size + ) +/*++ + Name: + SwapStringChars + + + Purpose: + This function is a helper function used to change the char order in a + string. It is designed specially for the PrintAtaModuleName() function. + After the IDE device is detected, the IDE driver gets the device module + name by sending ATA command called ATA Identify Command or ATAPI + Identify Command to the specified IDE device. The module name returned + is a string of ASCII characters: the first character is bit8--bit15 + of the first word, the second character is bit0--bit7 of the first word + and so on. Thus the string can not be print directly before it is + preprocessed by this func to change the order of characters in + each word in the string. + + + Parameters: + CHAR8 IN *Destination + Indicates the destination string. + + CHAR8 IN *Source + Indicates the source string. + + UINT8 IN Size + the length of the string + + + Returns: + none + + Notes: + +--*/ +// TODO: function comment is missing 'Routine Description:' +// TODO: function comment is missing 'Arguments:' +// TODO: Destination - add argument and description to function comment +// TODO: Source - add argument and description to function comment +// TODO: Size - add argument and description to function comment +{ + UINT32 Index; + CHAR8 Temp; + + for (Index = 0; Index < Size; Index += 2) { + + Temp = Source[Index + 1]; + Destination[Index + 1] = Source[Index]; + Destination[Index] = Temp; + } +} + +// +// ReleaseIdeResources +// +VOID +ReleaseIdeResources ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice + ) +/*++ +Routing Description: + + Release resources of an IDE device before stopping it. + +Arguments: + + IdeBlkIoDevice -- Standard IDE device private data structure + + +Returns: + + NONE + +---*/ +// TODO: function comment is missing 'Routine Description:' +{ + if (IdeBlkIoDevice == NULL) { + return ; + } + + // + // Release all the resourses occupied by the IDE_BLK_IO_DEV + // + + if (IdeBlkIoDevice->SenseData != NULL) { + gBS->FreePool (IdeBlkIoDevice->SenseData); + IdeBlkIoDevice->SenseData = NULL; + } + + if (IdeBlkIoDevice->Cache != NULL) { + gBS->FreePool (IdeBlkIoDevice->Cache); + IdeBlkIoDevice->Cache = NULL; + } + + if (IdeBlkIoDevice->pIdData != NULL) { + gBS->FreePool (IdeBlkIoDevice->pIdData); + IdeBlkIoDevice->pIdData = NULL; + } + + if (IdeBlkIoDevice->pInquiryData != NULL) { + gBS->FreePool (IdeBlkIoDevice->pInquiryData); + IdeBlkIoDevice->pInquiryData = NULL; + } + + if (IdeBlkIoDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable); + IdeBlkIoDevice->ControllerNameTable = NULL; + } + + if (IdeBlkIoDevice->IoPort != NULL) { + gBS->FreePool (IdeBlkIoDevice->IoPort); + } + + if (IdeBlkIoDevice->DevicePath != NULL) { + gBS->FreePool (IdeBlkIoDevice->DevicePath); + } + + gBS->FreePool (IdeBlkIoDevice); + IdeBlkIoDevice = NULL; + + return ; +} + +// +// SetDeviceTransferMode +// +EFI_STATUS +SetDeviceTransferMode ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATA_TRANSFER_MODE *TransferMode + ) +/*++ +Routing Description: + + Set the calculated Best transfer mode to a detected device + +Arguments: + + IdeDev -- Standard IDE device private data structure + TransferMode -- The device transfer mode to be set + +Returns: + + Set transfer mode Command execute status + +---*/ +// TODO: function comment is missing 'Routine Description:' +{ + EFI_STATUS Status; + UINT8 DeviceSelect; + UINT8 SectorCount; + + DeviceSelect = 0; + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + SectorCount = *((UINT8 *) TransferMode); + + // + // Send SET FEATURE command (sub command 0x03) to set pio mode. + // + Status = AtaNonDataCommandIn ( + IdeDev, + SET_FEATURES_CMD, + DeviceSelect, + 0x03, + SectorCount, + 0, + 0, + 0 + ); + + return Status; +} + +EFI_STATUS +AtaNonDataCommandIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT8 Feature, + IN UINT8 SectorCount, + IN UINT8 LbaLow, + IN UINT8 LbaMiddle, + IN UINT8 LbaHigh + ) +/*++ + +Routine Description: + + Send ATA command into device with NON_DATA protocol + +Arguments: + + IdeDev - Standard IDE device private data structure + AtaCommand - The ATA command to be sent + Device - The value in Device register + Feature - The value in Feature register + SectorCount - The value in SectorCount register + LbaLow - The value in LBA_LOW register + LbaMiddle - The value in LBA_MIDDLE register + LbaHigh - The value in LBA_HIGH register + +Returns: + + EFI_SUCCESS - Reading succeed + EFI_ABORTED - Command failed + EFI_DEVICE_ERROR - Device status error + +--*/ +{ + EFI_STATUS Status; + UINT8 StatusRegister; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility) + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + + // + // ATA commands for ATA device must be issued when DRDY is set + // + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Pass parameter into device register block + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + // + // Send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + // + // Wait for command completion + // + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + if ((StatusRegister & ERR) == ERR) { + // + // Failed to execute command, abort operation + // + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +AtaNonDataCommandInExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + Send ATA Ext command into device with NON_DATA protocol + +Arguments: + + IdeDev - Standard IDE device private data structure + AtaCommand - The ATA command to be sent + Device - The value in Device register + Feature - The value in Feature register + SectorCount - The value in SectorCount register + LbaAddress - The LBA address in 48-bit mode + +Returns: + + EFI_SUCCESS - Reading succeed + EFI_ABORTED - Command failed + EFI_DEVICE_ERROR - Device status error + +--*/ +{ + EFI_STATUS Status; + UINT8 StatusRegister; + UINT8 SectorCount8; + UINT8 Feature8; + UINT8 LbaLow; + UINT8 LbaMid; + UINT8 LbaHigh; + + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility) + // + IDEWritePortB ( + IdeDev->PciIo, + IdeDev->IoPort->Head, + (UINT8) ((IdeDev->Device << 4) | 0xe0) + ); + + // + // ATA commands for ATA device must be issued when DRDY is set + // + Status = DRDYReady (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Pass parameter into device register block + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device); + + // + // Fill the feature register, which is a two-byte FIFO. Need write twice. + // + Feature8 = (UINT8) (Feature >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); + + Feature8 = (UINT8) Feature; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8); + + // + // Fill the sector count register, which is a two-byte FIFO. Need write twice. + // + SectorCount8 = (UINT8) (SectorCount >> 8); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + SectorCount8 = (UINT8) SectorCount; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8); + + // + // Fill the start LBA registers, which are also two-byte FIFO + // + LbaLow = (UINT8) RShiftU64 (LbaAddress, 24); + LbaMid = (UINT8) RShiftU64 (LbaAddress, 32); + LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + LbaLow = (UINT8) LbaAddress; + LbaMid = (UINT8) RShiftU64 (LbaAddress, 8); + LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid); + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh); + + // + // Send command via Command Register + // + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand); + + // + // Wait for command completion + // + Status = WaitForBSYClear (IdeDev, ATATIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status); + if ((StatusRegister & ERR) == ERR) { + // + // Failed to execute command, abort operation + // + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +// +// SetDriveParameters +// +EFI_STATUS +SetDriveParameters ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATA_DRIVE_PARMS *DriveParameters + ) +/*++ +Routine Description: + + Set drive parameters for devices not support PACKETS command + +Arguments: + + IdeDev -- Standard IDE device private data structure + DriveParameters -- The device parameters to be set into the disk + +Returns: + + SetParameters Command execute status + +--*/ +{ + EFI_STATUS Status; + UINT8 DeviceSelect; + + DeviceSelect = 0; + DeviceSelect = (UINT8) ((IdeDev->Device) << 4); + + // + // Send Init drive parameters + // + Status = AtaPioDataIn ( + IdeDev, + NULL, + 0, + INIT_DRIVE_PARAM_CMD, + (UINT8) (DeviceSelect + DriveParameters->Heads), + DriveParameters->Sector, + 0, + 0, + 0 + ); + + // + // Send Set Multiple parameters + // + Status = AtaPioDataIn ( + IdeDev, + NULL, + 0, + SET_MULTIPLE_MODE_CMD, + DeviceSelect, + DriveParameters->MultipleSector, + 0, + 0, + 0 + ); + + return Status; +} + +EFI_STATUS +EnableInterrupt ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + EFI_SUCCESS - TODO: Add description for return value + +--*/ +{ + UINT8 DeviceControl; + + // + // Enable interrupt for DMA operation + // + DeviceControl = 0; + IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h new file mode 100644 index 0000000000..4c43ab94cd --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h @@ -0,0 +1,1806 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ide.h + +Abstract: + + Header file for IDE Bus Driver, containing the helper functions' + entire prototype. + +Revision History + + 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including + Add - IDEBlkIoReadBlocksExt() func definition + Add - IDEBlkIoWriteBlocksExt() func definition + +++*/ + +// TODO: fix comment to end with --*/ +#ifndef _IDE_H +#define _IDE_H + +// +// Helper functions Prototype +// +EFI_STATUS +DeRegisterIdeDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + Handle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EnableIdeDevice ( + IN EFI_HANDLE Controller, + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + PciIo - TODO: add argument description + ParentDevicePath - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +UINT8 +IDEReadPortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +IDEReadPortWMultiple ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINTN Count, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +IDEWritePortB ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT8 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +IDEWritePortW ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINT16 Data + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Data - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +IDEWritePortWMultiple ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 Port, + IN UINTN Count, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Port - TODO: add argument description + Count - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +GetIdeRegistersBaseAddr ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + IdeRegsBaseAddr - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ReassignIdeResources ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DiscoverIdeDevice ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DetectIDEController ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRQClear ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRQClear2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRQReady ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRQReady2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +WaitForBSYClear ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +WaitForBSYClear2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN TimeoutInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TimeoutInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRDYReady ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN DelayInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DelayInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DRDYReady2 ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINTN DelayInMilliSeconds + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DelayInMilliSeconds - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +SwapStringChars ( + IN CHAR8 *Destination, + IN CHAR8 *Source, + IN UINT32 Size + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Destination - TODO: add argument description + Source - TODO: add argument description + Size - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// ATA device functions' prototype +// +EFI_STATUS +ATAIdentify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +PrintAtaModuleName ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaPioDataIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN UINT8 Head, + IN UINT8 SectorCount, + IN UINT8 SectorNumber, + IN UINT8 CylinderLsb, + IN UINT8 CylinderMsb + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + AtaCommand - TODO: add argument description + Head - TODO: add argument description + SectorCount - TODO: add argument description + SectorNumber - TODO: add argument description + CylinderLsb - TODO: add argument description + CylinderMsb - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaPioDataOut ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN UINT8 Head, + IN UINT8 SectorCount, + IN UINT8 SectorNumber, + IN UINT8 CylinderLsb, + IN UINT8 CylinderMsb + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + AtaCommand - TODO: add argument description + Head - TODO: add argument description + SectorCount - TODO: add argument description + SectorNumber - TODO: add argument description + CylinderLsb - TODO: add argument description + CylinderMsb - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +CheckErrorStatus ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaReadSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaWriteSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *BufferData, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + BufferData - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaSoftReset ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaBlkIoReadBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevice - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaBlkIoWriteBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevice - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// ATAPI device functions' prototype +// +EFI_STATUS +ATAPIIdentify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiInquiry ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiPacketCommandIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATAPI_PACKET_COMMAND *Packet, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN UINTN TimeOut + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Packet - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + TimeOut - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiPacketCommandOut ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATAPI_PACKET_COMMAND *Packet, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN UINTN TimeOut + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Packet - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + TimeOut - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PioReadWriteData ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT16 *Buffer, + IN UINT32 ByteCount, + IN BOOLEAN Read, + IN UINTN TimeOut + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + Read - TODO: add argument description + TimeOut - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiTestUnitReady ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiRequestSense ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT UINTN *SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiReadCapacity ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiDetectMedia ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT BOOLEAN *MediaChange + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + MediaChange - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiReadSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiWriteSectors ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + Lba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiSoftReset ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiBlkIoReadBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevice - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtapiBlkIoWriteBlocks ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevice - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsNoMedia ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsMediaError ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsMediaChange ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +IsDriveReady ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts, + OUT BOOLEAN *NeedRetry + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + NeedRetry - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +HaveSenseKey ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SenseData - TODO: add argument description + SenseCounts - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +IsLS120orZipWriteProtected ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT BOOLEAN *WriteProtected + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + WriteProtected - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +VOID +ReleaseIdeResources ( + IN IDE_BLK_IO_DEV *IdeBlkIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeBlkIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SetDeviceTransferMode ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATA_TRANSFER_MODE *TransferMode + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + TransferMode - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ReadNativeMaxAddress ( + IN IDE_BLK_IO_DEV *IdeDev, + OUT EFI_LBA *NativeMaxAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + NativeMaxAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SetMaxAddress ( + IN IDE_BLK_IO_DEV *IdeDev, + IN EFI_LBA MaxAddress, + IN BOOLEAN bVolatile + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + MaxAddress - TODO: add argument description + bVolatile - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaNonDataCommandIn ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT8 Feature, + IN UINT8 SectorCount, + IN UINT8 LbaLow, + IN UINT8 LbaMiddle, + IN UINT8 LbaHigh + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + AtaCommand - TODO: add argument description + Device - TODO: add argument description + Feature - TODO: add argument description + SectorCount - TODO: add argument description + LbaLow - TODO: add argument description + LbaMiddle - TODO: add argument description + LbaHigh - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaNonDataCommandInExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + AtaCommand - TODO: add argument description + Device - TODO: add argument description + Feature - TODO: add argument description + SectorCount - TODO: add argument description + LbaAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaReadSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaWriteSectorsExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaUdmaReadExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaUdmaRead ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaUdmaWriteExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaUdmaWrite ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *DataBuffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DataBuffer - TODO: add argument description + StartLba - TODO: add argument description + NumberOfBlocks - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaCommandIssueExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + AtaCommand - TODO: add argument description + Device - TODO: add argument description + Feature - TODO: add argument description + SectorCount - TODO: add argument description + LbaAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaCommandIssue ( + IN IDE_BLK_IO_DEV *IdeDev, + IN UINT8 AtaCommand, + IN UINT8 Device, + IN UINT16 Feature, + IN UINT16 SectorCount, + IN EFI_LBA LbaAddress + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + AtaCommand - TODO: add argument description + Device - TODO: add argument description + Feature - TODO: add argument description + SectorCount - TODO: add argument description + LbaAddress - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaAtapi6Identify ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + + +VOID +AtaSMARTSupport ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaPioDataInExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN OUT VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + AtaCommand - TODO: add argument description + StartLba - TODO: add argument description + SectorCount - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AtaPioDataOutExt ( + IN IDE_BLK_IO_DEV *IdeDev, + IN VOID *Buffer, + IN UINT32 ByteCount, + IN UINT8 AtaCommand, + IN EFI_LBA StartLba, + IN UINT16 SectorCount + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + Buffer - TODO: add argument description + ByteCount - TODO: add argument description + AtaCommand - TODO: add argument description + StartLba - TODO: add argument description + SectorCount - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +SetDriveParameters ( + IN IDE_BLK_IO_DEV *IdeDev, + IN ATA_DRIVE_PARMS *DriveParameters + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + DriveParameters - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EnableInterrupt ( + IN IDE_BLK_IO_DEV *IdeDev + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + IdeDev - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c new file mode 100644 index 0000000000..2b8f52aa54 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c @@ -0,0 +1,1400 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + idebus.c + +Abstract: + + +Revision History + This module is modified from DXE\IDE module for Ide Contriller Init support + +--*/ + +#include "idebus.h" + +#define PCI_CLASS_MASS_STORAGE 0x01 +#define PCI_SUB_CLASS_IDE 0x01 + + +// +// IDE Bus Driver Binding Protocol Instance +// +EFI_DRIVER_BINDING_PROTOCOL gIDEBusDriverBinding = { + IDEBusDriverBindingSupported, + IDEBusDriverBindingStart, + IDEBusDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// *********************************************************************************** +// IDEBusDriverBindingSupported +// *********************************************************************************** +// +EFI_STATUS +EFIAPI +IDEBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + Register Driver Binding protocol for this driver. + +Arguments: + This -- A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + ControllerHandle -- The handle of the controller to test. + RemainingDevicePath -- A pointer to the remaining portion of a device path. + +Returns: + EFI_SUCCESS - Driver loaded. + other - Driver not loaded. +--*/ +// TODO: Controller - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_DEV_PATH *Node; + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit; + + if (RemainingDevicePath != NULL) { + Node = (EFI_DEV_PATH *) RemainingDevicePath; + if (Node->DevPath.Type != MESSAGING_DEVICE_PATH || + Node->DevPath.SubType != MSG_ATAPI_DP || + DevicePathNodeLength(&Node->DevPath) != sizeof(ATAPI_DEVICE_PATH)) { + return EFI_UNSUPPORTED; + } + } + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Clsoe protocol, don't use device path protocol in the .Support() function + // + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Verify the Ide Controller Init Protocol, which installed by the + // IdeController module. + // Note 1: PciIo protocol has been opened BY_DRIVER by ide_init, so We can't + // open BY_DRIVER here) That's why we don't check pciio protocol + // Note 2: ide_init driver check ide controller's pci config space, so we dont + // check here any more to save code size + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + (VOID **) &IdeInit, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + // + // If protocols were opened normally, closed it + // + gBS->CloseProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +// +// *********************************************************************************** +// IDEBusDriverBindingStart +// *********************************************************************************** +// +EFI_STATUS +EFIAPI +IDEBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Start this driver on Controller by detecting all disks and installing + BlockIo protocol on them. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to bind driver to. + RemainingDevicePath - Not used, always produce all possible children. + + Returns: + EFI_SUCCESS - This driver is added to ControllerHandle. + EFI_ALREADY_STARTED - This driver is already running on ControllerHandle. + other - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS SavedStatus; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_DEV_PATH *Node; + UINT8 IdeChannel; + UINT8 BeginningIdeChannel; + UINT8 EndIdeChannel; + UINT8 IdeDevice; + UINT8 BeginningIdeDevice; + UINT8 EndIdeDevice; + IDE_BLK_IO_DEV *IdeBlkIoDevice[IdeMaxChannel][IdeMaxDevice]; + IDE_BLK_IO_DEV *IdeBlkIoDevicePtr; + IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel]; + ATA_TRANSFER_MODE TransferMode; + ATA_DRIVE_PARMS DriveParameters; + EFI_DEV_PATH NewNode; + UINT8 ConfigurationOptions; + UINT16 CommandBlockBaseAddr; + UINT16 ControlBlockBaseAddr; + UINTN DataSize; + UINT32 Attributes; + IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData; + + // + // Local variables declaration for IdeControllerInit support + // + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit; + BOOLEAN EnumAll; + BOOLEAN ChannelEnabled; + UINT8 ChannelCount; + UINT8 MaxDevices; + EFI_IDENTIFY_DATA IdentifyData; + EFI_ATA_COLLECTIVE_MODE *SupportedModes; + + IdeBusDriverPrivateData = NULL; + SupportedModes = NULL; + + // + // Perform IdeBus initialization + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + // + // Now open the IDE_CONTROLLER_INIT protocol. Step7.1 + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + (VOID **) &IdeInit, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + // + // The following OpenProtocol function with _GET_PROTOCOL attribute and + // will not return EFI_ALREADY_STARTED, so save it for now + // + SavedStatus = Status; + + if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) { + DEBUG ((EFI_D_ERROR, "Open Init, Status=%x", Status)); + // + // open protocol is not SUCCESS or not ALREADY_STARTED, error exit + // + goto ErrorExit; + } + + // + // Save Enumall and ChannelCount. Step7.2 + // + EnumAll = IdeInit->EnumAll; + ChannelCount = IdeInit->ChannelCount; + + // + // Consume PCI I/O protocol. Note that the OpenProtocol with _GET_PROTOCOL + // attribute will not return EFI_ALREADY_STARTED + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Open PciIo, Status=%x", Status)); + goto ErrorExit; + } + + // + // We must check EFI_ALREADY_STARTED because many ATAPI devices are removable + // + if (SavedStatus != EFI_ALREADY_STARTED) { + IdeBusDriverPrivateData = AllocatePool (sizeof (IDE_BUS_DRIVER_PRIVATE_DATA)); + if (IdeBusDriverPrivateData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + ZeroMem (IdeBusDriverPrivateData, sizeof (IDE_BUS_DRIVER_PRIVATE_DATA)); + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiCallerIdGuid, + IdeBusDriverPrivateData, + NULL + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + } else { + Status = gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + (VOID **) &IdeBusDriverPrivateData, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + IdeBusDriverPrivateData = NULL; + goto ErrorExit; + } + } + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE, + NULL + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Read the environment variable that contains the IDEBus Driver's + // Config options that were set by the Driver Configuration Protocol + // + DataSize = sizeof (ConfigurationOptions); + Status = gRT->GetVariable ( + (CHAR16 *) L"Configuration", + &gEfiCallerIdGuid, + &Attributes, + &DataSize, + &ConfigurationOptions + ); + if (EFI_ERROR (Status)) { + ConfigurationOptions = 0x0f; + } + + if (EnumAll) { + // + // If IdeInit->EnumAll is TRUE, must enumerate all IDE device anyway + // + BeginningIdeChannel = IdePrimary; + EndIdeChannel = IdeSecondary; + BeginningIdeDevice = IdeMaster; + EndIdeDevice = IdeSlave; + } else if (RemainingDevicePath == NULL) { + // + // RemainingDevicePath is NULL, scan IDE bus for each device; + // + BeginningIdeChannel = IdePrimary; + EndIdeChannel = IdeSecondary; + BeginningIdeDevice = IdeMaster; + // + // default, may be redefined by IdeInit + // + EndIdeDevice = IdeSlave; + } else { + // + // RemainingDevicePath is not NULL, only scan the specified device. + // + Node = (EFI_DEV_PATH *) RemainingDevicePath; + BeginningIdeChannel = Node->Atapi.PrimarySecondary; + EndIdeChannel = BeginningIdeChannel; + BeginningIdeDevice = Node->Atapi.SlaveMaster; + EndIdeDevice = BeginningIdeDevice; + } + + // + // Obtain IDE IO port registers' base addresses + // + Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Report status code: begin IdeBus initialization + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET), + ParentDevicePath + ); + + // + // Strictly follow the enumeration based on IDE_CONTROLLER_INIT protocol + // + for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) { + + IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, IdeChannel); + + // + // now obtain channel information fron IdeControllerInit protocol. Step9 + // + Status = IdeInit->GetChannelInfo ( + IdeInit, + IdeChannel, + &ChannelEnabled, + &MaxDevices + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[GetChannel, Status=%x]", Status)); + continue; + } + + if (!ChannelEnabled) { + continue; + } + + EndIdeDevice = (UINT8) EFI_MIN ((MaxDevices - 1), EndIdeDevice); + + // + // Now inform the IDE Controller Init Module. Sept10 + // + IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelReset, IdeChannel); + + // + // No reset channel function implemented. Sept11 + // + IdeInit->NotifyPhase (IdeInit, EfiIdeAfterChannelReset, IdeChannel); + + // + // Step13 + // + IdeInit->NotifyPhase ( + IdeInit, + EfiIdeBusBeforeDevicePresenceDetection, + IdeChannel + ); + // + // -- 1st inner loop --- Master/Slave ------------ Step14 + // + for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) { + // + // Check whether the configuration options allow this device + // + if (!(ConfigurationOptions & (1 << (IdeChannel * 2 + IdeDevice)))) { + continue; + } + + // + // The device has been scanned in another Start(), No need to scan it again + // for perf optimization. + // + if (IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice]) { + continue; + } + + // + // create child handle for the detected device. + // + IdeBlkIoDevice[IdeChannel][IdeDevice] = AllocatePool (sizeof (IDE_BLK_IO_DEV)); + if (IdeBlkIoDevice[IdeChannel][IdeDevice] == NULL) { + continue; + } + + IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice]; + + ZeroMem (IdeBlkIoDevicePtr, sizeof (IDE_BLK_IO_DEV)); + + IdeBlkIoDevicePtr->Signature = IDE_BLK_IO_DEV_SIGNATURE; + IdeBlkIoDevicePtr->Channel = IdeChannel; + IdeBlkIoDevicePtr->Device = IdeDevice; + + // + // initialize Block IO interface's Media pointer + // + IdeBlkIoDevicePtr->BlkIo.Media = &IdeBlkIoDevicePtr->BlkMedia; + + // + // Initialize IDE IO port addresses, including Command Block registers + // and Control Block registers + // + IdeBlkIoDevicePtr->IoPort = AllocatePool (sizeof (IDE_BASE_REGISTERS)); + if (IdeBlkIoDevicePtr->IoPort == NULL) { + continue; + } + + ZeroMem (IdeBlkIoDevicePtr->IoPort, sizeof (IDE_BASE_REGISTERS)); + CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr; + ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr; + + IdeBlkIoDevicePtr->IoPort->Data = CommandBlockBaseAddr; + (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01); + IdeBlkIoDevicePtr->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02); + IdeBlkIoDevicePtr->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03); + IdeBlkIoDevicePtr->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04); + IdeBlkIoDevicePtr->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05); + IdeBlkIoDevicePtr->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06); + (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07); + + (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Alt) = ControlBlockBaseAddr; + IdeBlkIoDevicePtr->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01); + + IdeBlkIoDevicePtr->IoPort->MasterSlave = (UINT16) ((IdeDevice == IdeMaster) ? 1 : 0); + + IdeBlkIoDevicePtr->PciIo = PciIo; + IdeBlkIoDevicePtr->IdeBusDriverPrivateData = IdeBusDriverPrivateData; + IdeBlkIoDevicePtr->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeChannel].BusMasterBaseAddr; + + // + // Report Status code: is about to detect IDE drive + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_PRESENCE_DETECT), + IdeBlkIoDevicePtr->DevicePath + ); + + // + // Discover device, now! + // + PERF_START (0, "DiscoverIdeDevice", "IDE", 0); + Status = DiscoverIdeDevice (IdeBlkIoDevicePtr); + PERF_END (0, "DiscoverIdeDevice", "IDE", 0); + + IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice] = TRUE; + IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = FALSE; + + if (!EFI_ERROR (Status)) { + // + // Set Device Path + // + ZeroMem (&NewNode, sizeof (NewNode)); + NewNode.DevPath.Type = MESSAGING_DEVICE_PATH; + NewNode.DevPath.SubType = MSG_ATAPI_DP; + SetDevicePathNodeLength (&NewNode.DevPath, sizeof (ATAPI_DEVICE_PATH)); + + NewNode.Atapi.PrimarySecondary = (UINT8) IdeBlkIoDevicePtr->Channel; + NewNode.Atapi.SlaveMaster = (UINT8) IdeBlkIoDevicePtr->Device; + NewNode.Atapi.Lun = IdeBlkIoDevicePtr->Lun; + IdeBlkIoDevicePtr->DevicePath = AppendDevicePathNode ( + ParentDevicePath, + &NewNode.DevPath + ); + if (IdeBlkIoDevicePtr->DevicePath == NULL) { + ReleaseIdeResources (IdeBlkIoDevicePtr); + continue; + } + + // + // Submit identify data to IDE controller init driver + // + CopyMem (&IdentifyData, IdeBlkIoDevicePtr->pIdData, sizeof (IdentifyData)); + // IdentifyData = *IdeBlkIoDevicePtr->pIdData; + IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = TRUE; + IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &IdentifyData); + } else { + // + // Device detection failed + // + IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; + IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, NULL); + ReleaseIdeResources (IdeBlkIoDevicePtr); + IdeBlkIoDevicePtr = NULL; + } + // + // end of 1st inner loop --- + // + } + // + // end of 1st outer loop ========= + // + } + + // + // = 2nd outer loop == Primary/Secondary ================= + // + for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) { + + // + // -- 2nd inner loop --- Master/Slave -------- + // + for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) { + + if (IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice]) { + continue; + } + + if (!IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice]) { + continue; + } + + Status = IdeInit->CalculateMode ( + IdeInit, + IdeChannel, + IdeDevice, + &SupportedModes + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[bStStp20S=%x]", Status)); + continue; + } + + IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice]; + + // + // Set best supported PIO mode on this IDE device + // + if (SupportedModes->PioMode.Mode <= ATA_PIO_MODE_2) { + TransferMode.ModeCategory = ATA_MODE_CATEGORY_DEFAULT_PIO; + } else { + TransferMode.ModeCategory = ATA_MODE_CATEGORY_FLOW_PIO; + } + + TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode); + + if (SupportedModes->ExtModeCount == 0){ + Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode); + + if (EFI_ERROR (Status)) { + IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; + ReleaseIdeResources (IdeBlkIoDevicePtr); + IdeBlkIoDevicePtr = NULL; + continue; + } + } + + // + // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't + // be set together. Only one DMA mode can be set to a device. If setting + // DMA mode operation fails, we can continue moving on because we only use + // PIO mode at boot time. DMA modes are used by certain kind of OS booting + // + if (SupportedModes->UdmaMode.Valid) { + + TransferMode.ModeCategory = ATA_MODE_CATEGORY_UDMA; + TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode); + Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode); + + if (EFI_ERROR (Status)) { + IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; + ReleaseIdeResources (IdeBlkIoDevicePtr); + IdeBlkIoDevicePtr = NULL; + continue; + } + + EnableInterrupt (IdeBlkIoDevicePtr); + } else if (SupportedModes->MultiWordDmaMode.Valid) { + + TransferMode.ModeCategory = ATA_MODE_CATEGORY_MDMA; + TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode; + Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode); + + if (EFI_ERROR (Status)) { + IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE; + ReleaseIdeResources (IdeBlkIoDevicePtr); + IdeBlkIoDevicePtr = NULL; + continue; + } + + EnableInterrupt (IdeBlkIoDevicePtr); + } + // + // Init driver parameters + // + DriveParameters.Sector = (UINT8) IdeBlkIoDevicePtr->pIdData->AtaData.sectors_per_track; + DriveParameters.Heads = (UINT8) (IdeBlkIoDevicePtr->pIdData->AtaData.heads - 1); + DriveParameters.MultipleSector = (UINT8) IdeBlkIoDevicePtr->pIdData->AtaData.multi_sector_cmd_max_sct_cnt; + // + // Set Parameters for the device: + // 1) Init + // 2) Establish the block count for READ/WRITE MULTIPLE (EXT) command + // + if ((IdeBlkIoDevicePtr->Type == IdeHardDisk) || (IdeBlkIoDevicePtr->Type == Ide48bitAddressingHardDisk)) { + Status = SetDriveParameters (IdeBlkIoDevicePtr, &DriveParameters); + } + + // + // Record PIO mode used in private data + // + IdeBlkIoDevicePtr->PioMode = SupportedModes->PioMode.Mode; + + // + // Set IDE controller Timing Blocks in the PCI Configuration Space + // + IdeInit->SetTiming (IdeInit, IdeChannel, IdeDevice, SupportedModes); + + // + // Add Component Name for the IDE/ATAPI device that was discovered. + // + IdeBlkIoDevicePtr->ControllerNameTable = NULL; + ADD_NAME (IdeBlkIoDevicePtr); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &IdeBlkIoDevicePtr->Handle, + &gEfiDevicePathProtocolGuid, + IdeBlkIoDevicePtr->DevicePath, + &gEfiBlockIoProtocolGuid, + &IdeBlkIoDevicePtr->BlkIo, + &gEfiDiskInfoProtocolGuid, + &IdeBlkIoDevicePtr->DiskInfo, + NULL + ); + + if (EFI_ERROR (Status)) { + ReleaseIdeResources (IdeBlkIoDevicePtr); + } + + gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + IdeBlkIoDevicePtr->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = TRUE; + + // + // Report status code: device eanbled! + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_ENABLE), + IdeBlkIoDevicePtr->DevicePath + ); + // + // end of 2nd inner loop ---- + // + } + // + // end of 2nd outer loop ========== + // + } + + // + // All configurations done! Notify IdeController to do post initialization + // work such as saving IDE controller PCI settings for S3 resume + // + IdeInit->NotifyPhase (IdeInit, EfiIdeBusPhaseMaximum, 0); + + if (SupportedModes != NULL) { + gBS->FreePool (SupportedModes); + } + + PERF_START (0, "Finish IDE detection", "IDE", 1); + PERF_END (0, "Finish IDE detection", "IDE", 0); + + return EFI_SUCCESS; + +ErrorExit: + + // + // Report error code: controller error + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_EC_CONTROLLER_ERROR), + ParentDevicePath + ); + + gBS->CloseProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiCallerIdGuid, + IdeBusDriverPrivateData, + NULL + ); + + if (IdeBusDriverPrivateData != NULL) { + gBS->FreePool (IdeBusDriverPrivateData); + } + + if (SupportedModes != NULL) { + gBS->FreePool (SupportedModes); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; + +} + +// +// *********************************************************************************** +// IDEBusDriverBindingStop +// *********************************************************************************** +// +EFI_STATUS +EFIAPI +IDEBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on Controller Handle. + + Arguments: + This - Protocol instance pointer. + DeviceHandle - Handle of device to stop driver on + NumberOfChildren - Not used + ChildHandleBuffer - Not used + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + other - This driver was not removed from this device + +--*/ +// TODO: Controller - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + BOOLEAN AllChildrenStopped; + UINTN Index; + IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData; + + IdeBusDriverPrivateData = NULL; + + if (NumberOfChildren == 0) { + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationDisable, + EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE, + NULL + ); + } + + gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + (VOID **) &IdeBusDriverPrivateData, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiCallerIdGuid, + IdeBusDriverPrivateData, + NULL + ); + + if (IdeBusDriverPrivateData != NULL) { + gBS->FreePool (IdeBusDriverPrivateData); + } + // + // Close the bus driver + // + gBS->CloseProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + + Status = DeRegisterIdeDevice (This, Controller, ChildHandleBuffer[Index]); + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +// +// *********************************************************************************** +// DeRegisterIdeDevice +// *********************************************************************************** +// +EFI_STATUS +DeRegisterIdeDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + Deregister an IDE device and free resources + +Arguments: + + This - Protocol instance pointer. + Controller - Ide device handle + Handle - Handle of device to deregister driver on + +Returns: + + EFI_STATUS + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + IDE_BLK_IO_DEV *IdeBlkIoDevice; + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN Index; + + Status = gBS->OpenProtocol ( + Handle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo); + + // + // Report Status code: Device disabled + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_DISABLE), + IdeBlkIoDevice->DevicePath + ); + + // + // Close the child handle + // + Status = gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handle, + &gEfiDevicePathProtocolGuid, + IdeBlkIoDevice->DevicePath, + &gEfiBlockIoProtocolGuid, + &IdeBlkIoDevice->BlkIo, + &gEfiDiskInfoProtocolGuid, + &IdeBlkIoDevice->DiskInfo, + NULL + ); + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + return Status; + } + + // + // Release allocated resources + // + Index = IdeBlkIoDevice->Channel * 2 + IdeBlkIoDevice->Device; + IdeBlkIoDevice->IdeBusDriverPrivateData->HaveScannedDevice[Index] = FALSE; + + ReleaseIdeResources (IdeBlkIoDevice); + + return EFI_SUCCESS; +} + +// +// *********************************************************************************** +// IDEBlkIoReset +// *********************************************************************************** +// +EFI_STATUS +EFIAPI +IDEBlkIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: ExtendedVerification - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + EFI_STATUS Status; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This); + // + // Requery IDE IO resources in case of the switch of native and legacy modes + // + ReassignIdeResources (IdeBlkIoDevice); + + // + // for ATA device, using ATA reset method + // + if (IdeBlkIoDevice->Type == IdeHardDisk) { + return AtaSoftReset (IdeBlkIoDevice); + } + + if (IdeBlkIoDevice->Type == IdeUnknown) { + return EFI_DEVICE_ERROR; + } + + // + // for ATAPI device, using ATAPI reset method + // + Status = AtapiSoftReset (IdeBlkIoDevice); + if (ExtendedVerification) { + Status = AtaSoftReset (IdeBlkIoDevice); + } + + return Status; +} + +EFI_STATUS +EFIAPI +IDEBlkIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Read data from block io device + +Arguments: + + This - Protocol instance pointer. + MediaId - The media ID of the device + LBA - Starting LBA address to read data + BufferSize - The size of data to be read + Buffer - Caller supplied buffer to save data + +Returns: + + read data status + +--*/ +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This); + + // + // Requery IDE IO resources in case of the switch of native and legacy modes + // + ReassignIdeResources (IdeBlkIoDevice); + + // + // For ATA compatible device, use ATA read block's mechanism + // + if (IdeBlkIoDevice->Type == IdeHardDisk || + IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) { + return AtaBlkIoReadBlocks ( + IdeBlkIoDevice, + MediaId, + LBA, + BufferSize, + Buffer + ); + } + + if (IdeBlkIoDevice->Type == IdeUnknown) { + return EFI_DEVICE_ERROR; + } + + // + // for ATAPI device, using ATAPI read block's mechanism + // + return AtapiBlkIoReadBlocks ( + IdeBlkIoDevice, + MediaId, + LBA, + BufferSize, + Buffer + ); + +} + +EFI_STATUS +EFIAPI +IDEBlkIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Write data to block io device + +Arguments: + + This - Protocol instance pointer. + MediaId - The media ID of the device + LBA - Starting LBA address to write data + BufferSize - The size of data to be written + Buffer - Caller supplied buffer to save data + +Returns: + + write data status + +--*/ +// TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This); + // + // Requery IDE IO resources in case of the switch of native and legacy modes + // + ReassignIdeResources (IdeBlkIoDevice); + + // + // for ATA device, using ATA write block's mechanism + // + if (IdeBlkIoDevice->Type == IdeHardDisk || + IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) { + + return AtaBlkIoWriteBlocks ( + IdeBlkIoDevice, + MediaId, + LBA, + BufferSize, + Buffer + ); + } + + if (IdeBlkIoDevice->Type == IdeUnknown) { + return EFI_DEVICE_ERROR; + } + + // + // for ATAPI device, using ATAPI write block's mechanism + // + return AtapiBlkIoWriteBlocks ( + IdeBlkIoDevice, + MediaId, + LBA, + BufferSize, + Buffer + ); +} + +// +// *********************************************************************************** +// IDEBlkIoFlushBlocks +// *********************************************************************************** +// +EFI_STATUS +EFIAPI +IDEBlkIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: This - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + // + // return directly + // + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IDEDiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *InquiryDataSize + ) +/*++ + + Routine Description: + Return the results of the Inquiry command to a drive in InquiryData. + Data format of Inquiry data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + InquiryData - Results of Inquiry command to device + InquiryDataSize - Size of InquiryData in bytes. + + Returns: + EFI_SUCCESS - InquiryData valid + EFI_NOT_FOUND - Device does not support this data class + EFI_DEVICE_ERROR - Error reading InquiryData from device + EFI_BUFFER_TOO_SMALL - IntquiryDataSize not big enough + +--*/ +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This); + + if (*InquiryDataSize < sizeof (INQUIRY_DATA)) { + *InquiryDataSize = sizeof (INQUIRY_DATA); + return EFI_BUFFER_TOO_SMALL; + } + + if (IdeBlkIoDevice->pInquiryData == NULL) { + return EFI_NOT_FOUND; + } + + gBS->CopyMem (InquiryData, IdeBlkIoDevice->pInquiryData, sizeof (INQUIRY_DATA)); + *InquiryDataSize = sizeof (INQUIRY_DATA); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IDEDiskInfoIdentify ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize + ) +/*++ + + Routine Description: + Return the results of the Identify command to a drive in IdentifyData. + Data format of Identify data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + IdentifyData - Results of Identify command to device + IdentifyDataSize - Size of IdentifyData in bytes. + + Returns: + EFI_SUCCESS - IdentifyData valid + EFI_NOT_FOUND - Device does not support this data class + EFI_DEVICE_ERROR - Error reading IdentifyData from device + EFI_BUFFER_TOO_SMALL - IdentifyDataSize not big enough + +--*/ +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This); + + if (*IdentifyDataSize < sizeof (EFI_IDENTIFY_DATA)) { + *IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA); + return EFI_BUFFER_TOO_SMALL; + } + + if (IdeBlkIoDevice->pIdData == NULL) { + return EFI_NOT_FOUND; + } + + gBS->CopyMem (IdentifyData, IdeBlkIoDevice->pIdData, sizeof (EFI_IDENTIFY_DATA)); + *IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +IDEDiskInfoSenseData ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *SenseData, + IN OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber + ) +/*++ + + Routine Description: + Return the results of the Request Sense command to a drive in SenseData. + Data format of Sense data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + SenseData - Results of Request Sense command to device + SenseDataSize - Size of SenseData in bytes. + SenseDataNumber - Type of SenseData + + Returns: + EFI_SUCCESS - InquiryData valid + EFI_NOT_FOUND - Device does not support this data class + EFI_DEVICE_ERROR - Error reading InquiryData from device + EFI_BUFFER_TOO_SMALL - SenseDataSize not big enough + +--*/ +{ + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +IDEDiskInfoWhichIde ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice + ) +/*++ + + Routine Description: + Return the results of the Request Sense command to a drive in SenseData. + Data format of Sense data is defined by the Interface GUID. + + Arguments: + This - Protocol instance pointer. + IdeChannel - Primary or Secondary + IdeDevice - Master or Slave + + Returns: + EFI_SUCCESS - IdeChannel and IdeDevice are valid + EFI_UNSUPPORTED - This is not an IDE device + +--*/ +{ + IDE_BLK_IO_DEV *IdeBlkIoDevice; + + IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This); + *IdeChannel = IdeBlkIoDevice->Channel; + *IdeDevice = IdeBlkIoDevice->Device; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h new file mode 100644 index 0000000000..2e3caaf1b7 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h @@ -0,0 +1,439 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + idebus.h + +Abstract: + + Header file for IDE Bus Driver. + +Revision History +++*/ + +// TODO: fix comment to end with --*/ +#ifndef _IDE_BUS_H +#define _IDE_BUS_H + + +#include +#include "idedata.h" + +// +// Extra Definition to porting +// +#define EFI_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#define MAX_IDE_DEVICE 4 +#define MAX_IDE_CHANNELS 2 +#define MAX_IDE_DRIVES 2 + +typedef struct { + BOOLEAN HaveScannedDevice[MAX_IDE_DEVICE]; + BOOLEAN DeviceFound[MAX_IDE_DEVICE]; + BOOLEAN DeviceProcessed[MAX_IDE_DEVICE]; +} IDE_BUS_DRIVER_PRIVATE_DATA; + +#define IDE_BLK_IO_DEV_SIGNATURE EFI_SIGNATURE_32 ('i', 'b', 'i', 'd') + +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + EFI_BLOCK_IO_PROTOCOL BlkIo; + EFI_BLOCK_IO_MEDIA BlkMedia; + EFI_DISK_INFO_PROTOCOL DiskInfo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_PCI_IO_PROTOCOL *PciIo; + IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData; + + // + // Local Data for IDE interface goes here + // + EFI_IDE_CHANNEL Channel; + EFI_IDE_DEVICE Device; + UINT16 Lun; + IDE_DEVICE_TYPE Type; + + IDE_BASE_REGISTERS *IoPort; + UINT16 AtapiError; + + INQUIRY_DATA *pInquiryData; + EFI_IDENTIFY_DATA *pIdData; + ATA_PIO_MODE PioMode; + ATA_UDMA_MODE UDma_Mode; + CHAR8 ModelName[41]; + REQUEST_SENSE_DATA *SenseData; + UINT8 SenseDataNumber; + UINT8 *Cache; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} IDE_BLK_IO_DEV; + +#include "ComponentName.h" + +#define IDE_BLOCK_IO_DEV_FROM_THIS(a) CR (a, IDE_BLK_IO_DEV, BlkIo, IDE_BLK_IO_DEV_SIGNATURE) +#define IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS(a) CR (a, IDE_BLK_IO_DEV, DiskInfo, IDE_BLK_IO_DEV_SIGNATURE) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gIDEBusDriverBinding; + +#include "ide.h" + +// +// Prototypes +// Driver model protocol interface +// +EFI_STATUS +EFIAPI +IDEBusControllerDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + ImageHandle - TODO: add argument description + SystemTable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + Controller - TODO: add argument description + NumberOfChildren - TODO: add argument description + ChildHandleBuffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +// +// Block I/O Protocol Interface +// +EFI_STATUS +EFIAPI +IDEBlkIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + ExtendedVerification - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBlkIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBlkIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + MediaId - TODO: add argument description + LBA - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEBlkIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +IDERegisterDecodeEnableorDisable ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIo - TODO: add argument description + Enable - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEDiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *IntquiryDataSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + InquiryData - TODO: add argument description + IntquiryDataSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEDiskInfoIdentify ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + IdentifyData - TODO: add argument description + IdentifyDataSize - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEDiskInfoSenseData ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *SenseData, + IN OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + SenseData - TODO: add argument description + SenseDataSize - TODO: add argument description + SenseDataNumber - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +IDEDiskInfoWhichIde ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + IdeChannel - TODO: add argument description + IdeDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd new file mode 100644 index 0000000000..f6e3ba1c8a --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd @@ -0,0 +1,45 @@ + + + + + IdeBus + 69FD8E47-A161-4550-B01A-5594CEB2B2B2 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-22 16:27 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + DxeMemoryAllocationLib + UefiDevicePathLib + BasePerformanceLibNull + + diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa new file mode 100644 index 0000000000..1b303c6823 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa @@ -0,0 +1,90 @@ + + + + + IdeBus + DXE_DRIVER + BS_DRIVER + 69FD8E47-A161-4550-B01A-5594CEB2B2B2 + 0 + Component description file for PS2 keyboard module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-22 16:27 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + ReportStatusCodeLib + MemoryAllocationLib + PerformanceLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DevicePathLib + + + idebus.h + ide.h + idedata.h + idebus.c + ide.c + ata.c + atapi.c + ComponentName.c + ComponentName.h + + + MdePkg + EdkModulePkg + + + DevicePath + PciIo + IdeControllerInit + BlockIo + DiskInfo + + + + Configuration + 0x69fd8e47, 0xa161, 0x4550, 0xb0, 0x1a, 0x55, 0x94, 0xce, 0xb2, 0xb2, 0xb2 + + + + + DiskInfoIde + + + + + + + + gIDEBusDriverBinding + gIDEBusComponentName + + + diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd new file mode 100644 index 0000000000..fa4bc333d4 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd @@ -0,0 +1,44 @@ + + + + + IdeBusLite + 69FD8E47-A161-4550-B01A-5594CEB2B2B2 + 0 + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibNull + EdkDxePrintLib + BaseLib + UefiDevicePathLib + BasePerformanceLibNull + + diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa new file mode 100644 index 0000000000..71fc18ddce --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa @@ -0,0 +1,86 @@ + + + + + IdeBusLite + DXE_DRIVER + BS_DRIVER + 69FD8E47-A161-4550-B01A-5594CEB2B2B2 + 0 + Component description file for PS2 keyboard module. + FIX ME! + Copyright (c) 2004-2006, Intel Corporation + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + PerformanceLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DevicePathLib + + + idebus.h + ide.h + idedata.h + idebus.c + ide.c + ata.c + atapi.c + + + MdePkg + EdkModulePkg + + + DevicePath + PciIo + IdeControllerInit + BlockIo + DiskInfo + + + + DiskInfoIde + + + DiskInfoScsi + + + DiskInfoUsb + + + + + + + + gIDEBusDriverBinding + gIDEBusComponentName + + + diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h new file mode 100644 index 0000000000..50b1f05a47 --- /dev/null +++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h @@ -0,0 +1,879 @@ +/*++ +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + idedata.h + +Abstract: + + Header file for IDE Bus Driver's Data Structures + +Revision History +++*/ + +// TODO: fix comment to end with --*/ +#ifndef _IDE_DATA_H +#define _IDE_DATA_H + +// +// bit definition +// +#define bit0 (1 << 0) +#define bit1 (1 << 1) +#define bit2 (1 << 2) +#define bit3 (1 << 3) +#define bit4 (1 << 4) +#define bit5 (1 << 5) +#define bit6 (1 << 6) +#define bit7 (1 << 7) +#define bit8 (1 << 8) +#define bit9 (1 << 9) +#define bit10 (1 << 10) +#define bit11 (1 << 11) +#define bit12 (1 << 12) +#define bit13 (1 << 13) +#define bit14 (1 << 14) +#define bit15 (1 << 15) +#define bit16 (1 << 16) +#define bit17 (1 << 17) +#define bit18 (1 << 18) +#define bit19 (1 << 19) +#define bit20 (1 << 20) +#define bit21 (1 << 21) +#define bit22 (1 << 22) +#define bit23 (1 << 23) +#define bit24 (1 << 24) +#define bit25 (1 << 25) +#define bit26 (1 << 26) +#define bit27 (1 << 27) +#define bit28 (1 << 28) +#define bit29 (1 << 29) +#define bit30 (1 << 30) +#define bit31 (1 << 31) + +// +// common constants +// +#define STALL_1_MILLI_SECOND 1000 // stall 1 ms +#define STALL_1_SECOND 1000000 // stall 1 second +typedef enum { + IdePrimary = 0, + IdeSecondary = 1, + IdeMaxChannel = 2 +} EFI_IDE_CHANNEL; + +typedef enum { + IdeMaster = 0, + IdeSlave = 1, + IdeMaxDevice = 2 +} EFI_IDE_DEVICE; + +typedef enum { + IdeMagnetic, /* ZIP Drive or LS120 Floppy Drive */ + IdeCdRom, /* ATAPI CDROM */ + IdeHardDisk, /* Hard Disk */ + Ide48bitAddressingHardDisk, /* Hard Disk larger than 120GB */ + IdeUnknown +} IDE_DEVICE_TYPE; + +// +// IDE Registers +// +typedef union { + UINT16 Command; /* when write */ + UINT16 Status; /* when read */ +} IDE_CMD_OR_STATUS; + +typedef union { + UINT16 Error; /* when read */ + UINT16 Feature; /* when write */ +} IDE_ERROR_OR_FEATURE; + +typedef union { + UINT16 AltStatus; /* when read */ + UINT16 DeviceControl; /* when write */ +} IDE_AltStatus_OR_DeviceControl; + +// +// IDE registers set +// +typedef struct { + UINT16 Data; + IDE_ERROR_OR_FEATURE Reg1; + UINT16 SectorCount; + UINT16 SectorNumber; + UINT16 CylinderLsb; + UINT16 CylinderMsb; + UINT16 Head; + IDE_CMD_OR_STATUS Reg; + + IDE_AltStatus_OR_DeviceControl Alt; + UINT16 DriveAddress; + + UINT16 MasterSlave; + UINT16 BusMasterBaseAddr; +} IDE_BASE_REGISTERS; + +// +// IDE registers' base addresses +// +typedef struct { + UINT16 CommandBlockBaseAddr; + UINT16 ControlBlockBaseAddr; + UINT16 BusMasterBaseAddr; +} IDE_REGISTERS_BASE_ADDR; + +// +// Bit definitions in Programming Interface byte of the Class Code field +// in PCI IDE controller's Configuration Space +// +#define IDE_PRIMARY_OPERATING_MODE bit0 +#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR bit1 +#define IDE_SECONDARY_OPERATING_MODE bit2 +#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR bit3 + +// +// IDE registers bit definitions +// + +// +// Err Reg +// +#define BBK_ERR bit7 /* Bad block detected */ +#define UNC_ERR bit6 /* Uncorrectable Data */ +#define MC_ERR bit5 /* Media Change */ +#define IDNF_ERR bit4 /* ID Not Found */ +#define MCR_ERR bit3 /* Media Change Requested */ +#define ABRT_ERR bit2 /* Aborted Command */ +#define TK0NF_ERR bit1 /* Track 0 Not Found */ +#define AMNF_ERR bit0 /* Address Mark Not Found */ + +// +// Device/Head Reg +// +#define LBA_MODE bit6 +#define DEV bit4 +#define HS3 bit3 +#define HS2 bit2 +#define HS1 bit1 +#define HS0 bit0 +#define CHS_MODE (0) +#define DRV0 (0) +#define DRV1 (1) +#define MST_DRV DRV0 +#define SLV_DRV DRV1 + +// +// Status Reg +// +#define BSY bit7 /* Controller Busy */ +#define DRDY bit6 /* Drive Ready */ +#define DWF bit5 /* Drive Write Fault */ +#define DSC bit4 /* Disk Seek Complete */ +#define DRQ bit3 /* Data Request */ +#define CORR bit2 /* Corrected Data */ +#define IDX bit1 /* Index */ +#define ERR bit0 /* Error */ + +// +// Device Control Reg +// +#define SRST bit2 /* Software Reset */ +#define IEN_L bit1 /* Interrupt Enable #*/ + +// +// Bus Master Reg +// +#define BMIC_nREAD bit3 +#define BMIC_START bit0 +#define BMIS_INTERRUPT bit2 +#define BMIS_ERROR bit1 + +#define BMICP_OFFSET 0x00 +#define BMISP_OFFSET 0x02 +#define BMIDP_OFFSET 0x04 +#define BMICS_OFFSET 0x08 +#define BMISS_OFFSET 0x0A +#define BMIDS_OFFSET 0x0C + +// +// Time Out Value For IDE Device Polling +// + +// +// ATATIMEOUT is used for waiting time out for ATA device +// + +// +// 1 second +// +#define ATATIMEOUT 1000 + +// +// ATAPITIMEOUT is used for waiting operation +// except read and write time out for ATAPI device +// + +// +// 1 second +// +#define ATAPITIMEOUT 1000 + +// +// ATAPILONGTIMEOUT is used for waiting read and +// write operation timeout for ATAPI device +// + +// +// 2 seconds +// +#define CDROMLONGTIMEOUT 2000 + +// +// 5 seconds +// +#define ATAPILONGTIMEOUT 5000 + +// +// ATA Commands Code +// +#define ATA_INITIALIZE_DEVICE 0x91 + +// +// Class 1 +// +#define IDENTIFY_DRIVE_CMD 0xec +#define READ_BUFFER_CMD 0xe4 +#define READ_SECTORS_CMD 0x20 +#define READ_SECTORS_WITH_RETRY_CMD 0x21 +#define READ_LONG_CMD 0x22 +#define READ_LONG_WITH_RETRY_CMD 0x23 +// +// Class 1 - Atapi6 enhanced commands +// +#define READ_SECTORS_EXT_CMD 0x24 + +// +// Class 2 +// +#define FORMAT_TRACK_CMD 0x50 +#define WRITE_BUFFER_CMD 0xe8 +#define WRITE_SECTORS_CMD 0x30 +#define WRITE_SECTORS_WITH_RETRY_CMD 0x31 +#define WRITE_LONG_CMD 0x32 +#define WRITE_LONG_WITH_RETRY_CMD 0x33 +#define WRITE_VERIFY_CMD 0x3c +// +// Class 2 - Atapi6 enhanced commands +// +#define WRITE_SECTORS_EXT_CMD 0x34 + +// +// Class 3 +// +#define ACK_MEDIA_CHANGE_CMD 0xdb +#define BOOT_POST_BOOT_CMD 0xdc +#define BOOT_PRE_BOOT_CMD 0xdd +#define CHECK_POWER_MODE_CMD 0x98 +#define CHECK_POWER_MODE_CMD_ALIAS 0xe5 +#define DOOR_LOCK_CMD 0xde +#define DOOR_UNLOCK_CMD 0xdf +#define EXEC_DRIVE_DIAG_CMD 0x90 +#define IDLE_CMD_ALIAS 0x97 +#define IDLE_CMD 0xe3 +#define IDLE_IMMEDIATE_CMD 0x95 +#define IDLE_IMMEDIATE_CMD_ALIAS 0xe1 +#define INIT_DRIVE_PARAM_CMD 0x91 +#define RECALIBRATE_CMD 0x10 /* aliased to 1x */ +#define READ_DRIVE_STATE_CMD 0xe9 +#define SET_MULTIPLE_MODE_CMD 0xC6 +#define READ_DRIVE_STATE_CMD 0xe9 +#define READ_VERIFY_CMD 0x40 +#define READ_VERIFY_WITH_RETRY_CMD 0x41 +#define SEEK_CMD 0x70 /* aliased to 7x */ +#define SET_FEATURES_CMD 0xef +#define STANDBY_CMD 0x96 +#define STANDBY_CMD_ALIAS 0xe2 +#define STANDBY_IMMEDIATE_CMD 0x94 +#define STANDBY_IMMEDIATE_CMD_ALIAS 0xe0 + +// +// Class 4 +// +#define READ_DMA_CMD 0xc8 +#define READ_DMA_WITH_RETRY_CMD 0xc9 +#define READ_DMA_EXT_CMD 0x25 +#define WRITE_DMA_CMD 0xca +#define WRITE_DMA_WITH_RETRY_CMD 0xcb +#define WRITE_DMA_EXT_CMD 0x35 + +// +// Class 5 +// +#define READ_MULTIPLE_CMD 0xc4 +#define REST_CMD 0xe7 +#define RESTORE_DRIVE_STATE_CMD 0xea +#define SET_SLEEP_MODE_CMD 0x99 +#define SET_SLEEP_MODE_CMD_ALIAS 0xe6 +#define WRITE_MULTIPLE_CMD 0xc5 +#define WRITE_SAME_CMD 0xe9 + +// +// Class 6 - Host protected area access feature set +// +#define READ_NATIVE_MAX_ADDRESS_CMD 0xf8 +#define SET_MAX_ADDRESS_CMD 0xf9 + +// +// Class 6 - ATA/ATAPI-6 enhanced commands +// +#define READ_NATIVE_MAX_ADDRESS_EXT_CMD 0x27 +#define SET_MAX_ADDRESS_CMD_EXT 0x37 + +// +// Class 6 - SET_MAX related sub command (in feature register) +// +#define PARTIES_SET_MAX_ADDRESS_SUB_CMD 0x00 +#define PARTIES_SET_PASSWORD_SUB_CMD 0x01 +#define PARTIES_LOCK_SUB_CMD 0x02 +#define PARTIES_UNLOCK_SUB_CMD 0x03 +#define PARTIES_FREEZE_SUB_CMD 0x04 + +// +// S.M.A.R.T +// +#define ATA_SMART_CMD 0xb0 +#define ATA_CONSTANT_C2 0xc2 +#define ATA_CONSTANT_4F 0x4f +#define ATA_SMART_ENABLE_OPERATION 0xd8 +#define ATA_SMART_RETURN_STATUS 0xda + +// +// Error codes for Exec Drive Diag +// +#define DRIV_DIAG_NO_ERROR (0x01) +#define DRIV_DIAG_FORMATTER_ERROR (0x02) +#define DRIV_DIAG_DATA_BUFFER_ERROR (0x03) +#define DRIV_DIAG_ECC_CKT_ERRROR (0x04) +#define DRIV_DIAG_UP_ERROR (0x05) +#define DRIV_DIAG_SLAVE_DRV_ERROR (0x80) /* aliased to 0x8x */ + +// +// Codes for Format Track +// +#define FORMAT_GOOD_SECTOR (0x00) +#define FORMAT_SUSPEND_ALLOC (0x01) +#define FORMAT_REALLOC_SECTOR (0x02) +#define FORMAT_MARK_SECTOR_DEFECTIVE (0x03) + +// +// IDE_IDENTIFY bits +// config bits : +// +#define ID_CONFIG_RESERVED0 bit0 +#define ID_CONFIG_HARD_SECTORED_DRIVE bit1 +#define ID_CONFIG_SOFT_SECTORED_DRIVE bit2 +#define ID_CONFIG_NON_MFM bit3 +#define ID_CONFIG_15uS_HEAD_SWITCHING bit4 +#define ID_CONFIG_SPINDLE_MOTOR_CONTROL bit5 +#define ID_CONFIG_HARD_DRIVE bit6 +#define ID_CONFIG_CHANGEABLE_MEDIUM bit7 +#define ID_CONFIG_DATA_RATE_TO_5MHZ bit8 +#define ID_CONFIG_DATA_RATE_5_TO_10MHZ bit9 +#define ID_CONFIG_DATA_RATE_ABOVE_10MHZ bit10 +#define ID_CONFIG_MOTOR_SPEED_TOLERANCE_ABOVE_0_5_PERC bit11 +#define ID_CONFIG_DATA_CLK_OFFSET_AVAIL bit12 +#define ID_CONFIG_TRACK_OFFSET_AVAIL bit13 +#define ID_CONFIG_SPEED_TOLERANCE_GAP_NECESSARY bit14 +#define ID_CONFIG_RESERVED1 bit15 + +#define ID_DOUBLE_WORD_IO_POSSIBLE bit01 +#define ID_LBA_SUPPORTED bit9 +#define ID_DMA_SUPPORTED bit8 + +#define SET_FEATURE_ENABLE_8BIT_TRANSFER (0x01) +#define SET_FEATURE_ENABLE_WRITE_CACHE (0x02) +#define SET_FEATURE_TRANSFER_MODE (0x03) +#define SET_FEATURE_WRITE_SAME_WRITE_SPECIFIC_AREA (0x22) +#define SET_FEATURE_DISABLE_RETRIES (0x33) +// +// for Read & Write Longs +// +#define SET_FEATURE_VENDOR_SPEC_ECC_LENGTH (0x44) +#define SET_FEATURE_PLACE_NO_OF_CACHE_SEGMENTS_IN_SECTOR_NO_REG (0x54) +#define SET_FEATURE_DISABLE_READ_AHEAD (0x55) +#define SET_FEATURE_MAINTAIN_PARAM_AFTER_RESET (0x66) +#define SET_FEATURE_DISABLE_ECC (0x77) +#define SET_FEATURE_DISABLE_8BIT_TRANSFER (0x81) +#define SET_FEATURE_DISABLE_WRITE_CACHE (0x82) +#define SET_FEATURE_ENABLE_ECC (0x88) +#define SET_FEATURE_ENABLE_RETRIES (0x99) +#define SET_FEATURE_ENABLE_READ_AHEAD (0xaa) +#define SET_FEATURE_SET_SECTOR_CNT_REG_AS_NO_OF_READ_AHEAD_SECTORS (0xab) +#define SET_FEATURE_ALLOW_REST_MODE (0xac) +// +// for Read & Write Longs +// +#define SET_FEATURE_4BYTE_ECC (0xbb) +#define SET_FEATURE_DEFALUT_FEATURES_ON_SOFTWARE_RESET (0xcc) +#define SET_FEATURE_WRITE_SAME_TO_WRITE_ENTIRE_MEDIUM (0xdd) + +#define BLOCK_TRANSFER_MODE (0x00) +#define SINGLE_WORD_DMA_TRANSFER_MODE (0x10) +#define MULTI_WORD_DMA_TRANSFER_MODE (0x20) +#define TRANSFER_MODE_MASK (0x07) // 3 LSBs + +// +// Drive 0 - Head 0 +// +#define DEFAULT_DRIVE (0x00) +#define DEFAULT_CMD (0xa0) +// +// default content of device control register, disable INT +// +#define DEFAULT_CTL (0x0a) +#define DEFAULT_IDE_BM_IO_BASE_ADR (0xffa0) + +// +// ATAPI6 related data structure definition +// + +// +// The maximum sectors count in 28 bit addressing mode +// +#define MAX_28BIT_ADDRESSING_CAPACITY 0xfffffff + +// +// Move the IDENTIFY section to DXE\Protocol\IdeControllerInit +// + +// +// ATAPI Command +// +#define ATAPI_SOFT_RESET_CMD 0x08 +#define ATAPI_PACKET_CMD 0xA0 +#define PACKET_CMD 0xA0 +#define ATAPI_IDENTIFY_DEVICE_CMD 0xA1 +#define ATAPI_SERVICE_CMD 0xA2 + +// +// ATAPI Packet Command +// +#pragma pack(1) + +typedef struct { + UINT8 opcode; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} TEST_UNIT_READY_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 page_code; + UINT8 reserved_3; + UINT8 allocation_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} INQUIRY_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 allocation_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} REQUEST_SENSE_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 page_code : 4; + UINT8 page_control : 4; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 parameter_list_length_hi; + UINT8 parameter_list_length_lo; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} MODE_SENSE_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 5; + UINT8 lun : 3; + UINT8 Lba0; + UINT8 Lba1; + UINT8 Lba2; + UINT8 Lba3; + UINT8 reserved_6; + UINT8 TranLen0; + UINT8 TranLen1; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} READ10_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 allocation_length_hi; + UINT8 allocation_length_lo; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} READ_FORMAT_CAP_CMD; + +typedef union { + UINT16 Data16[6]; + TEST_UNIT_READY_CMD TestUnitReady; + READ10_CMD Read10; + REQUEST_SENSE_CMD RequestSence; + INQUIRY_CMD Inquiry; + MODE_SENSE_CMD ModeSense; + READ_FORMAT_CAP_CMD ReadFormatCapacity; +} ATAPI_PACKET_COMMAND; + +typedef struct { + UINT32 RegionBaseAddr; + UINT16 ByteCount; + UINT16 EndOfTable; +} IDE_DMA_PRD; + +#define MAX_DMA_EXT_COMMAND_SECTORS 0x10000 +#define MAX_DMA_COMMAND_SECTORS 0x100 + +#pragma pack() + +// +// Packet Command Code +// +#define TEST_UNIT_READY 0x00 +#define REZERO 0x01 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define REASSIGN_BLOCKS 0x07 +#define INQUIRY 0x12 +#define START_STOP_UNIT 0x1B +#define PREVENT_ALLOW_MEDIA_REMOVAL 0x1E +#define READ_FORMAT_CAPACITY 0x23 +#define OLD_FORMAT_UNIT 0x24 +#define READ_CAPACITY 0x25 +#define READ_10 0x28 +#define WRITE_10 0x2A +#define SEEK 0x2B +#define SEND_DIAGNOSTICS 0x3D +#define WRITE_VERIFY 0x2E +#define VERIFY 0x2F +#define READ_DEFECT_DATA 0x37 +#define WRITE_BUFFER 0x38 +#define READ_BUFFER 0x3C +#define READ_LONG 0x3E +#define WRITE_LONG 0x3F +#define MODE_SELECT 0x55 +#define MODE_SENSE 0x5A +#define READ_12 0xA8 +#define WRITE_12 0xAA +#define MAX_ATAPI_BYTE_COUNT (0xfffe) + +// +// Sense Key +// +#define REQUEST_SENSE_ERROR (0x70) +#define SK_NO_SENSE (0x0) +#define SK_RECOVERY_ERROR (0x1) +#define SK_NOT_READY (0x2) +#define SK_MEDIUM_ERROR (0x3) +#define SK_HARDWARE_ERROR (0x4) +#define SK_ILLEGAL_REQUEST (0x5) +#define SK_UNIT_ATTENTION (0x6) +#define SK_DATA_PROTECT (0x7) +#define SK_BLANK_CHECK (0x8) +#define SK_VENDOR_SPECIFIC (0x9) +#define SK_RESERVED_A (0xA) +#define SK_ABORT (0xB) +#define SK_RESERVED_C (0xC) +#define SK_OVERFLOW (0xD) +#define SK_MISCOMPARE (0xE) +#define SK_RESERVED_F (0xF) + +// +// Additional Sense Codes +// +#define ASC_NOT_READY (0x04) +#define ASC_MEDIA_ERR1 (0x10) +#define ASC_MEDIA_ERR2 (0x11) +#define ASC_MEDIA_ERR3 (0x14) +#define ASC_MEDIA_ERR4 (0x30) +#define ASC_MEDIA_UPSIDE_DOWN (0x06) +#define ASC_INVALID_CMD (0x20) +#define ASC_LBA_OUT_OF_RANGE (0x21) +#define ASC_INVALID_FIELD (0x24) +#define ASC_WRITE_PROTECTED (0x27) +#define ASC_MEDIA_CHANGE (0x28) +#define ASC_RESET (0x29) /* Power On Reset or Bus Reset occurred */ +#define ASC_ILLEGAL_FIELD (0x26) +#define ASC_NO_MEDIA (0x3A) +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK (0x64) + +// +// Additional Sense Code Qualifier +// +#define ASCQ_IN_PROGRESS (0x01) + +#define SETFEATURE TRUE +#define CLEARFEATURE FALSE + +// +// ATAPI Data structure +// +#pragma pack(1) + +typedef struct { + UINT8 peripheral_type; + UINT8 RMB; + UINT8 version; + UINT8 response_data_format; + UINT8 addnl_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 vendor_info[8]; + UINT8 product_id[12]; + UINT8 eeprom_product_code[4]; + UINT8 firmware_rev_level[4]; + UINT8 firmware_sub_rev_level[1]; + UINT8 reserved_37; + UINT8 reserved_38; + UINT8 reserved_39; + UINT8 max_capacity_hi; + UINT8 max_capacity_mid; + UINT8 max_capacity_lo; + UINT8 reserved_43_95[95 - 43 + 1]; +} INQUIRY_DATA; + +typedef struct { + UINT8 peripheral_type; + UINT8 RMB; + UINT8 version; + UINT8 response_data_format; + UINT8 addnl_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 vendor_info[8]; + UINT8 product_id[16]; + UINT8 product_revision_level[4]; + UINT8 vendor_specific[20]; + UINT8 reserved_56_95[40]; +} CDROM_INQUIRY_DATA; + +typedef struct { + UINT8 error_code : 7; + UINT8 valid : 1; + UINT8 reserved_1; + UINT8 sense_key : 4; + UINT8 reserved_21 : 1; + UINT8 ILI : 1; + UINT8 reserved_22 : 2; + UINT8 vendor_specific_3; + UINT8 vendor_specific_4; + UINT8 vendor_specific_5; + UINT8 vendor_specific_6; + UINT8 addnl_sense_length; // n - 7 + UINT8 vendor_specific_8; + UINT8 vendor_specific_9; + UINT8 vendor_specific_10; + UINT8 vendor_specific_11; + UINT8 addnl_sense_code; // mandatory + UINT8 addnl_sense_code_qualifier; // mandatory + UINT8 field_replaceable_unit_code; // optional + UINT8 reserved_15; + UINT8 reserved_16; + UINT8 reserved_17; + // + // Followed by additional sense bytes : FIXME + // +} REQUEST_SENSE_DATA; + +typedef struct { + UINT8 LastLba3; + UINT8 LastLba2; + UINT8 LastLba1; + UINT8 LastLba0; + UINT8 BlockSize3; + UINT8 BlockSize2; + UINT8 BlockSize1; + UINT8 BlockSize0; +} READ_CAPACITY_DATA; + +typedef struct { + UINT8 reserved_0; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 Capacity_Length; + UINT8 LastLba3; + UINT8 LastLba2; + UINT8 LastLba1; + UINT8 LastLba0; + UINT8 DesCode : 2; + UINT8 reserved_9 : 6; + UINT8 BlockSize2; + UINT8 BlockSize1; + UINT8 BlockSize0; +} READ_FORMAT_CAPACITY_DATA; + +#pragma pack() + +// +// PIO mode definition +// +typedef enum { + ATA_PIO_MODE_BELOW_2, + ATA_PIO_MODE_2, + ATA_PIO_MODE_3, + ATA_PIO_MODE_4 +} ATA_PIO_MODE; + +// +// Multi word DMA definition +// +typedef enum { + ATA_MDMA_MODE_0, + ATA_MDMA_MODE_1, + ATA_MDMA_MODE_2 +} ATA_MDMA_MODE; + +// +// UDMA mode definition +// +typedef enum { + ATA_UDMA_MODE_0, + ATA_UDMA_MODE_1, + ATA_UDMA_MODE_2, + ATA_UDMA_MODE_3, + ATA_UDMA_MODE_4, + ATA_UDMA_MODE_5 +} ATA_UDMA_MODE; + +#define ATA_MODE_CATEGORY_DEFAULT_PIO 0x00 +#define ATA_MODE_CATEGORY_FLOW_PIO 0x01 +#define ATA_MODE_CATEGORY_MDMA 0x04 +#define ATA_MODE_CATEGORY_UDMA 0x08 + +#pragma pack(1) + +typedef struct { + UINT8 ModeNumber : 3; + UINT8 ModeCategory : 5; +} ATA_TRANSFER_MODE; + +typedef struct { + UINT8 Sector; + UINT8 Heads; + UINT8 MultipleSector; +} ATA_DRIVE_PARMS; + +#pragma pack() +// +// IORDY Sample Point field value +// +#define ISP_5_CLK 0 +#define ISP_4_CLK 1 +#define ISP_3_CLK 2 +#define ISP_2_CLK 3 + +// +// Recovery Time field value +// +#define RECVY_4_CLK 0 +#define RECVY_3_CLK 1 +#define RECVY_2_CLK 2 +#define RECVY_1_CLK 3 + +// +// Slave IDE Timing Register Enable +// +#define SITRE bit14 + +// +// DMA Timing Enable Only Select 1 +// +#define DTE1 bit7 + +// +// Pre-fetch and Posting Enable Select 1 +// +#define PPE1 bit6 + +// +// IORDY Sample Point Enable Select 1 +// +#define IE1 bit5 + +// +// Fast Timing Bank Drive Select 1 +// +#define TIME1 bit4 + +// +// DMA Timing Enable Only Select 0 +// +#define DTE0 bit3 + +// +// Pre-fetch and Posting Enable Select 0 +// +#define PPE0 bit2 + +// +// IOREY Sample Point Enable Select 0 +// +#define IE0 bit1 + +// +// Fast Timing Bank Drive Select 0 +// +#define TIME0 bit0 + +#endif -- cgit v1.2.3