summaryrefslogtreecommitdiff
path: root/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe
diff options
context:
space:
mode:
authorqhuang8 <qhuang8@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-18 14:24:10 +0000
committerqhuang8 <qhuang8@6f19259b-4bc3-4df7-8a09-765794883524>2007-07-18 14:24:10 +0000
commit69b26c155a943267c38b0d770e8a83dfc82ef189 (patch)
treef5107c55282f79f11493b2b9b5caef0eb2f0456e /IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe
parenta0741b93e128587b8f2b033f0efcbd5b900dc904 (diff)
downloadedk2-platforms-69b26c155a943267c38b0d770e8a83dfc82ef189.tar.xz
Adjust directory structures.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3322 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe')
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.c210
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.h80
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverConfiguration.c322
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverDiagnostics.c200
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdebusDxe.inf123
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdebusDxe.msa114
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ata.c2624
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/atapi.c2140
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ide.c1824
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ide.h1328
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idebus.c1413
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idebus.h419
-rw-r--r--IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idedata.h311
13 files changed, 11108 insertions, 0 deletions
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.c
new file mode 100644
index 0000000000..12673c9c92
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.c
@@ -0,0 +1,210 @@
+/** @file
+ 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.
+
+**/
+
+#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 }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param 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.
+ @param 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.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString (
+ Language,
+ gIDEBusComponentName.SupportedLanguages,
+ mIDEBusDriverNameTable,
+ DriverName
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param 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.
+ @param 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.
+ @param 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.
+ @param 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.
+
+ @retval 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.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+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
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ &gEfiIdeControllerInitProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ChildHandle == NULL) {
+ return LookupUnicodeString (
+ Language,
+ gIDEBusComponentName.SupportedLanguages,
+ mIDEBusControllerNameTable,
+ ControllerName
+ );
+ }
+
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 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
+ );
+}
+
+/**
+ Add the component name for the IDE/ATAPI device
+
+ @param IdeBlkIoDevicePtr A pointer to the IDE_BLK_IO_DEV instance.
+
+**/
+VOID
+AddName (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr
+ )
+{
+ 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/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.h b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.h
new file mode 100644
index 0000000000..e6bf11f209
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.h
@@ -0,0 +1,80 @@
+/** @file
+ 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.
+
+**/
+
+#ifndef _IDE_BUS_COMPONENT_NAME_H
+#define _IDE_BUS_COMPONENT_NAME_H
+
+#define ADD_NAME(x) AddName ((x));
+
+extern EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName;
+
+
+//
+// EFI Component Name Functions
+//
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Language TODO: add argument description
+ @param DriverName TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param ControllerHandle TODO: add argument description
+ @param ChildHandle TODO: add argument description
+ @param Language TODO: add argument description
+ @param ControllerName TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeBlkIoDevicePtr TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+AddName (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr
+ )
+;
+
+#endif
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverConfiguration.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverConfiguration.c
new file mode 100644
index 0000000000..47288ac484
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverConfiguration.c
@@ -0,0 +1,322 @@
+/** @file
+ 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.
+
+**/
+
+
+#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 Protocol
+//
+EFI_DRIVER_CONFIGURATION_PROTOCOL gIDEBusDriverConfiguration = {
+ IDEBusDriverConfigurationSetOptions,
+ IDEBusDriverConfigurationOptionsValid,
+ IDEBusDriverConfigurationForceDefaults,
+ "eng"
+};
+
+/**
+ TODO: Add function description
+
+ @retval EFI_ABORTED TODO: Add description for return value
+ @retval EFI_SUCCESS TODO: Add description for return value
+ @retval EFI_NOT_FOUND TODO: Add description for return value
+
+**/
+STATIC
+EFI_STATUS
+GetResponse (
+ VOID
+ )
+{
+ 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;
+ }
+
+ }
+ }
+}
+
+/**
+ Allows the user to set controller specific options for a controller that a
+ driver is currently managing.
+
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL
+ instance.
+ @param ControllerHandle The handle of the controller to set options on.
+ @param 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.
+ @param 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.
+ @param 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.
+
+ @retval EFI_SUCCESS The driver specified by This successfully set the
+ configuration options for the controller specified
+ by ControllerHandle..
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
+ valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ActionRequired is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ setting configuration options for the controller
+ specified by ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempt to set the
+ configuration options for the controller specified
+ by ControllerHandle and ChildHandle.
+ @retval EFI_OUT_RESOURCES There are not enough resources available to set the
+ configuration options for the controller specified
+ by ControllerHandle and ChildHandle.
+
+**/
+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 Status;
+ UINT8 Value;
+ UINT8 NewValue;
+ UINTN DataSize;
+ UINTN Index;
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *ActionRequired = EfiDriverConfigurationActionNone;
+
+ DataSize = sizeof (Value);
+ Status = gRT->GetVariable (
+ L"Configuration",
+ &gEfiCallerIdGuid,
+ NULL,
+ &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) (NewValue | (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;
+}
+
+/**
+ Tests to see if a controller's current configuration options are valid.
+
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL
+ instance.
+ @param ControllerHandle The handle of the controller to test if it's current
+ configuration options are valid.
+ @param 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.
+
+ @retval 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.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval 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
+IDEBusDriverConfigurationOptionsValid (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Value;
+ UINTN DataSize;
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DataSize = sizeof (Value);
+ Status = gRT->GetVariable (
+ L"Configuration",
+ &gEfiCallerIdGuid,
+ NULL,
+ &DataSize,
+ &Value
+ );
+ if (EFI_ERROR (Status) || Value > 0x0f) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Forces a driver to set the default configuration options for a controller.
+
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL
+ instance.
+ @param ControllerHandle The handle of the controller to force default
+ configuration options on.
+ @param 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.
+ @param 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.
+ @param ActionRequired A pointer to the action that the calling agent
+ is required to perform when this function returns.
+
+ @retval EFI_SUCCESS The driver specified by This successfully forced
+ the default configuration options on the
+ controller specified by ControllerHandle and
+ ChildHandle.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a
+ valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ActionRequired is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ forcing the default configuration options on
+ the controller specified by ControllerHandle
+ and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the configuration type specified by DefaultType.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempt to force
+ the default configuration options on the controller
+ specified by ControllerHandle and ChildHandle.
+ @retval EFI_OUT_RESOURCES There are not enough resources available to force
+ the default configuration options on the controller
+ specified by ControllerHandle and ChildHandle.
+
+**/
+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
+ )
+{
+ 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/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverDiagnostics.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverDiagnostics.c
new file mode 100644
index 0000000000..8aa6d05712
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverDiagnostics.c
@@ -0,0 +1,200 @@
+/** @file
+ 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.
+
+**/
+
+
+#include "idebus.h"
+
+#define IDE_BUS_DIAGNOSTIC_ERROR L"PCI IDE/ATAPI Driver Diagnostics Failed"
+
+//
+// EFI Driver Diagnostics Protocol
+//
+EFI_DRIVER_DIAGNOSTICS_PROTOCOL gIDEBusDriverDiagnostics = {
+ IDEBusDriverDiagnosticsRunDiagnostics,
+ "eng"
+};
+
+/**
+ Runs diagnostics on a controller.
+
+ @param This A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOL
+ instance.
+ @param ControllerHandle The handle of the controller to run diagnostics on.
+ @param 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.
+ @param DiagnosticType Indicates type of diagnostics to perform on the
+ controller specified by ControllerHandle and ChildHandle.
+ See "Related Definitions" for the list of supported
+ types.
+ @param 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.
+ @param ErrorType A GUID that defines the format of the data returned in
+ Buffer.
+ @param BufferSize The size, in bytes, of the data returned in Buffer.
+ @param 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().
+
+ @retval EFI_SUCCESS The controller specified by ControllerHandle and
+ ChildHandle passed the diagnostic.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ErrorType is NULL.
+ @retval EFI_INVALID_PARAMETER BufferType is NULL.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ running diagnostics for the controller specified
+ by ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ type of diagnostic specified by DiagnosticType.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to complete
+ the diagnostics.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to return
+ the status information in ErrorType, BufferSize,
+ and Buffer.
+ @retval EFI_DEVICE_ERROR The controller specified by ControllerHandle and
+ ChildHandle did not pass the diagnostic.
+
+**/
+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_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;
+ }
+
+ CopyMem (*Buffer, IDE_BUS_DIAGNOSTIC_ERROR, *BufferSize);
+
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ gBS->FreePool (BlockBuffer);
+
+ return Status;
+}
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdebusDxe.inf b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdebusDxe.inf
new file mode 100644
index 0000000000..5514fa3476
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdebusDxe.inf
@@ -0,0 +1,123 @@
+#/** @file
+# Component description file for PS2 keyboard module.
+#
+# IDE bus driver. This driver will enumerate IDE device and export the blockIo
+# protocol for every device.
+# Copyright (c) 2006 - 2007, 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.
+#
+#
+#**/
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IdeBusDxe
+ FILE_GUID = 69FD8E47-A161-4550-B01A-5594CEB2B2B2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = InitializeIdeBus
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gIDEBusDriverBinding
+# COMPONENT_NAME = gIDEBusComponentName
+# Variable Guid C Name: gConfigurationGuid Variable Name: L"Configuration"
+#
+#
+
+################################################################################
+#
+# Sources Section - list of files that are required for the build to succeed.
+#
+################################################################################
+
+[Sources.common]
+ DriverDiagnostics.c
+ DriverConfiguration.c
+ ComponentName.h
+ ComponentName.c
+ atapi.c
+ ata.c
+ ide.c
+ idebus.c
+ idedata.h
+ ide.h
+ idebus.h
+
+
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+# this module.
+#
+################################################################################
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+
+
+################################################################################
+#
+# Library Class Section - list of Library Classes that are required for
+# this module.
+#
+################################################################################
+
+[LibraryClasses]
+ DevicePathLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ PerformanceLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+################################################################################
+#
+# Guid C Name Section - list of Guids that this module uses or produces.
+#
+################################################################################
+
+[Guids]
+ gEfiDiskInfoIdeInterfaceGuid # SOMETIMES_CONSUMED
+
+
+################################################################################
+#
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names
+# that this module uses or produces.
+#
+################################################################################
+
+[Protocols]
+ gEfiDiskInfoProtocolGuid # PROTOCOL BY_START
+ gEfiBlockIoProtocolGuid # PROTOCOL BY_START
+ gEfiIdeControllerInitProtocolGuid # PROTOCOL TO_START
+ gEfiPciIoProtocolGuid # PROTOCOL TO_START
+ gEfiDevicePathProtocolGuid # PROTOCOL TO_START
+
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdebusDxe.msa b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdebusDxe.msa
new file mode 100644
index 0000000000..7d8e9ad259
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdebusDxe.msa
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <MsaHeader>
+ <ModuleName>IdeBus</ModuleName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <GuidValue>69FD8E47-A161-4550-B01A-5594CEB2B2B2</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Component description file for PS2 keyboard module.</Abstract>
+ <Description>IDE bus driver. This driver will enumerate IDE device and export the blockIo
+ protocol for every device.</Description>
+ <Copyright>Copyright (c) 2006 - 2007, Intel Corporation</Copyright>
+ <License>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.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>IdeBus</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiDriverEntryPoint</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>ReportStatusCodeLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>MemoryAllocationLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PerformanceLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiBootServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>UefiRuntimeServicesTableLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DevicePathLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>idebus.h</Filename>
+ <Filename>ide.h</Filename>
+ <Filename>idedata.h</Filename>
+ <Filename>idebus.c</Filename>
+ <Filename>ide.c</Filename>
+ <Filename>ata.c</Filename>
+ <Filename>atapi.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>ComponentName.h</Filename>
+ <Filename>DriverConfiguration.c</Filename>
+ <Filename>DriverDiagnostics.c</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="1E73767F-8F52-4603-AEB4-F29B510B6766"/>
+ <Package PackageGuid="2759ded5-bb57-4b06-af4f-c398fa552719"/>
+ <Package PackageGuid="BA0D78D6-2CAF-414b-BD4D-B6762A894288"/>
+ </PackageDependencies>
+ <Protocols>
+ <Protocol Usage="TO_START">
+ <ProtocolCName>gEfiDevicePathProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="TO_START">
+ <ProtocolCName>gEfiPciIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="TO_START">
+ <ProtocolCName>gEfiIdeControllerInitProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="BY_START">
+ <ProtocolCName>gEfiBlockIoProtocolGuid</ProtocolCName>
+ </Protocol>
+ <Protocol Usage="BY_START">
+ <ProtocolCName>gEfiDiskInfoProtocolGuid</ProtocolCName>
+ </Protocol>
+ </Protocols>
+ <Variables>
+ <Variable Usage="ALWAYS_CONSUMED">
+ <VariableName>0x0043 0x006F 0x006E 0x0066 0x0069 0x0067 0x0075 0x0072 0x0061 0x0074 0x0069 0x006F 0x006E</VariableName>
+ <GuidC_Name>gConfigurationGuid</GuidC_Name>
+ </Variable>
+ </Variables>
+ <Guids>
+ <GuidCNames Usage="SOMETIMES_CONSUMED">
+ <GuidCName>gEfiDiskInfoIdeInterfaceGuid</GuidCName>
+ </GuidCNames>
+ </Guids>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ <Extern>
+ <DriverBinding>gIDEBusDriverBinding</DriverBinding>
+ <ComponentName>gIDEBusComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ata.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ata.c
new file mode 100644
index 0000000000..ec546bb6b2
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ata.c
@@ -0,0 +1,2624 @@
+/** @file
+ Copyright (c) 2006 - 2007 Intel Corporation. <BR>
+ 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.
+
+ @par Revision Reference:
+ 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"
+
+/**
+ Sends out an ATA Identify Command to the specified device.
+
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure,used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS Identify ATA device successfully.
+
+ @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or
+ device is not ATA device.
+
+ @note
+ parameter IdeDev will be updated in this function.
+
+**/
+EFI_STATUS
+ATAIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ 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 = (UINT8) ((IdeDev->Device) << 4);
+ Status = AtaPioDataIn (
+ IdeDev,
+ (VOID *) AtaIdentifyPointer,
+ sizeof (EFI_IDENTIFY_DATA),
+ ATA_CMD_IDENTIFY_DRIVE,
+ 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;
+}
+
+
+/**
+ This function is called by ATAIdentify() to identity whether this disk
+ supports ATA/ATAPI6 48bit addressing, ie support >120G capacity
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS The disk specified by IdeDev is a Atapi6 supported one
+ and 48-bit addressing must be used
+
+ @retval EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but
+ the capacity is below 120G, 48bit addressing is not
+ needed
+
+ @note
+ This function must be called after DEVICE_IDENTITY command has been
+ successfully returned
+
+**/
+EFI_STATUS
+AtaAtapi6Identify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ 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;
+}
+
+/**
+ This function is called by ATAIdentify() or ATAPIIdentify()
+ to print device's module name.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+**/
+VOID
+PrintAtaModuleName (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ if (IdeDev->pIdData == NULL) {
+ return ;
+ }
+
+ SwapStringChars (IdeDev->ModelName, IdeDev->pIdData->AtaData.ModelName, 40);
+ IdeDev->ModelName[40] = 0x00;
+}
+
+/**
+ This function is used to send out ATA commands conforms to the
+ PIO Data In Protocol.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *Buffer
+ buffer contained data transferred from device to host.
+
+ @param[in] ByteCount
+ data size in byte unit of the buffer.
+
+ @param[in] AtaCommand
+ value of the Command Register
+
+ @param[in] Head
+ value of the Head/Device Register
+
+ @param[in] SectorCount
+ value of the Sector Count Register
+
+ @param[in] SectorNumber
+ value of the Sector Number Register
+
+ @param[in] CylinderLsb
+ value of the low byte of the Cylinder Register
+
+ @param[in] CylinderMsb
+ value of the high byte of the Cylinder Register
+
+ @retval EFI_SUCCESS send out the ATA command and device send required
+ data successfully.
+
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+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
+ )
+{
+ 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 == ATA_CMD_SET_FEATURES) {
+ 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);
+}
+
+/**
+ This function is used to send out ATA commands conforms to the
+ PIO Data Out Protocol.
+
+ @param *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param *Buffer buffer contained data transferred from host to device.
+ @param ByteCount data size in byte unit of the buffer.
+ @param AtaCommand value of the Command Register
+ @param Head value of the Head/Device Register
+ @param SectorCount value of the Sector Count Register
+ @param SectorNumber value of the Sector Number Register
+ @param CylinderLsb value of the low byte of the Cylinder Register
+ @param CylinderMsb value of the high byte of the Cylinder Register
+
+ @retval EFI_SUCCESS send out the ATA command and device received required
+ data successfully.
+
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+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
+ )
+{
+ 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);
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS No err information in the Status Register.
+ @retval EFI_DEVICE_ERROR Any err information in the Status Register.
+
+**/
+EFI_STATUS
+CheckErrorStatus (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ UINT8 StatusRegister;
+ UINT8 ErrorRegister;
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ DEBUG_CODE_BEGIN ();
+
+ if (StatusRegister & ATA_STSREG_DWF) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Write Fault\n",
+ StatusRegister)
+ );
+ }
+
+ if (StatusRegister & ATA_STSREG_CORR) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Corrected Data\n",
+ StatusRegister)
+ );
+ }
+
+ if (StatusRegister & ATA_STSREG_ERR) {
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+
+ if (ErrorRegister & ATA_ERRREG_BBK) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
+ ErrorRegister)
+ );
+ }
+
+ if (ErrorRegister & ATA_ERRREG_UNC) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
+ ErrorRegister)
+ );
+ }
+
+ if (ErrorRegister & ATA_ERRREG_MC) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Media Change\n",
+ ErrorRegister)
+ );
+ }
+
+ if (ErrorRegister & ATA_ERRREG_ABRT) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Abort\n",
+ ErrorRegister)
+ );
+ }
+
+ if (ErrorRegister & ATA_ERRREG_TK0NF) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
+ ErrorRegister)
+ );
+ }
+
+ if (ErrorRegister & ATA_ERRREG_AMNF) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
+ ErrorRegister)
+ );
+ }
+ }
+
+ DEBUG_CODE_END ();
+
+ if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_DEVICE_ERROR;
+
+}
+
+/**
+ This function is called by the AtaBlkIoReadBlocks() to perform
+ reading from media in block unit.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *DataBuffer
+ A pointer to the destination buffer for the data.
+
+ @param[in] Lba
+ The starting logical block address to read from
+ on the device media.
+
+ @param[in] NumberOfBlocks
+ The number of transfer data blocks.
+
+ @return return status is fully dependent on the return status
+ of AtaPioDataIn() function.
+
+**/
+EFI_STATUS
+AtaReadSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ 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 = ATA_CMD_READ_SECTORS;
+
+
+ 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;
+}
+
+/**
+ This function is called by the AtaBlkIoWriteBlocks() to perform
+ writing onto media in block unit.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure,used
+ to record all the information of the IDE device.
+
+ @param[in] *BufferData
+ A pointer to the source buffer for the data.
+
+ @param[in] Lba
+ The starting logical block address to write onto
+ the device media.
+
+ @param[in] NumberOfBlocks
+ The number of transfer data blocks.
+
+ @return return status is fully dependent on the return status
+ of AtaPioDataOut() function.
+
+**/
+EFI_STATUS
+AtaWriteSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *BufferData,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ 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 = ATA_CMD_WRITE_SECTORS;
+
+ 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;
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS Soft reset completes successfully.
+ @retval EFI_DEVICE_ERROR Any step during the reset process is failed.
+
+ @note
+ The registers initial values after ATA soft reset are different
+ to the ATA device and ATAPI device.
+
+**/
+EFI_STATUS
+AtaSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+
+ UINT8 DeviceControl;
+
+ DeviceControl = 0;
+ //
+ // set SRST bit to initiate soft reset
+ //
+ DeviceControl |= ATA_CTLREG_SRST;
+
+ //
+ // disable Interrupt
+ //
+ DeviceControl |= BIT1;
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ //
+ // SRST should assert for at least 5 us, we use 10 us for
+ // better compatibility
+ //
+ gBS->Stall (10);
+
+ //
+ // Enable interrupt to support UDMA, and clear SRST bit
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ //
+ // Wait for at least 2 ms to check BSY status, we use 10 ms
+ // for better compatibility
+ //
+ gBS->Stall(10000);
+ //
+ // slave device needs at most 31s to clear BSY
+ //
+ if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the ATA implementation for ReadBlocks in the
+ Block I/O Protocol interface.
+
+ @param[in] *IdeBlkIoDevice
+ Indicates the calling context.
+
+ @param[in] MediaId
+ The media id that the read request is for.
+
+ @param[in] LBA
+ The starting logical block address to read from
+ on the device.
+
+ @param[in] BufferSize
+ The size of the Buffer in bytes. This must be a
+ multiple of the intrinsic block size of the device.
+
+ @param[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.
+
+ @retval EFI_SUCCESS Read Blocks successfully.
+ @retval EFI_DEVICE_ERROR Read Blocks failed.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.
+
+ @retval EFI_BAD_BUFFER_SIZE
+ The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+
+ @retval EFI_INVALID_PARAMETER
+ The read request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ @note
+ If Read Block error because of device error, this function will call
+ AtaSoftReset() function to reset device.
+
+**/
+EFI_STATUS
+AtaBlkIoReadBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ 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;
+ }
+
+ Status = EFI_SUCCESS;
+ if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+ //
+ // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism
+ //
+ if (IdeBlkIoDevice->UdmaMode.Valid) {
+ Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ } else {
+ Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ }
+ } else {
+ //
+ // For ATA-3 compatible device, use ATA-3 read block mechanism
+ //
+ if (IdeBlkIoDevice->UdmaMode.Valid) {
+ Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ } else {
+ Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AtaSoftReset (IdeBlkIoDevice);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ This function is the ATA implementation for WriteBlocks in the
+ Block I/O Protocol interface.
+
+ @param[in] *IdeBlkIoDevice
+ Indicates the calling context.
+
+ @param[in] MediaId
+ The media id that the write request is for.
+
+ @param[in] LBA
+ The starting logical block address to write onto
+ the device.
+
+ @param[in] BufferSize
+ The size of the Buffer in bytes. This must be a
+ multiple of the intrinsic block size of the device.
+
+ @param[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.
+
+ @retval EFI_SUCCESS Write Blocks successfully.
+ @retval EFI_DEVICE_ERROR Write Blocks failed.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.
+
+ @retval EFI_BAD_BUFFER_SIZE
+ The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+
+ @retval EFI_INVALID_PARAMETER
+ The write request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ @note
+ If Write Block error because of device error, this function will call
+ AtaSoftReset() function to reset device.
+
+**/
+EFI_STATUS
+AtaBlkIoWriteBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+
+ 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;
+ }
+
+ Status = EFI_SUCCESS;
+ if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+ //
+ // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism
+ //
+ if (IdeBlkIoDevice->UdmaMode.Valid) {
+ Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ } else {
+ Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ }
+ } else {
+ //
+ // For ATA-3 compatible device, use ATA-3 write block mechanism
+ //
+ if (IdeBlkIoDevice->UdmaMode.Valid) {
+ Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ } else {
+ Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AtaSoftReset (IdeBlkIoDevice);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *DataBuffer A pointer to the destination buffer for the data.
+ @param[in] StartLba The starting logical block address to read from
+ on the device media.
+ @param[in] NumberOfBlocks The number of transfer data blocks.
+
+ @return return status is fully dependent on the return status
+ of AtaPioDataInExt() function.
+
+**/
+EFI_STATUS
+AtaReadSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ 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 = ATA_CMD_READ_SECTORS_EXT;
+ 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;
+}
+
+/**
+ 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
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure,used
+ to record all the information of the IDE device.
+
+ @param[in] *DataBuffer
+ A pointer to the source buffer for the data.
+
+ @param[in] Lba
+ The starting logical block address to write onto
+ the device media.
+
+ @param[in] NumberOfBlocks
+ The number of transfer data blocks.
+
+ @return status is fully dependent on the return status
+ of AtaPioDataOutExt() function.
+
+**/
+EFI_STATUS
+AtaWriteSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ 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 = ATA_CMD_WRITE_SECTORS_EXT;
+ 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;
+}
+
+/**
+ 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:<BR>
+ 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!)
+
+ @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in,out] *Buffer buffer contained data transferred from device to host.
+ @param[in] ByteCount data size in byte unit of the buffer.
+ @param[in] AtaCommand value of the Command Register
+ @param[in] StartLba the start LBA of this transaction
+ @param[in] SectorCount the count of sectors to be transfered
+
+ @retval EFI_SUCCESS send out the ATA command and device send required
+ data successfully.
+
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+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
+ )
+{
+ 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 == ATA_CMD_SET_FEATURES) {
+ 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);
+}
+
+/**
+ 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:<BR>
+ 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!)
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *Buffer buffer contained data transferred from host to device.
+ @param[in] ByteCount data size in byte unit of the buffer.
+ @param[in] AtaCommand value of the Command Register
+ @param[in] StartLba the start LBA of this transaction
+ @param[in] SectorCount the count of sectors to be transfered
+
+ @retval EFI_SUCCESS send out the ATA command and device receive required
+ data successfully.
+
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+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
+ )
+{
+ 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 == ATA_CMD_SET_FEATURES) {
+ 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);
+}
+
+
+/**
+ Enable SMART of the disk if supported
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure,used
+ to record all the information of the IDE device.
+
+**/
+VOID
+AtaSMARTSupport (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ 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_CMD_SMART,
+ 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),
+ ATA_CMD_IDENTIFY_DRIVE,
+ 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_CMD_SMART,
+ 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 ;
+}
+
+/**
+ Send ATA Ext command into device with NON_DATA protocol
+
+ @param IdeDev Standard IDE device private data structure
+ @param AtaCommand The ATA command to be sent
+ @param Device The value in Device register
+ @param Feature The value in Feature register
+ @param SectorCount The value in SectorCount register
+ @param LbaAddress The LBA address in 48-bit mode
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_DEVICE_ERROR Error executing commands on this device
+
+**/
+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
+ )
+{
+ 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;
+}
+
+/**
+ Send ATA Ext command into device with NON_DATA protocol
+
+ @param IdeDev Standard IDE device private data structure
+ @param AtaCommand The ATA command to be sent
+ @param Device The value in Device register
+ @param Feature The value in Feature register
+ @param SectorCount The value in SectorCount register
+ @param LbaAddress The LBA address in 48-bit mode
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_DEVICE_ERROR Error executing commands on this device
+
+**/
+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
+ )
+{
+ 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 = (UINT8) (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;
+}
+
+/**
+ 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
+
+ @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *DataBuffer A pointer to the destination buffer for the data.
+
+ @param[in] StartLba The starting logical block address to read from
+ on the device media.
+
+ @param[in] NumberOfBlocks The number of transfer data blocks.
+
+ @return The device status of UDMA operation. If the operation is
+ successful, return EFI_SUCCESS.
+
+ 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
+**/
+EFI_STATUS
+AtaUdmaReadExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);
+}
+
+/**
+ 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
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *DataBuffer A pointer to the destination buffer for the data.
+ @param[in] StartLba The starting logical block address to read from
+ on the device media.
+ @param[in] NumberOfBlocks The number of transfer data blocks.
+
+ @return The device status of UDMA operation. If the operation is
+ successful, return EFI_SUCCESS.
+
+ 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
+**/
+EFI_STATUS
+AtaUdmaRead (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);
+}
+
+/**
+ 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
+
+ @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *DataBuffer A pointer to the source buffer for the data.
+
+ @param[in] StartLba The starting logical block address to write to
+ on the device media.
+
+ @param[in] NumberOfBlocks The number of transfer data blocks.
+
+ @return The device status of UDMA operation. If the operation is
+ successful, return EFI_SUCCESS.
+
+ 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
+**/
+EFI_STATUS
+AtaUdmaWriteExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);
+}
+
+/**
+ 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
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *DataBuffer
+ A pointer to the source buffer for the data.
+
+ @param[in] StartLba
+ The starting logical block address to write to
+ on the device media.
+
+ @param[in] NumberOfBlocks
+ The number of transfer data blocks.
+
+ @return The device status of UDMA operation. If the operation is
+ successful, return EFI_SUCCESS.
+
+ 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
+**/
+EFI_STATUS
+AtaUdmaWrite (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);
+}
+
+/**
+ Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *DataBuffer
+ A pointer to the source buffer for the data.
+
+ @param[in] StartLba
+ The starting logical block address to write to
+ on the device media.
+
+ @param[in] NumberOfBlocks
+ The number of transfer data blocks.
+
+ @param[in] UdmaOp
+ The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,
+ AtaUdmaWriteOp, AtaUdmaWriteExOp
+
+ @return The device status of UDMA operation. If the operation is
+ successful, return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+DoAtaUdma (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks,
+ IN ATA_UDMA_OPERATION UdmaOp
+ )
+{
+ 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;
+ UINT32 Count;
+ UINTN PageCount;
+ VOID *Map;
+ VOID *MemPage;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+ UINTN MaxDmaCommandSectors;
+ EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;
+ UINT8 AtaCommand;
+
+ switch (UdmaOp) {
+ case AtaUdmaReadOp:
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;
+ PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;
+ AtaCommand = ATA_CMD_READ_DMA;
+ break;
+ case AtaUdmaReadExtOp:
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;
+ PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;
+ AtaCommand = ATA_CMD_READ_DMA_EXT;
+ break;
+ case AtaUdmaWriteOp:
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;
+ PciIoProtocolOp = EfiPciIoOperationBusMasterRead;
+ AtaCommand = ATA_CMD_WRITE_DMA;
+ break;
+ case AtaUdmaWriteExtOp:
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;
+ PciIoProtocolOp = EfiPciIoOperationBusMasterRead;
+ AtaCommand = ATA_CMD_WRITE_DMA_EXT;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ break;
+ }
+
+ //
+ // 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 >= MaxDmaCommandSectors) {
+ //
+ // SectorCount is used to record the number of sectors to be read
+ // Max 65536 sectors can be transfered at a time.
+ //
+ NumberOfBlocks = MaxDmaCommandSectors;
+ RemainBlockNum -= MaxDmaCommandSectors;
+ } 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
+ //
+ PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));
+ Status = IdeDev->PciIo->AllocateBuffer (
+ IdeDev->PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ PageCount,
+ &MemPage,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));
+
+ PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);
+ //
+ // 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
+ //
+ Status = IdeDev->PciIo->Map (
+ IdeDev->PciIo,
+ PciIoProtocolOp,
+ DataBuffer,
+ &ByteCount,
+ &DeviceAddress,
+ &Map
+ );
+ if (EFI_ERROR (Status)) {
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ PrdBuffer = (VOID *) ((UINTN) DeviceAddress);
+ 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
+ );
+
+ if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {
+ RegisterValue |= BMIC_nREAD;
+ } else {
+ 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
+ );
+
+ if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {
+ Status = AtaCommandIssueExt (
+ IdeDev,
+ AtaCommand,
+ Device,
+ 0,
+ (UINT16) NumberOfBlocks,
+ StartLba
+ );
+ } else {
+ Status = AtaCommandIssue (
+ IdeDev,
+ AtaCommand,
+ Device,
+ 0,
+ (UINT16) NumberOfBlocks,
+ StartLba
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);
+ IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
+ 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
+ // Max transfer number of sectors for one command is 65536(32Mbyte),
+ // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).
+ // So set the variable Count to 2000, for about 2 second timeout time.
+ //
+ Count = 2000;
+ while (TRUE) {
+
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+ if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {
+ if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {
+ //
+ // Clear START bit of BMIC register before return EFI_DEVICE_ERROR
+ //
+ 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
+ );
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);
+ IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+ }
+
+ gBS->Stall (1000);
+ Count --;
+ }
+
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);
+ IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
+ //
+ // Read Status Register of IDE device to clear interrupt
+ //
+ RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);
+ //
+ // Clear 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;
+ }
+
+ //
+ // Disable interrupt of Select device
+ //
+ IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);
+ DeviceControl |= ATA_CTLREG_IEN_L;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/atapi.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/atapi.c
new file mode 100644
index 0000000000..2609591c0c
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/atapi.c
@@ -0,0 +1,2140 @@
+/** @file
+ Copyright (c) 2006 - 2007, 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.
+
+**/
+
+#include "idebus.h"
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS
+ The media status is achieved successfully and the media
+ can be read/written.
+
+ @retval EFI_DEVICE_ERROR
+ Get Media Status Command is failed.
+
+ @retval EFI_NO_MEDIA
+ There is no media in the drive.
+
+ @retval EFI_WRITE_PROTECTED
+ The media is writing protected.
+
+ @note
+ This function must be called after the LS120EnableMediaStatus()
+ with second parameter set to TRUE
+ (means enable media status notification) is called.
+
+**/
+STATIC
+EFI_STATUS
+LS120GetMediaStatus (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ 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;
+ }
+}
+
+/**
+ This function is used to send Enable Media Status Notification Command
+ or Disable Media Status Notification Command.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] Enable
+ a flag that indicates whether enable or disable media
+ status notification.
+
+ @retval EFI_SUCCESS
+ If command completes successfully.
+
+ @retval EFI_DEVICE_ERROR
+ If command failed.
+
+**/
+STATIC
+EFI_STATUS
+LS120EnableMediaStatus (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN BOOLEAN Enable
+ )
+{
+ 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;
+}
+
+/**
+ 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
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS
+ Identify ATAPI device successfully.
+
+ @retval EFI_DEVICE_ERROR
+ ATAPI Identify Device Command failed or device type
+ is not supported by this IDE driver.
+
+ @note
+ Parameter "IdeDev" will be updated in this function.
+
+ TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
+ TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
+**/
+EFI_STATUS
+ATAPIIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ EFI_IDENTIFY_DATA *AtapiIdentifyPointer;
+ UINT8 DeviceSelect;
+ EFI_STATUS Status;
+
+ //
+ // device select bit
+ //
+ 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),
+ ATA_CMD_IDENTIFY_DEVICE,
+ 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 (ATAPI_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;
+}
+
+/**
+ Sends out ATAPI Inquiry Packet Command to the specified device.
+ This command will return INQUIRY data of the device.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS
+ Inquiry command completes successfully.
+
+ @retval EFI_DEVICE_ERROR
+ Inquiry command failed.
+
+ @note
+ Parameter "IdeDev" will be updated in this function.
+
+**/
+EFI_STATUS
+AtapiInquiry (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+ ATAPI_INQUIRY_DATA *InquiryData;
+
+ //
+ // prepare command packet for the ATAPI Inquiry Packet Command.
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.Inquiry.opcode = ATA_CMD_INQUIRY;
+ Packet.Inquiry.page_code = 0;
+ Packet.Inquiry.allocation_length = sizeof (ATAPI_INQUIRY_DATA);
+
+ InquiryData = AllocatePool (sizeof (ATAPI_INQUIRY_DATA));
+ if (InquiryData == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send command packet and get requested Inquiry data.
+ //
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) InquiryData,
+ sizeof (ATAPI_INQUIRY_DATA),
+ ATAPITIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (InquiryData);
+ return EFI_DEVICE_ERROR;
+ }
+
+ IdeDev->pInquiryData = InquiryData;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to send out ATAPI commands conforms to the
+ Packet Command with PIO Data In Protocol.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *Packet
+ pointer pointing to ATAPI_PACKET_COMMAND data structure
+ which contains the contents of the command.
+
+ @param[in] *Buffer
+ buffer contained data transferred from device to host.
+
+ @param[in] ByteCount
+ data size in byte unit of the buffer.
+
+ @param[in] TimeOut
+ this parameter is used to specify the timeout
+ value for the PioReadWriteData() function.
+
+ @retval EFI_SUCCESS
+ send out the ATAPI packet command successfully
+ and device sends data successfully.
+
+ @retval EFI_DEVICE_ERROR
+ the device failed to send data.
+
+**/
+EFI_STATUS
+AtapiPacketCommandIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATAPI_PACKET_COMMAND *Packet,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN UINTN TimeOut
+ )
+{
+ 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) | ATA_DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)
+ );
+
+ //
+ // No OVL; No DMA
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);
+
+ //
+ // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
+ // determine how many data should be transferred.
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderLsb,
+ (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff)
+ );
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderMsb,
+ (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8)
+ );
+
+ //
+ // ATA_DEFAULT_CTL:0x0a (0000,1010)
+ // Disable interrupt
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL);
+
+ //
+ // Send Packet command to inform device
+ // that the following data bytes are command packet.
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET);
+
+ 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);
+}
+
+/**
+ This function is used to send out ATAPI commands conforms to the
+ Packet Command with PIO Data Out Protocol.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *Packet
+ pointer pointing to ATAPI_PACKET_COMMAND data structure
+ which contains the contents of the command.
+
+ @param[in] *Buffer
+ buffer contained data transferred from host to device.
+
+ @param[in] ByteCount
+ data size in byte unit of the buffer.
+
+ @param[in] TimeOut
+ this parameter is used to specify the timeout
+ value for the PioReadWriteData() function.
+
+ @retval EFI_SUCCESS
+ send out the ATAPI packet command successfully
+ and device received data successfully.
+
+ @retval EFI_DEVICE_ERROR
+ the device failed to send data.
+
+**/
+EFI_STATUS
+AtapiPacketCommandOut (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATAPI_PACKET_COMMAND *Packet,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN UINTN TimeOut
+ )
+{
+ 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) | ATA_DEFAULT_CMD) // ATA_DEFAULT_CMD: 0xa0 (1010,0000)
+ );
+
+ //
+ // No OVL; No DMA
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);
+
+ //
+ // set the transfersize to ATAPI_MAX_BYTE_COUNT to
+ // let the device determine how many data should be transferred.
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderLsb,
+ (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff)
+ );
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderMsb,
+ (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8)
+ );
+
+ //
+ // DEFAULT_CTL:0x0a (0000,1010)
+ // Disable interrupt
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL);
+
+ //
+ // Send Packet command to inform device
+ // that the following data bytes are command packet.
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET);
+
+ 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);
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *Buffer
+ buffer contained data transferred between host and device.
+
+ @param[in] ByteCount
+ data size in byte unit of the buffer.
+
+ @param[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.
+
+ @param[in] TimeOut
+ timeout value for wait DRQ ready before each data
+ stream's transfer.
+
+ @retval EFI_SUCCESS
+ data is transferred successfully.
+
+ @retval EFI_DEVICE_ERROR
+ the device failed to transfer data.
+
+**/
+EFI_STATUS
+PioReadWriteData (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN BOOLEAN Read,
+ IN UINTN TimeOut
+ )
+{
+ //
+ // required transfer data in word unit.
+ //
+ UINT32 RequiredWordCount;
+
+ //
+ // actual transfer data in word unit.
+ //
+ UINT32 ActualWordCount;
+ UINT32 WordCount;
+ EFI_STATUS Status;
+ UINT16 *PtrBuffer;
+
+ //
+ // 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
+ //
+ IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ //
+ // get current data transfer size from Cylinder Registers.
+ //
+ WordCount = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8;
+ WordCount = WordCount | IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);
+ WordCount = WordCount & 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;
+ }
+
+ if (Read) {
+ //
+ // In the case where the drive wants to send more data than we need to read,
+ // the DRQ bit will be set and cause delays from DRQClear2().
+ // We need to read data from the drive until it clears DRQ so we can move on.
+ //
+ AtapiReadPendingData (IdeDev);
+ }
+
+ //
+ // 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);
+}
+
+/**
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device
+ to find out whether device is accessible.
+
+ @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param[in] *SenseCount Sense count for this packet command
+
+ @retval EFI_SUCCESS Device is accessible.
+ @retval EFI_DEVICE_ERROR Device is not accessible.
+
+**/
+EFI_STATUS
+AtapiTestUnitReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT UINTN *SenseCount
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+
+ *SenseCount = 0;
+
+ //
+ // fill command packet
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;
+
+ //
+ // send command packet
+ //
+ Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = AtapiRequestSense (IdeDev, SenseCount);
+ if (EFI_ERROR (Status)) {
+ *SenseCount = 0;
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[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.
+
+ @param[out] *BufUnit
+ record the unit size of the sense data block in the SenseBuffers,
+
+ @param[out] *BufNumbers
+ record the number of units in the SenseBuffers.
+
+ @retval EFI_SUCCESS
+ Request Sense command completes successfully.
+
+ @retval EFI_DEVICE_ERROR
+ Request Sense command failed.
+
+**/
+EFI_STATUS
+AtapiRequestSense (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT UINTN *SenseCounts
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_REQUEST_SENSE_DATA *Sense;
+ UINT16 *Ptr;
+ BOOLEAN FetchSenseData;
+ ATAPI_PACKET_COMMAND Packet;
+
+ *SenseCounts = 0;
+
+ ZeroMem (IdeDev->SenseData, sizeof (ATAPI_REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));
+ //
+ // fill command packet for Request Sense Packet Command
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE;
+ Packet.RequestSence.allocation_length = sizeof (ATAPI_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 = (ATAPI_REQUEST_SENSE_DATA *) Ptr;
+
+ //
+ // send out Request Sense Packet Command and get one Sense data form device
+ //
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ Ptr,
+ sizeof (ATAPI_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 != ATA_SK_NO_SENSE) && ((*SenseCounts) < 20)) {
+ //
+ // Ptr is word-based pointer
+ //
+ Ptr += (sizeof (ATAPI_REQUEST_SENSE_DATA) + 1) >> 1;
+
+ } else {
+ //
+ // when no sense key, skip out the loop
+ //
+ FetchSenseData = FALSE;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param[in] SenseCount Sense count for this packet command
+
+ @retval EFI_SUCCESS Read Capacity Command finally completes successfully.
+ @retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error.
+
+ @note Parameter "IdeDev" will be updated in this function.
+
+ TODO: EFI_NOT_READY - add return value to function comment
+**/
+EFI_STATUS
+AtapiReadCapacity (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT UINTN *SenseCount
+ )
+{
+ //
+ // status returned by Read Capacity Packet Command
+ //
+ EFI_STATUS Status;
+ EFI_STATUS SenseStatus;
+ ATAPI_PACKET_COMMAND Packet;
+
+ //
+ // used for capacity data returned from ATAPI device
+ //
+ ATAPI_READ_CAPACITY_DATA Data;
+ ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;
+
+ *SenseCount = 0;
+
+ ZeroMem (&Data, sizeof (Data));
+ ZeroMem (&FormatData, sizeof (FormatData));
+
+ if (IdeDev->Type == IdeCdRom) {
+
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) &Data,
+ sizeof (ATAPI_READ_CAPACITY_DATA),
+ ATAPITIMEOUT
+ );
+
+ } else {
+ //
+ // Type == IdeMagnetic
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;
+ Packet.ReadFormatCapacity.allocation_length_lo = 12;
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) &FormatData,
+ sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),
+ ATAPITIMEOUT
+ );
+ }
+
+ if (Status == EFI_TIMEOUT) {
+ *SenseCount = 0;
+ return Status;
+ }
+
+ SenseStatus = AtapiRequestSense (IdeDev, SenseCount);
+
+ if (!EFI_ERROR (SenseStatus)) {
+
+ 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 {
+ *SenseCount = 0;
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[out] *MediaChange
+ return value that indicates if the media of the device has been
+ changed.
+
+ @retval EFI_SUCCESS
+ media found successfully.
+
+ @retval EFI_DEVICE_ERROR
+ any error encounters during media detection.
+
+ @retval EFI_NO_MEDIA
+ media not found.
+
+ @note
+ parameter IdeDev may be updated in this function.
+
+**/
+EFI_STATUS
+AtapiDetectMedia (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT BOOLEAN *MediaChange
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS CleanStateStatus;
+ EFI_BLOCK_IO_MEDIA OldMediaInfo;
+ UINTN RetryTimes;
+ UINTN RetryNotReady;
+ UINTN SenseCount;
+ SENSE_RESULT SResult;
+ BOOLEAN WriteProtected;
+
+ CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA));
+ *MediaChange = FALSE;
+ //
+ // Retry for SenseDeviceNotReadyNeedRetry.
+ // Each retry takes 1s and we limit the upper boundary to
+ // 120 times about 2 min.
+ //
+ RetryNotReady = 120;
+
+ //
+ // Do Test Unit Ready
+ //
+ DoTUR:
+ //
+ // Retry 5 times
+ //
+ RetryTimes = 5;
+ while (RetryTimes != 0) {
+
+ Status = AtapiTestUnitReady (IdeDev, &SenseCount);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Test Unit Ready error without sense data.
+ // For some devices, this means there's extra data
+ // that has not been read, so we read these extra
+ // data out before going on.
+ //
+ CleanStateStatus = AtapiReadPendingData (IdeDev);
+ if (EFI_ERROR (CleanStateStatus)) {
+ //
+ // Busy wait failed, try again
+ //
+ RetryTimes--;
+ }
+ //
+ // Try again without counting down RetryTimes
+ //
+ continue;
+ } else {
+
+ ParseSenseData (IdeDev, SenseCount, &SResult);
+
+ switch (SResult) {
+ case SenseNoSenseKey:
+ if (IdeDev->BlkIo.Media->MediaPresent) {
+ goto Done;
+ } else {
+ //
+ // Media present but the internal structure need refreshed.
+ // Try Read Capacity
+ //
+ goto DoRC;
+ }
+ break;
+
+ case SenseDeviceNotReadyNeedRetry:
+ if (--RetryNotReady == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall (1000 * STALL_1_MILLI_SECOND);
+ continue;
+ break;
+
+ case SenseNoMedia:
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ goto Done;
+ break;
+
+ case SenseDeviceNotReadyNoRetry:
+ case SenseMediaError:
+ return EFI_DEVICE_ERROR;
+
+ case SenseMediaChange:
+ IdeDev->BlkIo.Media->MediaId++;
+ goto DoRC;
+ break;
+
+ default:
+ RetryTimes--;
+ break;
+ }
+ }
+ }
+
+ return EFI_DEVICE_ERROR;
+
+ //
+ // Do Read Capacity
+ //
+ DoRC:
+ RetryTimes = 5;
+
+ while (RetryTimes != 0) {
+
+ Status = AtapiReadCapacity (IdeDev, &SenseCount);
+
+ if (EFI_ERROR (Status)) {
+ RetryTimes--;
+ continue;
+ } else {
+
+ ParseSenseData (IdeDev, SenseCount, &SResult);
+
+ switch (SResult) {
+ case SenseNoSenseKey:
+ goto Done;
+ break;
+
+ case SenseDeviceNotReadyNeedRetry:
+ //
+ // We use Test Unit Ready to retry which
+ // is faster.
+ //
+ goto DoTUR;
+ break;
+
+ case SenseNoMedia:
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ goto Done;
+ break;
+
+ case SenseDeviceNotReadyNoRetry:
+ case SenseMediaError:
+ return EFI_DEVICE_ERROR;
+
+ case SenseMediaChange:
+ IdeDev->BlkIo.Media->MediaId++;
+ continue;
+ break;
+
+ default:
+ RetryTimes--;
+ break;
+ }
+ }
+ }
+
+ return EFI_DEVICE_ERROR;
+
+ Done:
+ //
+ // 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
+ );
+ }
+
+ if (IdeDev->BlkIo.Media->MediaPresent) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NO_MEDIA;
+ }
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *Buffer
+ A pointer to the destination buffer for the data.
+
+ @param[in] Lba
+ The starting logical block address to read from
+ on the device media.
+
+ @param[in] NumberOfBlocks
+ The number of transfer data blocks.
+
+ @return status is fully dependent on the return status
+ of AtapiPacketCommandIn() function.
+
+**/
+EFI_STATUS
+AtapiReadSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_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 = 65535;
+
+ BlocksRemaining = NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining <= MaxBlock) {
+
+ SectorCount = (UINT16) BlocksRemaining;
+ } else {
+
+ SectorCount = MaxBlock;
+ }
+
+ //
+ // fill the Packet data structure
+ //
+
+ Read10Packet->opcode = ATA_CMD_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;
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *Buffer
+ A pointer to the source buffer for the data.
+
+ @param[in] Lba
+ The starting logical block address to write onto
+ the device media.
+
+ @param[in] NumberOfBlocks
+ The number of transfer data blocks.
+
+ @return status is fully dependent on the return status
+ of AtapiPacketCommandOut() function.
+
+**/
+EFI_STATUS
+AtapiWriteSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_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 = ATA_CMD_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;
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS
+ Soft reset completes successfully.
+
+ @retval EFI_DEVICE_ERROR
+ Any step during the reset process is failed.
+
+**/
+EFI_STATUS
+AtapiSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ 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 = ATA_CMD_SOFT_RESET;
+ 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;
+}
+
+/**
+ This function is the ATAPI implementation for ReadBlocks in the
+ Block I/O Protocol interface.
+
+ @param[in] *IdeBlkIoDev
+ Indicates the calling context.
+
+ @param[in] MediaId
+ The media id that the read request is for.
+
+ @param[in] LBA
+ The starting logical block address to read from
+ on the device.
+
+ @param[in] BufferSize
+ The size of the Buffer in bytes. This must be a
+ multiple of the intrinsic block size of the device.
+
+ @param[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.
+
+ @retval EFI_SUCCESS
+ Read Blocks successfully.
+
+ @retval EFI_DEVICE_ERROR
+ Read Blocks failed.
+
+ @retval EFI_NO_MEDIA
+ There is no media in the device.
+
+ @retval EFI_MEDIA_CHANGED
+ The MediaId is not for the current media.
+
+ @retval EFI_BAD_BUFFER_SIZE
+ The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+
+ @retval EFI_INVALID_PARAMETER
+ The read request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+**/
+EFI_STATUS
+AtapiBlkIoReadBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ 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;
+
+}
+
+/**
+ This function is the ATAPI implementation for WriteBlocks in the
+ Block I/O Protocol interface.
+
+ @param[in] *This
+ Indicates the calling context.
+
+ @param[in] MediaId
+ The media id that the write request is for.
+
+ @param[in] LBA
+ The starting logical block address to write onto
+ the device.
+
+ @param[in] BufferSize
+ The size of the Buffer in bytes. This must be a
+ multiple of the intrinsic block size of the device.
+
+ @param[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.
+
+ @retval EFI_SUCCESS
+ Write Blocks successfully.
+
+ @retval EFI_DEVICE_ERROR
+ Write Blocks failed.
+
+ @retval EFI_NO_MEDIA
+ There is no media in the device.
+
+ @retval EFI_MEDIA_CHANGE
+ The MediaId is not for the current media.
+
+ @retval EFI_BAD_BUFFER_SIZE
+ The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+
+ @retval EFI_INVALID_PARAMETER
+ The write request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ TODO: EFI_MEDIA_CHANGED - add return value to function comment
+ TODO: EFI_WRITE_PROTECTED - add return value to function comment
+**/
+EFI_STATUS
+AtapiBlkIoWriteBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+
+ 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;
+
+}
+
+/**
+ This function is used to parse sense data. Only the first
+ sense data is honoured.
+
+ @param[in] IdeDev Indicates the calling context.
+ @param[in] SenseCount Count of sense data.
+ @param[out] Result The parsed result.
+
+ @retval EFI_SUCCESS Successfully parsed.
+ @retval EFI_INVALID_PARAMETER Count of sense data is zero.
+
+**/
+EFI_STATUS
+ParseSenseData (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN SenseCount,
+ OUT SENSE_RESULT *Result
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SenseData;
+
+ if (SenseCount == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Only use the first sense data
+ //
+ SenseData = IdeDev->SenseData;
+ *Result = SenseOtherSense;
+
+ switch (SenseData->sense_key) {
+ case ATA_SK_NO_SENSE:
+ *Result = SenseNoSenseKey;
+ break;
+ case ATA_SK_NOT_READY:
+ switch (SenseData->addnl_sense_code) {
+ case ATA_ASC_NO_MEDIA:
+ *Result = SenseNoMedia;
+ break;
+ case ATA_ASC_MEDIA_UPSIDE_DOWN:
+ *Result = SenseMediaError;
+ break;
+ case ATA_ASC_NOT_READY:
+ if (SenseData->addnl_sense_code_qualifier == ATA_ASCQ_IN_PROGRESS) {
+ *Result = SenseDeviceNotReadyNeedRetry;
+ } else {
+ *Result = SenseDeviceNotReadyNoRetry;
+ }
+ break;
+ }
+ break;
+ case ATA_SK_UNIT_ATTENTION:
+ if (SenseData->addnl_sense_code == ATA_ASC_MEDIA_CHANGE) {
+ *Result = SenseMediaChange;
+ }
+ break;
+ case ATA_SK_MEDIUM_ERROR:
+ switch (SenseData->addnl_sense_code) {
+ case ATA_ASC_MEDIA_ERR1:
+ case ATA_ASC_MEDIA_ERR2:
+ case ATA_ASC_MEDIA_ERR3:
+ case ATA_ASC_MEDIA_ERR4:
+ *Result = SenseMediaError;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function reads the pending data in the device.
+
+ @param[in] IdeDev Indicates the calling context.
+
+ @retval EFI_SUCCESS Successfully read.
+ @retval EFI_NOT_READY The BSY is set avoiding reading.
+
+**/
+EFI_STATUS
+AtapiReadPendingData (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ UINT8 AltRegister;
+ UINT16 TempWordBuffer;
+
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+ if ((AltRegister & ATA_STSREG_BSY) == ATA_STSREG_BSY) {
+ return EFI_NOT_READY;
+ }
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);
+ while ((TempWordBuffer & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ IDEReadPortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ 1,
+ &TempWordBuffer
+ );
+ TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param WriteProtected TODO: add argument description
+
+ @retval EFI_DEVICE_ERROR TODO: Add description for return value
+ @retval EFI_DEVICE_ERROR TODO: Add description for return value
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+IsLS120orZipWriteProtected (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT BOOLEAN *WriteProtected
+ )
+{
+ 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/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ide.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ide.c
new file mode 100644
index 0000000000..a69c72e9e4
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ide.c
@@ -0,0 +1,1824 @@
+/** @file
+ 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.
+
+**/
+
+#include "idebus.h"
+
+BOOLEAN ChannelDeviceDetected = FALSE;
+BOOLEAN SlaveDeviceExist = FALSE;
+UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;
+BOOLEAN MasterDeviceExist = FALSE;
+UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;
+
+/**
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+
+ TODO: add return values
+
+**/
+UINT8
+IDEReadPortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ )
+{
+ 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;
+}
+
+/**
+ 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
+
+ @param PciIo Pointer to the EFI_PCI_IO instance
+ @param Port IO port to read
+ @param Count No. of UINT16's to read
+ @param Buffer Pointer to the data buffer for read
+
+**/
+VOID
+IDEReadPortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ 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);
+}
+
+/**
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+ @param Data TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+IDEWritePortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT8 Data
+ )
+{
+ //
+ // perform 1-byte data write to register
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+
+}
+
+/**
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+ @param Data TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+IDEWritePortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT16 Data
+ )
+{
+ //
+ // perform 1-word data write to register
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+}
+
+/**
+ 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
+
+ @param PciIo Pointer to the EFI_PCI_IO instance
+ @param Port IO port to read
+ @param Count No. of UINT16's to read
+ @param Buffer Pointer to the data buffer for read
+
+**/
+VOID
+IDEWritePortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ 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);
+}
+
+//
+// GetIdeRegistersBaseAddr
+//
+/**
+ 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.
+ <pre>
+ ___________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|_______________|_______________|
+ | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
+ |___________|_______________|_______________|
+ | Secondary | 170h - 177h | 376h - 377h |
+ |___________|_______________|_______________|
+
+ Table 1. Compatibility resource mappings
+ </pre>
+
+ 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.
+ <pre>
+ ___________________________________________________
+ | | 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
+ </pre>
+ @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.
+
+ @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
+ @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
+ receive IDE IO port registers' base addresses
+
+**/
+EFI_STATUS
+GetIdeRegistersBaseAddr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
+ )
+// 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;
+}
+
+/**
+ 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.
+
+ @param IdeDev The BLK_IO private data which specifies the IDE device
+
+**/
+EFI_STATUS
+ReassignIdeResources (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+// 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;
+}
+
+//
+// DiscoverIdeDevice
+//
+/**
+ Detect if there is disk connected to this port
+
+ @param IdeDev The BLK_IO private data which specifies the IDE device
+
+**/
+EFI_STATUS
+DiscoverIdeDevice (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+// 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;
+
+ //
+ // 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.
+ //
+ if (ChannelDeviceDetected == FALSE) {
+ Status = DetectIDEController (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Device exists. test if it is an ATA device.
+ // Prefer the result from DetectIDEController,
+ // if failed, try another device type to handle
+ // devices that not follow the spec.
+ //
+ if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {
+ if (MasterDeviceType == ATA_DEVICE_TYPE) {
+ Status = ATAIdentify (IdeDev);
+ if (EFI_ERROR (Status)) {
+ Status = ATAPIIdentify (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ MasterDeviceType = ATAPI_DEVICE_TYPE;
+ }
+ }
+ } else {
+ Status = ATAPIIdentify (IdeDev);
+ if (EFI_ERROR (Status)) {
+ Status = ATAIdentify (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ MasterDeviceType = ATA_DEVICE_TYPE;
+ }
+ }
+ }
+ }
+ if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {
+ if (SlaveDeviceType == ATA_DEVICE_TYPE) {
+ Status = ATAIdentify (IdeDev);
+ if (EFI_ERROR (Status)) {
+ Status = ATAPIIdentify (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ SlaveDeviceType = ATAPI_DEVICE_TYPE;
+ }
+ }
+ } else {
+ Status = ATAPIIdentify (IdeDev);
+ if (EFI_ERROR (Status)) {
+ Status = ATAIdentify (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ SlaveDeviceType = ATA_DEVICE_TYPE;
+ }
+ }
+ }
+ }
+ if (EFI_ERROR (Status)) {
+ 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;
+}
+
+/**
+ This interface is used to initialize all state data related to the detection of one
+ channel.
+
+ @retval EFI_SUCCESS Completed Successfully.
+
+**/
+EFI_STATUS
+InitializeIDEChannelData (
+ VOID
+ )
+{
+ ChannelDeviceDetected = FALSE;
+ MasterDeviceExist = FALSE;
+ MasterDeviceType = 0xff;
+ SlaveDeviceExist = FALSE;
+ SlaveDeviceType = 0xff;
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval TRUE
+ successfully detects device.
+
+ @retval FALSE
+ any failure during detection process will return this
+ value.
+
+ @note
+ TODO: EFI_SUCCESS - add return value to function comment
+ TODO: EFI_NOT_FOUND - add return value to function comment
+
+**/
+EFI_STATUS
+DetectIDEController (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SectorCountReg;
+ UINT8 LBALowReg;
+ UINT8 LBAMidReg;
+ UINT8 LBAHighReg;
+ UINT8 InitStatusReg;
+ UINT8 StatusReg;
+
+ //
+ // 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);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));
+ return Status;
+ }
+ //
+ // Read device signature
+ //
+ //
+ // Select Master
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((0 << 4) | 0xe0)
+ );
+ gBS->Stall (100);
+ SectorCountReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->SectorCount
+ );
+ LBALowReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->SectorNumber
+ );
+ LBAMidReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderLsb
+ );
+ LBAHighReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderMsb
+ );
+ if ((SectorCountReg == 0x1) &&
+ (LBALowReg == 0x1) &&
+ (LBAMidReg == 0x0) &&
+ (LBAHighReg == 0x0)) {
+ MasterDeviceExist = TRUE;
+ MasterDeviceType = ATA_DEVICE_TYPE;
+ } else {
+ if ((LBAMidReg == 0x14) &&
+ (LBAHighReg == 0xeb)) {
+ MasterDeviceExist = TRUE;
+ MasterDeviceType = ATAPI_DEVICE_TYPE;
+ }
+ }
+
+ //
+ // For some Hard Drive, it takes some time to get
+ // the right signature when operating in single slave mode.
+ // We stall 20ms to work around this.
+ //
+ if (!MasterDeviceExist) {
+ gBS->Stall (20000);
+ }
+
+ //
+ // Select Slave
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((1 << 4) | 0xe0)
+ );
+ gBS->Stall (100);
+ SectorCountReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->SectorCount
+ );
+ LBALowReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->SectorNumber
+ );
+ LBAMidReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderLsb
+ );
+ LBAHighReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderMsb
+ );
+ StatusReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Reg.Status
+ );
+ if ((SectorCountReg == 0x1) &&
+ (LBALowReg == 0x1) &&
+ (LBAMidReg == 0x0) &&
+ (LBAHighReg == 0x0)) {
+ SlaveDeviceExist = TRUE;
+ SlaveDeviceType = ATA_DEVICE_TYPE;
+ } else {
+ if ((LBAMidReg == 0x14) &&
+ (LBAHighReg == 0xeb)) {
+ SlaveDeviceExist = TRUE;
+ SlaveDeviceType = ATAPI_DEVICE_TYPE;
+ }
+ }
+
+ //
+ // When single master is plugged, slave device
+ // will be wrongly detected. Here's the workaround
+ // for ATA devices by detecting DRY bit in status
+ // register.
+ // NOTE: This workaround doesn't apply to ATAPI.
+ //
+ if (MasterDeviceExist && SlaveDeviceExist &&
+ (StatusReg & ATA_STSREG_DRDY) == 0 &&
+ (InitStatusReg & ATA_STSREG_DRDY) == 0 &&
+ MasterDeviceType == SlaveDeviceType &&
+ SlaveDeviceType != ATAPI_DEVICE_TYPE) {
+ SlaveDeviceExist = FALSE;
+ }
+
+ //
+ // Indicate this channel has been detected
+ //
+ ChannelDeviceDetected = TRUE;
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ clear.
+
+ @retval EFI_SUCCESS
+ DRQ bit clear within the time out.
+
+ @retval EFI_TIMEOUT
+ DRQ bit not clear within the time out.
+
+ @note
+ Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRQClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+// 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 & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
+ break;
+ }
+
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ clear.
+
+ @retval EFI_SUCCESS
+ DRQ bit clear within the time out.
+
+ @retval EFI_TIMEOUT
+ DRQ bit not clear within the time out.
+
+ @note
+ Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+DRQClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+// 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 & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
+ break;
+ }
+
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+
+ @param[in] 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.
+
+ @param[in] UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS
+ DRQ bit set within the time out.
+
+ @retval EFI_TIMEOUT
+ DRQ bit not set within the time out.
+
+ @retval EFI_ABORTED
+ DRQ bit not set caused by the command abort.
+
+ @note
+ Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRQReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+// 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 & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ break;
+ }
+
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+
+ @param[in] 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.
+
+ @param[in] UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS
+ DRQ bit set within the time out.
+
+ @retval EFI_TIMEOUT
+ DRQ bit not set within the time out.
+
+ @retval EFI_ABORTED
+ DRQ bit not set caused by the command abort.
+
+ @note
+ Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+DRQReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+// 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 & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ break;
+ }
+
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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.
+
+ @param[in] 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.
+
+ @param[in] UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS
+ BSY bit clear within the time out.
+
+ @retval EFI_TIMEOUT
+ BSY bit not clear within the time out.
+
+ @note
+ Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+WaitForBSYClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+// 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 & ATA_STSREG_BSY) == 0x00) {
+ break;
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+//
+// WaitForBSYClear2
+//
+/**
+ 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.
+
+ @param[in] 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.
+
+ @param[in] UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS
+ BSY bit clear within the time out.
+
+ @retval EFI_TIMEOUT
+ BSY bit not clear within the time out.
+
+ @note
+ Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+WaitForBSYClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+// 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 & ATA_STSREG_BSY) == 0x00) {
+ break;
+ }
+
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// DRDYReady
+//
+/**
+ 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.
+
+ @param[in] 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.
+
+ @param[in] UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS
+ DRDY bit set within the time out.
+
+ @retval EFI_TIMEOUT
+ DRDY bit not set within the time out.
+
+ @note
+ Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRDYReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ )
+// 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 & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {
+ break;
+ }
+
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// DRDYReady2
+//
+/**
+ 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.
+
+ @param[in] 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.
+
+ @param[in] UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS
+ DRDY bit set within the time out.
+
+ @retval EFI_TIMEOUT
+ DRDY bit not set within the time out.
+
+ @note
+ Read Alternate Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRDYReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ )
+// 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 & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {
+ break;
+ }
+
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// SwapStringChars
+//
+/**
+ 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.
+
+ @param[in] CHAR8 IN *Destination
+ Indicates the destination string.
+
+ @param[in] CHAR8 IN *Source
+ Indicates the source string.
+
+ @param[in] UINT8 IN Size
+ the length of the string
+
+**/
+VOID
+SwapStringChars (
+ IN CHAR8 *Destination,
+ IN CHAR8 *Source,
+ IN UINT32 Size
+ )
+{
+ UINT32 Index;
+ CHAR8 Temp;
+
+ for (Index = 0; Index < Size; Index += 2) {
+
+ Temp = Source[Index + 1];
+ Destination[Index + 1] = Source[Index];
+ Destination[Index] = Temp;
+ }
+}
+
+//
+// ReleaseIdeResources
+//
+/**
+ Release resources of an IDE device before stopping it.
+
+ @param[in] *IdeBlkIoDevice Standard IDE device private data structure
+
+**/
+VOID
+ReleaseIdeResources (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice
+ )
+{
+ 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);
+ }
+
+ if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {
+ gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);
+ IdeBlkIoDevice->ExitBootServiceEvent = NULL;
+ }
+
+ gBS->FreePool (IdeBlkIoDevice);
+ IdeBlkIoDevice = NULL;
+
+ return ;
+}
+
+//
+// SetDeviceTransferMode
+//
+/**
+ Set the calculated Best transfer mode to a detected device
+
+ @param[in] *IdeDev Standard IDE device private data structure
+ @param[in] *TransferMode The device transfer mode to be set
+
+ @return Set transfer mode Command execute status
+
+**/
+EFI_STATUS
+SetDeviceTransferMode (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_TRANSFER_MODE *TransferMode
+ )
+// 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,
+ ATA_CMD_SET_FEATURES,
+ DeviceSelect,
+ 0x03,
+ SectorCount,
+ 0,
+ 0,
+ 0
+ );
+
+ return Status;
+}
+
+/**
+ Send ATA command into device with NON_DATA protocol
+
+ @param IdeDev Standard IDE device private data structure
+ @param AtaCommand The ATA command to be sent
+ @param Device The value in Device register
+ @param Feature The value in Feature register
+ @param SectorCount The value in SectorCount register
+ @param LbaLow The value in LBA_LOW register
+ @param LbaMiddle The value in LBA_MIDDLE register
+ @param LbaHigh The value in LBA_HIGH register
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_ABORTED Command failed
+ @retval EFI_DEVICE_ERROR Device status error
+
+**/
+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
+ )
+{
+ 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
+ // For ATAPI_SMART_CMD, we may need more timeout to let device
+ // adjust internal states.
+ //
+ if (AtaCommand == ATA_CMD_SMART) {
+ Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);
+ } else {
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+ if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+ //
+ // Failed to execute command, abort operation
+ //
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send ATA Ext command into device with NON_DATA protocol
+
+ @param IdeDev Standard IDE device private data structure
+ @param AtaCommand The ATA command to be sent
+ @param Device The value in Device register
+ @param Feature The value in Feature register
+ @param SectorCount The value in SectorCount register
+ @param LbaAddress The LBA address in 48-bit mode
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_ABORTED Command failed
+ @retval EFI_DEVICE_ERROR Device status error
+
+**/
+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
+ )
+{
+ 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 & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+ //
+ // Failed to execute command, abort operation
+ //
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// SetDriveParameters
+//
+/**
+ Set drive parameters for devices not support PACKETS command
+
+ @param[in] IdeDev Standard IDE device private data structure
+ @param[in] DriveParameters The device parameters to be set into the disk
+
+ @return SetParameters Command execute status
+
+**/
+EFI_STATUS
+SetDriveParameters (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_DRIVE_PARMS *DriveParameters
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DeviceSelect;
+
+ DeviceSelect = 0;
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+
+ //
+ // Send Init drive parameters
+ //
+ Status = AtaNonDataCommandIn (
+ IdeDev,
+ ATA_CMD_INIT_DRIVE_PARAM,
+ (UINT8) (DeviceSelect + DriveParameters->Heads),
+ 0,
+ DriveParameters->Sector,
+ 0,
+ 0,
+ 0
+ );
+
+ //
+ // Send Set Multiple parameters
+ //
+ Status = AtaNonDataCommandIn (
+ IdeDev,
+ ATA_CMD_SET_MULTIPLE_MODE,
+ DeviceSelect,
+ 0,
+ DriveParameters->MultipleSector,
+ 0,
+ 0,
+ 0
+ );
+ return Status;
+}
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+EnableInterrupt (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ UINT8 DeviceControl;
+
+ //
+ // Enable interrupt for DMA operation
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
+
+ @param[in] Event Pointer to this event
+ @param[in] Context Event hanlder private data
+
+**/
+VOID
+EFIAPI
+ClearInterrupt (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINT64 IoPortForBmis;
+ UINT8 RegisterValue;
+ IDE_BLK_IO_DEV *IdeDev;
+
+ //
+ // Get our context
+ //
+ IdeDev = (IDE_BLK_IO_DEV *) Context;
+
+ //
+ // Obtain IDE IO port registers' base addresses
+ //
+ Status = ReassignIdeResources (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Check whether interrupt is pending
+ //
+
+ //
+ // Reset IDE device to force it de-assert interrupt pin
+ // Note: this will reset all devices on this IDE channel
+ //
+ AtaSoftReset (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Get base address of IDE Bus Master Status Regsiter
+ //
+ if (IdePrimary == IdeDev->Channel) {
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
+ } else {
+ if (IdeSecondary == IdeDev->Channel) {
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
+ } else {
+ return;
+ }
+ }
+ //
+ // 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
+ );
+
+ //
+ // Select the other device on this channel to ensure this device to release the interrupt pin
+ //
+ if (IdeDev->Device == 0) {
+ RegisterValue = (1 << 4) | 0xe0;
+ } else {
+ RegisterValue = (0 << 4) | 0xe0;
+ }
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ RegisterValue
+ );
+
+}
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ide.h b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ide.h
new file mode 100644
index 0000000000..ec1f9e07a0
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ide.h
@@ -0,0 +1,1328 @@
+/** @file
+ Header file for IDE Bus Driver, containing the helper functions'
+ entire prototype.
+
+ Copyright (c) 2006 - 2007 Intel Corporation. <BR>
+ 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.
+
+ @par Revision Reference:
+ 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including
+ Add - IDEBlkIoReadBlocksExt() func definition
+ Add - IDEBlkIoWriteBlocksExt() func definition
+
+**/
+
+#ifndef _IDE_H
+#define _IDE_H
+
+//
+// Helper functions Prototype
+//
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Controller TODO: add argument description
+ @param Handle TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+DeRegisterIdeDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param Controller TODO: add argument description
+ @param PciIo TODO: add argument description
+ @param ParentDevicePath TODO: add argument description
+ @param RemainingDevicePath TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+
+ TODO: add return values
+
+**/
+UINT8
+IDEReadPortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+ @param Count TODO: add argument description
+ @param Buffer TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+IDEReadPortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+ @param Data TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+IDEWritePortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT8 Data
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+ @param Data TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+IDEWritePortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT16 Data
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Port TODO: add argument description
+ @param Count TODO: add argument description
+ @param Buffer TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+IDEWritePortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param IdeRegsBaseAddr TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+GetIdeRegistersBaseAddr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+ReassignIdeResources (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+DiscoverIdeDevice (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ This interface is used to initialize all state data related to the
+ detection of one channel.
+
+ @retval EFI_SUCCESS Completed successfully.
+
+**/
+EFI_STATUS
+InitializeIDEChannelData (
+ VOID
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+DetectIDEController (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param TimeoutInMilliSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+DRQClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param TimeoutInMilliSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+DRQClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param TimeoutInMilliSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+DRQReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param TimeoutInMilliSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+DRQReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param TimeoutInMilliSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+WaitForBSYClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param TimeoutInMilliSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+WaitForBSYClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param DelayInMilliSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+DRDYReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param DelayInMilliSeconds TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+DRDYReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param Destination TODO: add argument description
+ @param Source TODO: add argument description
+ @param Size TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+SwapStringChars (
+ IN CHAR8 *Destination,
+ IN CHAR8 *Source,
+ IN UINT32 Size
+ )
+;
+
+//
+// ATA device functions' prototype
+//
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+ATAIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+PrintAtaModuleName (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param ByteCount TODO: add argument description
+ @param AtaCommand TODO: add argument description
+ @param Head TODO: add argument description
+ @param SectorCount TODO: add argument description
+ @param SectorNumber TODO: add argument description
+ @param CylinderLsb TODO: add argument description
+ @param CylinderMsb TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param ByteCount TODO: add argument description
+ @param AtaCommand TODO: add argument description
+ @param Head TODO: add argument description
+ @param SectorCount TODO: add argument description
+ @param SectorNumber TODO: add argument description
+ @param CylinderLsb TODO: add argument description
+ @param CylinderMsb TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+CheckErrorStatus (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param DataBuffer TODO: add argument description
+ @param Lba TODO: add argument description
+ @param NumberOfBlocks TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtaReadSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param BufferData TODO: add argument description
+ @param Lba TODO: add argument description
+ @param NumberOfBlocks TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtaWriteSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *BufferData,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtaSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeBlkIoDevice TODO: add argument description
+ @param MediaId TODO: add argument description
+ @param LBA TODO: add argument description
+ @param BufferSize TODO: add argument description
+ @param Buffer TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeBlkIoDevice TODO: add argument description
+ @param MediaId TODO: add argument description
+ @param LBA TODO: add argument description
+ @param BufferSize TODO: add argument description
+ @param Buffer TODO: add argument description
+
+ 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
+ )
+;
+
+//
+// ATAPI device functions' prototype
+//
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+ATAPIIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiInquiry (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param Packet TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param ByteCount TODO: add argument description
+ @param TimeOut TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param Packet TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param ByteCount TODO: add argument description
+ @param TimeOut TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param ByteCount TODO: add argument description
+ @param Read TODO: add argument description
+ @param TimeOut TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiTestUnitReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT UINTN *SenseCount
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param SenseCounts TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiRequestSense (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT UINTN *SenseCounts
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiReadCapacity (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT UINTN *SenseCount
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param MediaChange TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiDetectMedia (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT BOOLEAN *MediaChange
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param Lba TODO: add argument description
+ @param NumberOfBlocks TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiReadSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param Lba TODO: add argument description
+ @param NumberOfBlocks TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiWriteSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeBlkIoDevice TODO: add argument description
+ @param MediaId TODO: add argument description
+ @param LBA TODO: add argument description
+ @param BufferSize TODO: add argument description
+ @param Buffer TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeBlkIoDevice TODO: add argument description
+ @param MediaId TODO: add argument description
+ @param LBA TODO: add argument description
+ @param BufferSize TODO: add argument description
+ @param Buffer TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param SenseCount TODO: add argument description
+ @param Result TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+ParseSenseData (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN SenseCount,
+ OUT SENSE_RESULT *Result
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtapiReadPendingData (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param WriteProtected TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+IsLS120orZipWriteProtected (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT BOOLEAN *WriteProtected
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeBlkIoDevice TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+ReleaseIdeResources (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param TransferMode TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+SetDeviceTransferMode (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_TRANSFER_MODE *TransferMode
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param NativeMaxAddress TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+ReadNativeMaxAddress (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT EFI_LBA *NativeMaxAddress
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param MaxAddress TODO: add argument description
+ @param bVolatile TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+SetMaxAddress (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN EFI_LBA MaxAddress,
+ IN BOOLEAN bVolatile
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param AtaCommand TODO: add argument description
+ @param Device TODO: add argument description
+ @param Feature TODO: add argument description
+ @param SectorCount TODO: add argument description
+ @param LbaLow TODO: add argument description
+ @param LbaMiddle TODO: add argument description
+ @param LbaHigh TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param AtaCommand TODO: add argument description
+ @param Device TODO: add argument description
+ @param Feature TODO: add argument description
+ @param SectorCount TODO: add argument description
+ @param LbaAddress TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param DataBuffer TODO: add argument description
+ @param StartLba TODO: add argument description
+ @param NumberOfBlocks TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtaReadSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param DataBuffer TODO: add argument description
+ @param StartLba TODO: add argument description
+ @param NumberOfBlocks TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtaWriteSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param DataBuffer TODO: add argument description
+ @param StartLba TODO: add argument description
+ @param NumberOfBlocks TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtaUdmaReadExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param DataBuffer TODO: add argument description
+ @param StartLba TODO: add argument description
+ @param NumberOfBlocks TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtaUdmaRead (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param DataBuffer TODO: add argument description
+ @param StartLba TODO: add argument description
+ @param NumberOfBlocks TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtaUdmaWriteExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+;
+
+/**
+ Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).
+
+ @param[in] *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param[in] *DataBuffer
+ A pointer to the source buffer for the data.
+
+ @param[in] StartLba
+ The starting logical block address to write to
+ on the device media.
+
+ @param[in] NumberOfBlocks
+ The number of transfer data blocks.
+
+ @param[in] UdmaOp
+ The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,
+ AtaUdmaWriteOp, AtaUdmaWriteExOp
+
+ @return The device status of UDMA operation. If the operation is
+ successful, return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+DoAtaUdma (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks,
+ IN ATA_UDMA_OPERATION UdmaOp
+ )
+;
+
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param DataBuffer TODO: add argument description
+ @param StartLba TODO: add argument description
+ @param NumberOfBlocks TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtaUdmaWrite (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param AtaCommand TODO: add argument description
+ @param Device TODO: add argument description
+ @param Feature TODO: add argument description
+ @param SectorCount TODO: add argument description
+ @param LbaAddress TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param AtaCommand TODO: add argument description
+ @param Device TODO: add argument description
+ @param Feature TODO: add argument description
+ @param SectorCount TODO: add argument description
+ @param LbaAddress TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+AtaAtapi6Identify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+AtaSMARTSupport (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param ByteCount TODO: add argument description
+ @param AtaCommand TODO: add argument description
+ @param StartLba TODO: add argument description
+ @param SectorCount TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param Buffer TODO: add argument description
+ @param ByteCount TODO: add argument description
+ @param AtaCommand TODO: add argument description
+ @param StartLba TODO: add argument description
+ @param SectorCount TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+ @param DriveParameters TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+SetDriveParameters (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_DRIVE_PARMS *DriveParameters
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param IdeDev TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EnableInterrupt (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+;
+
+/**
+ Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
+
+ @param[in] Event Pointer to this event
+ @param[in] Context Event hanlder private data
+
+ @retval EFI_SUCCESS - Interrupt cleared
+
+**/
+VOID
+EFIAPI
+ClearInterrupt (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+;
+
+#endif
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idebus.c b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idebus.c
new file mode 100644
index 0000000000..5830044752
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idebus.c
@@ -0,0 +1,1413 @@
+/** @file
+ Copyright (c) 2006 - 2007 Intel Corporation. <BR>
+ 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.
+
+ @par Revision Reference:
+ 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,
+ 0xa,
+ NULL,
+ NULL
+};
+
+//
+// ***********************************************************************************
+// IDEBusDriverBindingSupported
+// ***********************************************************************************
+//
+/**
+ Register Driver Binding protocol for this driver.
+
+ @param[in] This -- A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle -- The handle of the controller to test.
+ @param[in] RemainingDevicePath -- A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS Driver loaded.
+ @retval other Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+// 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;
+ }
+
+ //
+ // Close 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
+// ***********************************************************************************
+//
+/**
+ Start this driver on Controller by detecting all disks and installing
+ BlockIo protocol on them.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Not used, always produce all possible children.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle.
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ 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;
+ IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
+
+ //
+ // Local variables declaration for IdeControllerInit support
+ //
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
+ BOOLEAN EnumAll;
+ BOOLEAN ChannelEnabled;
+ 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. Step7.2
+ //
+ EnumAll = IdeInit->EnumAll;
+
+ //
+ // 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,
+ NULL,
+ &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
+ );
+
+ //
+ // Prepare to detect IDE device of this channel
+ //
+ InitializeIDEChannelData ();
+
+ //
+ // -- 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 = (EFI_IDE_CHANNEL) IdeChannel;
+ IdeBlkIoDevicePtr->Device = (EFI_IDE_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_EX (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_PRESENCE_DETECT),
+ 0,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL,
+ 0
+ );
+
+ //
+ // 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));
+ 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;
+ }
+ //
+ // Record Udma Mode
+ //
+ IdeBlkIoDevicePtr->UdmaMode.Valid = TRUE;
+ IdeBlkIoDevicePtr->UdmaMode.Mode = SupportedModes->UdmaMode.Mode;
+ 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 = (ATA_PIO_MODE) 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
+ );
+
+ //
+ // Create event to clear pending IDE interrupt
+ //
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ TPL_NOTIFY,
+ ClearInterrupt,
+ IdeBlkIoDevicePtr,
+ &IdeBlkIoDevicePtr->ExitBootServiceEvent
+ );
+
+ //
+ // 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
+// ***********************************************************************************
+//
+/**
+ Stop this driver on Controller Handle.
+
+ @param This Protocol instance pointer.
+ @param DeviceHandle Handle of device to stop driver on
+ @param NumberOfChildren Not used
+ @param ChildHandleBuffer Not used
+
+ @retval EFI_SUCCESS This driver is removed DeviceHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+// 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
+// ***********************************************************************************
+//
+/**
+ Deregister an IDE device and free resources
+
+ @param This Protocol instance pointer.
+ @param Controller Ide device handle
+ @param Handle Handle of device to deregister driver on
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+DeRegisterIdeDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ )
+// 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
+// ***********************************************************************************
+//
+/**
+ 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
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ 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 ||
+ IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+ Status = AtaSoftReset (IdeBlkIoDevice);
+ goto Done;
+ }
+
+ if (IdeBlkIoDevice->Type == IdeUnknown) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // for ATAPI device, using ATAPI reset method
+ //
+ Status = AtapiSoftReset (IdeBlkIoDevice);
+ if (ExtendedVerification) {
+ Status = AtaSoftReset (IdeBlkIoDevice);
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Read data from block io device
+
+ @param This Protocol instance pointer.
+ @param MediaId The media ID of the device
+ @param LBA Starting LBA address to read data
+ @param BufferSize The size of data to be read
+ @param Buffer Caller supplied buffer to save data
+
+ @return read data status
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ 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) {
+ Status = AtaBlkIoReadBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ LBA,
+ BufferSize,
+ Buffer
+ );
+ goto Done;
+ }
+
+ if (IdeBlkIoDevice->Type == IdeUnknown) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // for ATAPI device, using ATAPI read block's mechanism
+ //
+ Status = AtapiBlkIoReadBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ LBA,
+ BufferSize,
+ Buffer
+ );
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Write data to block io device
+
+ @param This Protocol instance pointer.
+ @param MediaId The media ID of the device
+ @param LBA Starting LBA address to write data
+ @param BufferSize The size of data to be written
+ @param Buffer Caller supplied buffer to save data
+
+ @return write data status
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ 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) {
+
+ Status = AtaBlkIoWriteBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ LBA,
+ BufferSize,
+ Buffer
+ );
+ goto Done;
+ }
+
+ if (IdeBlkIoDevice->Type == IdeUnknown) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // for ATAPI device, using ATAPI write block's mechanism
+ //
+ Status = AtapiBlkIoWriteBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ LBA,
+ BufferSize,
+ Buffer
+ );
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+//
+// ***********************************************************************************
+// IDEBlkIoFlushBlocks
+// ***********************************************************************************
+//
+/**
+ TODO: This - add argument and description to function comment
+ TODO: EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ //
+ // return directly
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the results of the Inquiry command to a drive in InquiryData.
+ Data format of Inquiry data is defined by the Interface GUID.
+
+ @param This Protocol instance pointer.
+ @param InquiryData Results of Inquiry command to device
+ @param InquiryDataSize Size of InquiryData in bytes.
+
+ @retval EFI_SUCCESS InquiryData valid
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device
+ @retval EFI_BUFFER_TOO_SMALL IntquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+
+ if (*InquiryDataSize < sizeof (ATAPI_INQUIRY_DATA)) {
+ *InquiryDataSize = sizeof (ATAPI_INQUIRY_DATA);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (IdeBlkIoDevice->pInquiryData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ gBS->CopyMem (InquiryData, IdeBlkIoDevice->pInquiryData, sizeof (ATAPI_INQUIRY_DATA));
+ *InquiryDataSize = sizeof (ATAPI_INQUIRY_DATA);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the results of the Identify command to a drive in IdentifyData.
+ Data format of Identify data is defined by the Interface GUID.
+
+ @param This Protocol instance pointer.
+ @param IdentifyData Results of Identify command to device
+ @param IdentifyDataSize Size of IdentifyData in bytes.
+
+ @retval EFI_SUCCESS IdentifyData valid
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
+ @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ 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;
+}
+
+/**
+ Return the results of the Request Sense command to a drive in SenseData.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param This Protocol instance pointer.
+ @param SenseData Results of Request Sense command to device
+ @param SenseDataSize Size of SenseData in bytes.
+ @param SenseDataNumber Type of SenseData
+
+ @retval EFI_SUCCESS InquiryData valid
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Return the results of the Request Sense command to a drive in SenseData.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param This Protocol instance pointer.
+ @param IdeChannel Primary or Secondary
+ @param IdeDevice Master or Slave
+
+ @retval EFI_SUCCESS IdeChannel and IdeDevice are valid
+ @retval EFI_UNSUPPORTED This is not an IDE device
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+ *IdeChannel = IdeBlkIoDevice->Channel;
+ *IdeDevice = IdeBlkIoDevice->Device;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user Entry Point for module IdeBus. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeIdeBus(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallAllDriverProtocols (
+ ImageHandle,
+ SystemTable,
+ &gIDEBusDriverBinding,
+ ImageHandle,
+ &gIDEBusComponentName,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idebus.h b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idebus.h
new file mode 100644
index 0000000000..13fa1b5130
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idebus.h
@@ -0,0 +1,419 @@
+/** @file
+ Header file for IDE Bus Driver.
+
+ Copyright (c) 2006 - 2007 Intel Corporation. <BR>
+ 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.
+
+**/
+
+#ifndef _IDE_BUS_H
+#define _IDE_BUS_H
+
+
+//
+// The package level header files this module uses
+//
+#include <FrameworkDxe.h>
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Protocol/IdeControllerInit.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/DevicePath.h>
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <IndustryStandard/pci22.h>
+#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
+
+#define INVALID_DEVICE_TYPE 0xff
+#define ATA_DEVICE_TYPE 0x00
+#define ATAPI_DEVICE_TYPE 0x01
+
+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;
+
+ ATAPI_INQUIRY_DATA *pInquiryData;
+ EFI_IDENTIFY_DATA *pIdData;
+ ATA_PIO_MODE PioMode;
+ EFI_ATA_MODE UdmaMode;
+ CHAR8 ModelName[41];
+ ATAPI_REQUEST_SENSE_DATA *SenseData;
+ UINT8 SenseDataNumber;
+ UINT8 *Cache;
+
+ //
+ // ExitBootService Event, it is used to clear pending IDE interrupt
+ //
+ EFI_EVENT ExitBootServiceEvent;
+
+ 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
+//
+/**
+ TODO: Add function description
+
+ @param ImageHandle TODO: add argument description
+ @param SystemTable TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusControllerDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Controller TODO: add argument description
+ @param RemainingDevicePath TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Controller TODO: add argument description
+ @param RemainingDevicePath TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Controller TODO: add argument description
+ @param NumberOfChildren TODO: add argument description
+ @param ChildHandleBuffer TODO: add argument description
+
+ 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
+ )
+;
+
+//
+// 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 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
+ );
+
+//
+// Block I/O Protocol Interface
+//
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param ExtendedVerification TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param MediaId TODO: add argument description
+ @param LBA TODO: add argument description
+ @param BufferSize TODO: add argument description
+ @param Buffer TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param MediaId TODO: add argument description
+ @param LBA TODO: add argument description
+ @param BufferSize TODO: add argument description
+ @param Buffer TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param PciIo TODO: add argument description
+ @param Enable TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+IDERegisterDecodeEnableorDisable (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN BOOLEAN Enable
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param InquiryData TODO: add argument description
+ @param IntquiryDataSize TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *IntquiryDataSize
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param IdentifyData TODO: add argument description
+ @param IdentifyDataSize TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param SenseData TODO: add argument description
+ @param SenseDataSize TODO: add argument description
+ @param SenseDataNumber TODO: add argument description
+
+ 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
+ )
+;
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param IdeChannel TODO: add argument description
+ @param IdeDevice TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+;
+
+#endif
diff --git a/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idedata.h b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idedata.h
new file mode 100644
index 0000000000..83a42af6b1
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/idedata.h
@@ -0,0 +1,311 @@
+/** @file
+ Header file for IDE Bus Driver's Data Structures
+
+ Copyright (c) 2006 - 2007 Intel Corporation. <BR>
+ 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.
+
+**/
+
+#ifndef _IDE_DATA_H
+#define _IDE_DATA_H
+
+#include <IndustryStandard/Atapi.h>
+
+//
+// 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;
+
+typedef enum {
+ SenseNoSenseKey,
+ SenseDeviceNotReadyNoRetry,
+ SenseDeviceNotReadyNeedRetry,
+ SenseNoMedia,
+ SenseMediaChange,
+ SenseMediaError,
+ SenseOtherSense
+} SENSE_RESULT;
+
+typedef enum {
+ AtaUdmaReadOp,
+ AtaUdmaReadExtOp,
+ AtaUdmaWriteOp,
+ AtaUdmaWriteExtOp
+} ATA_UDMA_OPERATION;
+
+//
+// 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
+
+
+//
+// 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
+
+//
+// 10 seconds
+//
+#define ATASMARTTIMEOUT 10000
+
+
+//
+// ATAPI6 related data structure definition
+//
+
+//
+// The maximum sectors count in 28 bit addressing mode
+//
+#define MAX_28BIT_ADDRESSING_CAPACITY 0xfffffff
+
+#pragma pack(1)
+
+typedef struct {
+ UINT32 RegionBaseAddr;
+ UINT16 ByteCount;
+ UINT16 EndOfTable;
+} IDE_DMA_PRD;
+
+#pragma pack()
+
+#define SETFEATURE TRUE
+#define CLEARFEATURE FALSE
+
+//
+// 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