--- /dev/null
+/** @file\r
+ Copyright (c) 2006, Intel Corporation \r
+ All rights reserved. This program and the accompanying materials \r
+ are licensed and made available under the terms and conditions of the BSD License \r
+ which accompanies this distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "idebus.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName = {\r
+ IDEBusComponentNameGetDriverName,\r
+ IDEBusComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+STATIC EFI_UNICODE_STRING_TABLE mIDEBusDriverNameTable[] = {\r
+ { "eng", (CHAR16 *) L"PCI IDE/ATAPI Bus Driver" },\r
+ { NULL , NULL }\r
+};\r
+\r
+STATIC EFI_UNICODE_STRING_TABLE mIDEBusControllerNameTable[] = {\r
+ { "eng", (CHAR16 *) L"PCI IDE/ATAPI Controller" },\r
+ { NULL , NULL }\r
+};\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ @param Language A pointer to a three character ISO 639-2 language identifier.\r
+ This is the language of the driver name that that the caller\r
+ is requesting, and it must match one of the languages specified\r
+ in SupportedLanguages. The number of languages supported by a\r
+ driver is up to the driver writer.\r
+ @param DriverName A pointer to the Unicode string to return. This Unicode string\r
+ is the name of the driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by This\r
+ and the language specified by Language was returned\r
+ in DriverName.\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IDEBusComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gIDEBusComponentName.SupportedLanguages,\r
+ mIDEBusDriverNameTable,\r
+ DriverName\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by an EFI Driver.\r
+\r
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+ @param ControllerHandle The handle of a controller that the driver specified by\r
+ This is managing. This handle specifies the controller\r
+ whose name is to be returned.\r
+ @param ChildHandle The handle of the child controller to retrieve the name\r
+ of. This is an optional parameter that may be NULL. It\r
+ will be NULL for device drivers. It will also be NULL\r
+ for a bus drivers that wish to retrieve the name of the\r
+ bus controller. It will not be NULL for a bus driver\r
+ that wishes to retrieve the name of a child controller.\r
+ @param Language A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language of the controller name\r
+ that that the caller is requesting, and it must match one\r
+ of the languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up to the\r
+ driver writer.\r
+ @param ControllerName A pointer to the Unicode string to return. This Unicode\r
+ string is the name of the controller specified by\r
+ ControllerHandle and ChildHandle in the language\r
+ specified by Language from the point of view of the\r
+ driver specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in the\r
+ language specified by Language for the driver\r
+ specified by This was returned in DriverName.\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the\r
+ language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IDEBusComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;\r
+\r
+ //\r
+ // Make sure this driver is currently managing ControllHandle\r
+ //\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gIDEBusDriverBinding.DriverBindingHandle,\r
+ &gEfiIdeControllerInitProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (ChildHandle == NULL) {\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gIDEBusComponentName.SupportedLanguages,\r
+ mIDEBusControllerNameTable,\r
+ ControllerName\r
+ );\r
+ }\r
+\r
+ Status = EfiTestChildHandle (\r
+ ControllerHandle,\r
+ ChildHandle,\r
+ &gEfiPciIoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get the child context\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ gIDEBusDriverBinding.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlockIo);\r
+\r
+ return LookupUnicodeString (\r
+ Language,\r
+ gIDEBusComponentName.SupportedLanguages,\r
+ IdeBlkIoDevice->ControllerNameTable,\r
+ ControllerName\r
+ );\r
+}\r
+\r
+/**\r
+ Add the component name for the IDE/ATAPI device\r
+\r
+ @param IdeBlkIoDevicePtr A pointer to the IDE_BLK_IO_DEV instance.\r
+\r
+**/\r
+VOID\r
+AddName (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr\r
+ )\r
+{\r
+ UINTN StringIndex;\r
+ CHAR16 ModelName[41];\r
+\r
+ //\r
+ // Add Component Name for the IDE/ATAPI device that was discovered.\r
+ //\r
+ IdeBlkIoDevicePtr->ControllerNameTable = NULL;\r
+ for (StringIndex = 0; StringIndex < 41; StringIndex++) {\r
+ ModelName[StringIndex] = IdeBlkIoDevicePtr->ModelName[StringIndex];\r
+ }\r
+\r
+ AddUnicodeString (\r
+ "eng",\r
+ gIDEBusComponentName.SupportedLanguages,\r
+ &IdeBlkIoDevicePtr->ControllerNameTable,\r
+ ModelName\r
+ );\r
+}\r
--- /dev/null
+/** @file\r
+ Copyright (c) 2006, Intel Corporation\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _IDE_BUS_COMPONENT_NAME_H\r
+#define _IDE_BUS_COMPONENT_NAME_H\r
+\r
+#define ADD_NAME(x) AddName ((x));\r
+\r
+extern EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName;\r
+\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param This TODO: add argument description\r
+ @param Language TODO: add argument description\r
+ @param DriverName TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IDEBusComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param This TODO: add argument description\r
+ @param ControllerHandle TODO: add argument description\r
+ @param ChildHandle TODO: add argument description\r
+ @param Language TODO: add argument description\r
+ @param ControllerName TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IDEBusComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeBlkIoDevicePtr TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+AddName (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr\r
+ )\r
+;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ Copyright (c) 2006, Intel Corporation \r
+ All rights reserved. This program and the accompanying materials \r
+ are licensed and made available under the terms and conditions of the BSD License \r
+ which accompanies this distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+\r
+#include "idebus.h"\r
+\r
+CHAR16 *OptionString[4] = {\r
+ L"Enable Primary Master (Y/N)? -->",\r
+ L"Enable Primary Slave (Y/N)? -->",\r
+ L"Enable Secondary Master (Y/N)? -->",\r
+ L"Enable Secondary Slave (Y/N)? -->"\r
+};\r
+\r
+//\r
+// EFI Driver Configuration Protocol\r
+//\r
+EFI_DRIVER_CONFIGURATION_PROTOCOL gIDEBusDriverConfiguration = {\r
+ IDEBusDriverConfigurationSetOptions,\r
+ IDEBusDriverConfigurationOptionsValid,\r
+ IDEBusDriverConfigurationForceDefaults,\r
+ "eng"\r
+};\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @retval EFI_ABORTED TODO: Add description for return value\r
+ @retval EFI_SUCCESS TODO: Add description for return value\r
+ @retval EFI_NOT_FOUND TODO: Add description for return value\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+GetResponse (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_INPUT_KEY Key;\r
+\r
+ while (TRUE) {\r
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (Key.ScanCode == SCAN_ESC) {\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ switch (Key.UnicodeChar) {\r
+\r
+ //\r
+ // fall through\r
+ //\r
+ case L'y':\r
+ case L'Y':\r
+ gST->ConOut->OutputString (gST->ConOut, L"Y\n");\r
+ return EFI_SUCCESS;\r
+\r
+ //\r
+ // fall through\r
+ //\r
+ case L'n':\r
+ case L'N':\r
+ gST->ConOut->OutputString (gST->ConOut, L"N\n");\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Allows the user to set controller specific options for a controller that a \r
+ driver is currently managing.\r
+\r
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL\r
+ instance.\r
+ @param ControllerHandle The handle of the controller to set options on.\r
+ @param ChildHandle The handle of the child controller to set options on.\r
+ This is an optional parameter that may be NULL.\r
+ It will be NULL for device drivers, and for a bus drivers\r
+ that wish to set options for the bus controller.\r
+ It will not be NULL for a bus driver that wishes to set\r
+ options for one of its child controllers.\r
+ @param Language A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language of the user interface\r
+ that should be presented to the user, and it must match\r
+ one of the languages specified in SupportedLanguages.\r
+ The number of languages supported by a driver is up to\r
+ the driver writer.\r
+ @param ActionRequired A pointer to the action that the calling agent is\r
+ required to perform when this function returns.\r
+ See "Related Definitions" for a list of the actions that\r
+ the calling agent is required to perform prior to\r
+ accessing ControllerHandle again.\r
+\r
+ @retval EFI_SUCCESS The driver specified by This successfully set the\r
+ configuration options for the controller specified\r
+ by ControllerHandle..\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a\r
+ valid EFI_HANDLE.\r
+ @retval EFI_INVALID_PARAMETER ActionRequired is NULL.\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ setting configuration options for the controller\r
+ specified by ControllerHandle and ChildHandle.\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the\r
+ language specified by Language.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempt to set the\r
+ configuration options for the controller specified\r
+ by ControllerHandle and ChildHandle.\r
+ @retval EFI_OUT_RESOURCES There are not enough resources available to set the\r
+ configuration options for the controller specified\r
+ by ControllerHandle and ChildHandle.\r
+\r
+**/\r
+EFI_STATUS\r
+IDEBusDriverConfigurationSetOptions (\r
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Value;\r
+ UINT8 NewValue;\r
+ UINTN DataSize;\r
+ UINTN Index;\r
+\r
+ if (ChildHandle != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ *ActionRequired = EfiDriverConfigurationActionNone;\r
+\r
+ DataSize = sizeof (Value);\r
+ Status = gRT->GetVariable (\r
+ L"Configuration",\r
+ &gEfiCallerIdGuid,\r
+ NULL,\r
+ &DataSize,\r
+ &Value\r
+ );\r
+\r
+ gST->ConOut->OutputString (gST->ConOut, L"IDE Bus Driver Configuration\n");\r
+ gST->ConOut->OutputString (gST->ConOut, L"===============================\n");\r
+\r
+ NewValue = 0;\r
+ for (Index = 0; Index < 4; Index++) {\r
+ gST->ConOut->OutputString (gST->ConOut, OptionString[Index]);\r
+\r
+ Status = GetResponse ();\r
+ if (Status == EFI_ABORTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ NewValue = (UINT8) (NewValue | (1 << Index));\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status) || (NewValue != Value)) {\r
+ gRT->SetVariable (\r
+ L"Configuration",\r
+ &gEfiCallerIdGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ sizeof (NewValue),\r
+ &NewValue\r
+ );\r
+\r
+ *ActionRequired = EfiDriverConfigurationActionRestartController;\r
+ } else {\r
+ *ActionRequired = EfiDriverConfigurationActionNone;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Tests to see if a controller's current configuration options are valid.\r
+\r
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL\r
+ instance.\r
+ @param ControllerHandle The handle of the controller to test if it's current\r
+ configuration options are valid.\r
+ @param ChildHandle The handle of the child controller to test if it's\r
+ current\r
+ configuration options are valid. This is an optional\r
+ parameter that may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers that\r
+ wish to test the configuration options for the bus\r
+ controller. It will not be NULL for a bus driver that\r
+ wishes to test configuration options for one of\r
+ its child controllers.\r
+\r
+ @retval EFI_SUCCESS The controller specified by ControllerHandle and\r
+ ChildHandle that is being managed by the driver\r
+ specified by This has a valid set of configuration\r
+ options.\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+ @retval EFI_DEVICE_ERROR The controller specified by ControllerHandle and\r
+ ChildHandle that is being managed by the driver\r
+ specified by This has an invalid set of\r
+ configuration options.\r
+\r
+**/\r
+EFI_STATUS\r
+IDEBusDriverConfigurationOptionsValid (\r
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Value;\r
+ UINTN DataSize;\r
+\r
+ if (ChildHandle != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ DataSize = sizeof (Value);\r
+ Status = gRT->GetVariable (\r
+ L"Configuration",\r
+ &gEfiCallerIdGuid,\r
+ NULL,\r
+ &DataSize,\r
+ &Value\r
+ );\r
+ if (EFI_ERROR (Status) || Value > 0x0f) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Forces a driver to set the default configuration options for a controller.\r
+\r
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL\r
+ instance.\r
+ @param ControllerHandle The handle of the controller to force default\r
+ configuration options on.\r
+ @param ChildHandle The handle of the child controller to force default\r
+ configuration options on This is an optional parameter\r
+ that may be NULL. It will be NULL for device drivers.\r
+ It will also be NULL for a bus drivers that wish to\r
+ force default configuration options for the bus\r
+ controller. It will not be NULL for a bus driver that\r
+ wishes to force default configuration options for one\r
+ of its child controllers.\r
+ @param DefaultType The type of default configuration options to force on\r
+ the controller specified by ControllerHandle and\r
+ ChildHandle. See Table 9-1 for legal values.\r
+ A DefaultType of 0x00000000 must be supported\r
+ by this protocol.\r
+ @param ActionRequired A pointer to the action that the calling agent\r
+ is required to perform when this function returns.\r
+\r
+ @retval EFI_SUCCESS The driver specified by This successfully forced\r
+ the default configuration options on the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle.\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a\r
+ valid EFI_HANDLE.\r
+ @retval EFI_INVALID_PARAMETER ActionRequired is NULL.\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ forcing the default configuration options on\r
+ the controller specified by ControllerHandle\r
+ and ChildHandle.\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the configuration type specified by DefaultType.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempt to force\r
+ the default configuration options on the controller\r
+ specified by ControllerHandle and ChildHandle.\r
+ @retval EFI_OUT_RESOURCES There are not enough resources available to force\r
+ the default configuration options on the controller\r
+ specified by ControllerHandle and ChildHandle.\r
+\r
+**/\r
+EFI_STATUS\r
+IDEBusDriverConfigurationForceDefaults (\r
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN UINT32 DefaultType,\r
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired\r
+ )\r
+{\r
+ UINT8 Value;\r
+\r
+ if (ChildHandle != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Value = 0x0f;\r
+ gRT->SetVariable (\r
+ L"Configuration",\r
+ &gEfiCallerIdGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ sizeof (Value),\r
+ &Value\r
+ );\r
+ *ActionRequired = EfiDriverConfigurationActionRestartController;\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ Copyright (c) 2006, Intel Corporation \r
+ All rights reserved. This program and the accompanying materials \r
+ are licensed and made available under the terms and conditions of the BSD License \r
+ which accompanies this distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+\r
+#include "idebus.h"\r
+\r
+#define IDE_BUS_DIAGNOSTIC_ERROR L"PCI IDE/ATAPI Driver Diagnostics Failed"\r
+\r
+//\r
+// EFI Driver Diagnostics Protocol\r
+//\r
+EFI_DRIVER_DIAGNOSTICS_PROTOCOL gIDEBusDriverDiagnostics = {\r
+ IDEBusDriverDiagnosticsRunDiagnostics,\r
+ "eng"\r
+};\r
+\r
+/**\r
+ Runs diagnostics on a controller.\r
+\r
+ @param This A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOL\r
+ instance.\r
+ @param ControllerHandle The handle of the controller to run diagnostics on.\r
+ @param ChildHandle The handle of the child controller to run diagnostics on\r
+ This is an optional parameter that may be NULL. It will\r
+ be NULL for device drivers. It will also be NULL for a\r
+ bus drivers that wish to run diagnostics on the bus\r
+ controller. It will not be NULL for a bus driver that\r
+ wishes to run diagnostics on one of its child\r
+ controllers.\r
+ @param DiagnosticType Indicates type of diagnostics to perform on the\r
+ controller specified by ControllerHandle and ChildHandle.\r
+ See "Related Definitions" for the list of supported\r
+ types.\r
+ @param Language A pointer to a three character ISO 639-2 language\r
+ identifier. This is the language in which the optional\r
+ error message should be returned in Buffer, and it must\r
+ match one of the languages specified in\r
+ SupportedLanguages. The number of languages supported by\r
+ a driver is up to the driver writer.\r
+ @param ErrorType A GUID that defines the format of the data returned in\r
+ Buffer.\r
+ @param BufferSize The size, in bytes, of the data returned in Buffer.\r
+ @param Buffer A buffer that contains a Null-terminated Unicode string\r
+ plus some additional data whose format is defined by\r
+ ErrorType. Buffer is allocated by this function with\r
+ AllocatePool(), and it is the caller's responsibility\r
+ to free it with a call to FreePool().\r
+\r
+ @retval EFI_SUCCESS The controller specified by ControllerHandle and\r
+ ChildHandle passed the diagnostic.\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+ @retval EFI_INVALID_PARAMETER ErrorType is NULL.\r
+ @retval EFI_INVALID_PARAMETER BufferType is NULL.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ running diagnostics for the controller specified\r
+ by ControllerHandle and ChildHandle.\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the\r
+ type of diagnostic specified by DiagnosticType.\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the\r
+ language specified by Language.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to complete\r
+ the diagnostics.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to return\r
+ the status information in ErrorType, BufferSize,\r
+ and Buffer.\r
+ @retval EFI_DEVICE_ERROR The controller specified by ControllerHandle and\r
+ ChildHandle did not pass the diagnostic.\r
+\r
+**/\r
+EFI_STATUS\r
+IDEBusDriverDiagnosticsRunDiagnostics (\r
+ IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,\r
+ IN CHAR8 *Language,\r
+ OUT EFI_GUID **ErrorType,\r
+ OUT UINTN *BufferSize,\r
+ OUT CHAR16 **Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;\r
+ UINT32 VendorDeviceId;\r
+ VOID *BlockBuffer;\r
+\r
+ *ErrorType = NULL;\r
+ *BufferSize = 0;\r
+\r
+ if (ChildHandle == NULL) {\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiCallerIdGuid,\r
+ NULL,\r
+ gIDEBusDriverBinding.DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ gIDEBusDriverBinding.DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Use services of PCI I/O Protocol to test the PCI IDE/ATAPI Controller\r
+ // The following test simply reads the Device ID and Vendor ID.\r
+ // It should never fail. A real test would perform more advanced\r
+ // diagnostics.\r
+ //\r
+\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, 1, &VendorDeviceId);\r
+ if (EFI_ERROR (Status) || VendorDeviceId == 0xffffffff) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlkIo,\r
+ gIDEBusDriverBinding.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo);\r
+\r
+ //\r
+ // Use services available from IdeBlkIoDevice to test the IDE/ATAPI device\r
+ //\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ IdeBlkIoDevice->BlkMedia.BlockSize,\r
+ (VOID **) &BlockBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = IdeBlkIoDevice->BlkIo.ReadBlocks (\r
+ &IdeBlkIoDevice->BlkIo,\r
+ IdeBlkIoDevice->BlkMedia.MediaId,\r
+ 0,\r
+ IdeBlkIoDevice->BlkMedia.BlockSize,\r
+ BlockBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ *ErrorType = &gEfiCallerIdGuid;\r
+ *BufferSize = sizeof (IDE_BUS_DIAGNOSTIC_ERROR);\r
+\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ (UINTN) (*BufferSize),\r
+ (VOID **) Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ CopyMem (*Buffer, IDE_BUS_DIAGNOSTIC_ERROR, *BufferSize);\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ gBS->FreePool (BlockBuffer);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ Copyright (c) 2006 - 2007 Intel Corporation. <BR>\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+ @par Revision Reference:\r
+ 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including\r
+ update - ATAIdentity() func\r
+ update - AtaBlockIoReadBlocks() func\r
+ update - AtaBlockIoWriteBlocks() func\r
+ add - AtaAtapi6Identify() func\r
+ add - AtaReadSectorsExt() func\r
+ add - AtaWriteSectorsExt() func\r
+ add - AtaPioDataInExt() func\r
+ add - AtaPioDataOutExt() func\r
+\r
+**/\r
+\r
+#include "idebus.h"\r
+\r
+/**\r
+ Sends out an ATA Identify Command to the specified device.\r
+\r
+ This function is called by DiscoverIdeDevice() during its device\r
+ identification. It sends out the ATA Identify Command to the\r
+ specified device. Only ATA device responses to this command. If\r
+ the command succeeds, it returns the Identify data structure which\r
+ contains information about the device. This function extracts the\r
+ information it needs to fill the IDE_BLK_IO_DEV data structure,\r
+ including device type, media block size, media capacity, and etc.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+ to record all the information of the IDE device.\r
+\r
+ @retval EFI_SUCCESS Identify ATA device successfully.\r
+\r
+ @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or\r
+ device is not ATA device.\r
+\r
+ @note\r
+ parameter IdeDev will be updated in this function.\r
+\r
+**/\r
+EFI_STATUS\r
+ATAIdentify (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_IDENTIFY_DATA *AtaIdentifyPointer;\r
+ UINT32 Capacity;\r
+ UINT8 DeviceSelect;\r
+\r
+ //\r
+ // AtaIdentifyPointer is used for accommodating returned IDENTIFY data of\r
+ // the ATA Identify command\r
+ //\r
+ AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
+\r
+ //\r
+ // use ATA PIO Data In protocol to send ATA Identify command\r
+ // and receive data from device\r
+ //\r
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
+ Status = AtaPioDataIn (\r
+ IdeDev,\r
+ (VOID *) AtaIdentifyPointer,\r
+ sizeof (EFI_IDENTIFY_DATA),\r
+ IDENTIFY_DRIVE_CMD,\r
+ DeviceSelect,\r
+ 0,\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+ //\r
+ // If ATA Identify command succeeds, then according to the received\r
+ // IDENTIFY data,\r
+ // identify the device type ( ATA or not ).\r
+ // If ATA device, fill the information in IdeDev.\r
+ // If not ATA device, return IDE_DEVICE_ERROR\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ IdeDev->pIdData = AtaIdentifyPointer;\r
+\r
+ //\r
+ // Print ATA Module Name\r
+ //\r
+ PrintAtaModuleName (IdeDev);\r
+\r
+ //\r
+ // bit 15 of pAtaIdentify->config is used to identify whether device is\r
+ // ATA device or ATAPI device.\r
+ // if 0, means ATA device; if 1, means ATAPI device.\r
+ //\r
+ if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) {\r
+ //\r
+ // Detect if support S.M.A.R.T. If yes, enable it as default\r
+ //\r
+ AtaSMARTSupport (IdeDev);\r
+\r
+ //\r
+ // Check whether this device needs 48-bit addressing (ATAPI-6 ata device)\r
+ //\r
+ Status = AtaAtapi6Identify (IdeDev);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify()\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // This is a hard disk <= 120GB capacity, treat it as normal hard disk\r
+ //\r
+ IdeDev->Type = IdeHardDisk;\r
+\r
+ //\r
+ // Block Media Information:\r
+ // Media->LogicalPartition , Media->WriteCaching will be filled\r
+ // in the DiscoverIdeDevcie() function.\r
+ //\r
+ IdeDev->BlkIo.Media->IoAlign = 4;\r
+ IdeDev->BlkIo.Media->MediaId = 1;\r
+ IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
+ IdeDev->BlkIo.Media->ReadOnly = FALSE;\r
+ IdeDev->BlkIo.Media->BlockSize = 0x200;\r
+\r
+ //\r
+ // Calculate device capacity\r
+ //\r
+ Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) |\r
+ AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ;\r
+ IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ }\r
+ }\r
+\r
+ gBS->FreePool (AtaIdentifyPointer);\r
+ //\r
+ // Make sure the pIdData will not be freed again.\r
+ //\r
+ IdeDev->pIdData = NULL;\r
+\r
+ return EFI_DEVICE_ERROR;\r
+}\r
+\r
+\r
+/**\r
+ This function is called by ATAIdentify() to identity whether this disk\r
+ supports ATA/ATAPI6 48bit addressing, ie support >120G capacity\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @retval EFI_SUCCESS The disk specified by IdeDev is a Atapi6 supported one\r
+ and 48-bit addressing must be used\r
+\r
+ @retval EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but\r
+ the capacity is below 120G, 48bit addressing is not\r
+ needed\r
+\r
+ @note\r
+ This function must be called after DEVICE_IDENTITY command has been\r
+ successfully returned\r
+\r
+**/\r
+EFI_STATUS\r
+AtaAtapi6Identify (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ UINT8 Index;\r
+ EFI_LBA TmpLba;\r
+ EFI_LBA Capacity;\r
+ EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;\r
+\r
+ if (IdeDev->pIdData == NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Atapi6IdentifyStruct = IdeDev->pIdData;\r
+\r
+ if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & bit10) == 0) {\r
+ //\r
+ // The device dosn't support 48 bit addressing\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // 48 bit address feature set is supported, get maximum capacity\r
+ //\r
+ Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0];\r
+ for (Index = 1; Index < 4; Index++) {\r
+ //\r
+ // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r
+ //\r
+ TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index];\r
+ Capacity |= LShiftU64 (TmpLba, 16 * Index);\r
+ }\r
+\r
+ if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {\r
+ //\r
+ // Capacity exceeds 120GB. 48-bit addressing is really needed\r
+ //\r
+ IdeDev->Type = Ide48bitAddressingHardDisk;\r
+\r
+ //\r
+ // Fill block media information:Media->LogicalPartition ,\r
+ // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.\r
+ //\r
+ IdeDev->BlkIo.Media->IoAlign = 4;\r
+ IdeDev->BlkIo.Media->MediaId = 1;\r
+ IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
+ IdeDev->BlkIo.Media->ReadOnly = FALSE;\r
+ IdeDev->BlkIo.Media->BlockSize = 0x200;\r
+ IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ This function is called by ATAIdentify() or ATAPIIdentify()\r
+ to print device's module name.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+**/\r
+VOID\r
+PrintAtaModuleName (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ if (IdeDev->pIdData == NULL) {\r
+ return ;\r
+ }\r
+\r
+ SwapStringChars (IdeDev->ModelName, IdeDev->pIdData->AtaData.ModelName, 40);\r
+ IdeDev->ModelName[40] = 0x00;\r
+}\r
+\r
+/**\r
+ This function is used to send out ATA commands conforms to the\r
+ PIO Data In Protocol.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Buffer\r
+ buffer contained data transferred from device to host.\r
+\r
+ @param[in] ByteCount\r
+ data size in byte unit of the buffer.\r
+\r
+ @param[in] AtaCommand\r
+ value of the Command Register\r
+\r
+ @param[in] Head\r
+ value of the Head/Device Register\r
+\r
+ @param[in] SectorCount\r
+ value of the Sector Count Register\r
+\r
+ @param[in] SectorNumber\r
+ value of the Sector Number Register\r
+\r
+ @param[in] CylinderLsb\r
+ value of the low byte of the Cylinder Register\r
+\r
+ @param[in] CylinderMsb\r
+ value of the high byte of the Cylinder Register\r
+\r
+ @retval EFI_SUCCESS send out the ATA command and device send required\r
+ data successfully.\r
+\r
+ @retval EFI_DEVICE_ERROR command sent failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataIn (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Head,\r
+ IN UINT8 SectorCount,\r
+ IN UINT8 SectorNumber,\r
+ IN UINT8 CylinderLsb,\r
+ IN UINT8 CylinderMsb\r
+ )\r
+{\r
+ UINTN WordCount;\r
+ UINTN Increment;\r
+ UINT16 *Buffer16;\r
+ EFI_STATUS Status;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // e0:1110,0000-- bit7 and bit5 are reserved bits.\r
+ // bit6 set means LBA mode\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)\r
+ );\r
+\r
+ //\r
+ // All ATAPI device's ATA commands can be issued regardless of the\r
+ // state of the DRDY\r
+ //\r
+ if (IdeDev->Type == IdeHardDisk) {\r
+\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ //\r
+ // set all the command parameters\r
+ // Before write to all the following registers, BSY and DRQ must be 0.\r
+ //\r
+ Status = DRQClear2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (AtaCommand == SET_FEATURES_CMD) {\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
+ }\r
+\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);\r
+\r
+ //\r
+ // send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ Buffer16 = (UINT16 *) Buffer;\r
+\r
+ //\r
+ // According to PIO data in protocol, host can perform a series of reads to\r
+ // the data register after each time device set DRQ ready;\r
+ // The data size of "a series of read" is command specific.\r
+ // For most ATA command, data size received from device will not exceed\r
+ // 1 sector, hence the data size for "a series of read" can be the whole data\r
+ // size of one command request.\r
+ // For ATA command such as Read Sector command, the data size of one ATA\r
+ // command request is often larger than 1 sector, according to the\r
+ // Read Sector command, the data size of "a series of read" is exactly 1\r
+ // sector.\r
+ // Here for simplification reason, we specify the data size for\r
+ // "a series of read" to 1 sector (256 words) if data size of one ATA command\r
+ // request is larger than 256 words.\r
+ //\r
+ Increment = 256;\r
+\r
+ //\r
+ // used to record bytes of currently transfered data\r
+ //\r
+ WordCount = 0;\r
+\r
+ while (WordCount < ByteCount / 2) {\r
+ //\r
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+ //\r
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = CheckErrorStatus (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Get the byte count for one series of read\r
+ //\r
+ if ((WordCount + Increment) > ByteCount / 2) {\r
+ Increment = ByteCount / 2 - WordCount;\r
+ }\r
+\r
+ IDEReadPortWMultiple (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Data,\r
+ Increment,\r
+ Buffer16\r
+ );\r
+\r
+ WordCount += Increment;\r
+ Buffer16 += Increment;\r
+\r
+ }\r
+\r
+ DRQClear (IdeDev, ATATIMEOUT);\r
+\r
+ return CheckErrorStatus (IdeDev);\r
+}\r
+\r
+/**\r
+ This function is used to send out ATA commands conforms to the\r
+ PIO Data Out Protocol.\r
+\r
+ @param *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param *Buffer buffer contained data transferred from host to device.\r
+ @param ByteCount data size in byte unit of the buffer.\r
+ @param AtaCommand value of the Command Register\r
+ @param Head value of the Head/Device Register\r
+ @param SectorCount value of the Sector Count Register\r
+ @param SectorNumber value of the Sector Number Register\r
+ @param CylinderLsb value of the low byte of the Cylinder Register\r
+ @param CylinderMsb value of the high byte of the Cylinder Register\r
+\r
+ @retval EFI_SUCCESS send out the ATA command and device received required\r
+ data successfully.\r
+\r
+ @retval EFI_DEVICE_ERROR command sent failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataOut (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Head,\r
+ IN UINT8 SectorCount,\r
+ IN UINT8 SectorNumber,\r
+ IN UINT8 CylinderLsb,\r
+ IN UINT8 CylinderMsb\r
+ )\r
+{\r
+ UINTN WordCount;\r
+ UINTN Increment;\r
+ UINT16 *Buffer16;\r
+ EFI_STATUS Status;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // select device via Head/Device register.\r
+ // Before write Head/Device register, BSY and DRQ must be 0.\r
+ //\r
+ Status = DRQClear2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // e0:1110,0000-- bit7 and bit5 are reserved bits.\r
+ // bit6 set means LBA mode\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)\r
+ );\r
+\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // set all the command parameters\r
+ // Before write to all the following registers, BSY and DRQ must be 0.\r
+ //\r
+ Status = DRQClear2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);\r
+\r
+ //\r
+ // send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ Buffer16 = (UINT16 *) Buffer;\r
+\r
+ //\r
+ // According to PIO data out protocol, host can perform a series of\r
+ // writes to the data register after each time device set DRQ ready;\r
+ // The data size of "a series of read" is command specific.\r
+ // For most ATA command, data size written to device will not exceed 1 sector,\r
+ // hence the data size for "a series of write" can be the data size of one\r
+ // command request.\r
+ // For ATA command such as Write Sector command, the data size of one\r
+ // ATA command request is often larger than 1 sector, according to the\r
+ // Write Sector command, the data size of "a series of read" is exactly\r
+ // 1 sector.\r
+ // Here for simplification reason, we specify the data size for\r
+ // "a series of write" to 1 sector (256 words) if data size of one ATA command\r
+ // request is larger than 256 words.\r
+ //\r
+ Increment = 256;\r
+ WordCount = 0;\r
+\r
+ while (WordCount < ByteCount / 2) {\r
+\r
+ //\r
+ // DRQReady2-- read Alternate Status Register to determine the DRQ bit\r
+ // data transfer can be performed only when DRQ is ready.\r
+ //\r
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = CheckErrorStatus (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Check the remaining byte count is less than 512 bytes\r
+ //\r
+ if ((WordCount + Increment) > ByteCount / 2) {\r
+ Increment = ByteCount / 2 - WordCount;\r
+ }\r
+ //\r
+ // perform a series of write without check DRQ ready\r
+ //\r
+\r
+ IDEWritePortWMultiple (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Data,\r
+ Increment,\r
+ Buffer16\r
+ );\r
+ WordCount += Increment;\r
+ Buffer16 += Increment;\r
+\r
+ }\r
+\r
+ DRQClear (IdeDev, ATATIMEOUT);\r
+\r
+ return CheckErrorStatus (IdeDev);\r
+}\r
+\r
+/**\r
+ This function is used to analyze the Status Register and print out\r
+ some debug information and if there is ERR bit set in the Status\r
+ Register, the Error Register's value is also be parsed and print out.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @retval EFI_SUCCESS No err information in the Status Register.\r
+ @retval EFI_DEVICE_ERROR Any err information in the Status Register.\r
+\r
+**/\r
+EFI_STATUS\r
+CheckErrorStatus (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ UINT8 StatusRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+ DEBUG_CODE_BEGIN ();\r
+\r
+ if (StatusRegister & DWF) {\r
+ DEBUG (\r
+ (EFI_D_BLKIO,\r
+ "CheckErrorStatus()-- %02x : Error : Write Fault\n",\r
+ StatusRegister)\r
+ );\r
+ }\r
+\r
+ if (StatusRegister & CORR) {\r
+ DEBUG (\r
+ (EFI_D_BLKIO,\r
+ "CheckErrorStatus()-- %02x : Error : Corrected Data\n",\r
+ StatusRegister)\r
+ );\r
+ }\r
+\r
+ if (StatusRegister & ERR) {\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+\r
+ if (ErrorRegister & BBK_ERR) {\r
+ DEBUG (\r
+ (EFI_D_BLKIO,\r
+ "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",\r
+ ErrorRegister)\r
+ );\r
+ }\r
+\r
+ if (ErrorRegister & UNC_ERR) {\r
+ DEBUG (\r
+ (EFI_D_BLKIO,\r
+ "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",\r
+ ErrorRegister)\r
+ );\r
+ }\r
+\r
+ if (ErrorRegister & MC_ERR) {\r
+ DEBUG (\r
+ (EFI_D_BLKIO,\r
+ "CheckErrorStatus()-- %02x : Error : Media Change\n",\r
+ ErrorRegister)\r
+ );\r
+ }\r
+\r
+ if (ErrorRegister & ABRT_ERR) {\r
+ DEBUG (\r
+ (EFI_D_BLKIO,\r
+ "CheckErrorStatus()-- %02x : Error : Abort\n",\r
+ ErrorRegister)\r
+ );\r
+ }\r
+\r
+ if (ErrorRegister & TK0NF_ERR) {\r
+ DEBUG (\r
+ (EFI_D_BLKIO,\r
+ "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",\r
+ ErrorRegister)\r
+ );\r
+ }\r
+\r
+ if (ErrorRegister & AMNF_ERR) {\r
+ DEBUG (\r
+ (EFI_D_BLKIO,\r
+ "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",\r
+ ErrorRegister)\r
+ );\r
+ }\r
+ }\r
+\r
+ DEBUG_CODE_END ();\r
+\r
+ if ((StatusRegister & (ERR | DWF | CORR)) == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_DEVICE_ERROR;\r
+\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoReadBlocks() to perform\r
+ reading from media in block unit.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer\r
+ A pointer to the destination buffer for the data.\r
+\r
+ @param[in] Lba\r
+ The starting logical block address to read from\r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+\r
+ @return return status is fully dependent on the return status\r
+ of AtaPioDataIn() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaReadSectors (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BlocksRemaining;\r
+ UINT32 Lba32;\r
+ UINT8 Lba0;\r
+ UINT8 Lba1;\r
+ UINT8 Lba2;\r
+ UINT8 Lba3;\r
+ UINT8 AtaCommand;\r
+ UINT8 SectorCount8;\r
+ UINT16 SectorCount;\r
+ UINTN ByteCount;\r
+ VOID *Buffer;\r
+\r
+ Buffer = DataBuffer;\r
+\r
+ //\r
+ // Using ATA Read Sector(s) command (opcode=0x20) with PIO DATA IN protocol\r
+ //\r
+ AtaCommand = READ_SECTORS_CMD;\r
+\r
+\r
+ BlocksRemaining = NumberOfBlocks;\r
+\r
+ Lba32 = (UINT32) Lba;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ while (BlocksRemaining > 0) {\r
+\r
+ //\r
+ // in ATA-3 spec, LBA is in 28 bit width\r
+ //\r
+ Lba0 = (UINT8) Lba32;\r
+ Lba1 = (UINT8) (Lba32 >> 8);\r
+ Lba2 = (UINT8) (Lba32 >> 16);\r
+ //\r
+ // low 4 bit of Lba3 stands for LBA bit24~bit27.\r
+ //\r
+ Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);\r
+\r
+ if (BlocksRemaining >= 0x100) {\r
+\r
+ //\r
+ // SectorCount8 is sent to Sector Count register, 0x00 means 256\r
+ // sectors to be read\r
+ //\r
+ SectorCount8 = 0x00;\r
+ //\r
+ // SectorCount is used to record the number of sectors to be read\r
+ //\r
+ SectorCount = 256;\r
+ } else {\r
+\r
+ SectorCount8 = (UINT8) BlocksRemaining;\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ }\r
+\r
+ //\r
+ // ByteCount is the number of bytes that will be read\r
+ //\r
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+\r
+ //\r
+ // call AtaPioDataIn() to send Read Sector Command and receive data read\r
+ //\r
+ Status = AtaPioDataIn (\r
+ IdeDev,\r
+ Buffer,\r
+ (UINT32) ByteCount,\r
+ AtaCommand,\r
+ Lba3,\r
+ SectorCount8,\r
+ Lba0,\r
+ Lba1,\r
+ Lba2\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Lba32 += SectorCount;\r
+ Buffer = ((UINT8 *) Buffer + ByteCount);\r
+ BlocksRemaining -= SectorCount;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoWriteBlocks() to perform\r
+ writing onto media in block unit.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *BufferData\r
+ A pointer to the source buffer for the data.\r
+\r
+ @param[in] Lba\r
+ The starting logical block address to write onto\r
+ the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+\r
+ @return return status is fully dependent on the return status\r
+ of AtaPioDataOut() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaWriteSectors (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *BufferData,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BlocksRemaining;\r
+ UINT32 Lba32;\r
+ UINT8 Lba0;\r
+ UINT8 Lba1;\r
+ UINT8 Lba2;\r
+ UINT8 Lba3;\r
+ UINT8 AtaCommand;\r
+ UINT8 SectorCount8;\r
+ UINT16 SectorCount;\r
+ UINTN ByteCount;\r
+ VOID *Buffer;\r
+\r
+ Buffer = BufferData;\r
+\r
+ //\r
+ // Using Write Sector(s) command (opcode=0x30) with PIO DATA OUT protocol\r
+ //\r
+ AtaCommand = WRITE_SECTORS_CMD;\r
+\r
+ BlocksRemaining = NumberOfBlocks;\r
+\r
+ Lba32 = (UINT32) Lba;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ while (BlocksRemaining > 0) {\r
+\r
+ Lba0 = (UINT8) Lba32;\r
+ Lba1 = (UINT8) (Lba32 >> 8);\r
+ Lba2 = (UINT8) (Lba32 >> 16);\r
+ Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);\r
+\r
+ if (BlocksRemaining >= 0x100) {\r
+\r
+ //\r
+ // SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors\r
+ // to be written\r
+ //\r
+ SectorCount8 = 0x00;\r
+ //\r
+ // SectorCount is used to record the number of sectors to be written\r
+ //\r
+ SectorCount = 256;\r
+ } else {\r
+\r
+ SectorCount8 = (UINT8) BlocksRemaining;\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ }\r
+\r
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+\r
+ Status = AtaPioDataOut (\r
+ IdeDev,\r
+ Buffer,\r
+ (UINT32) ByteCount,\r
+ AtaCommand,\r
+ Lba3,\r
+ SectorCount8,\r
+ Lba0,\r
+ Lba1,\r
+ Lba2\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Lba32 += SectorCount;\r
+ Buffer = ((UINT8 *) Buffer + ByteCount);\r
+ BlocksRemaining -= SectorCount;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function is used to implement the Soft Reset on the specified\r
+ device. But, the ATA Soft Reset mechanism is so strong a reset method\r
+ that it will force resetting on both devices connected to the\r
+ same cable.\r
+\r
+ It is called by IdeBlkIoReset(), a interface function of Block\r
+ I/O protocol.\r
+\r
+ This function can also be used by the ATAPI device to perform reset when\r
+ ATAPI Reset command is failed.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @retval EFI_SUCCESS Soft reset completes successfully.\r
+ @retval EFI_DEVICE_ERROR Any step during the reset process is failed.\r
+\r
+ @note\r
+ The registers initial values after ATA soft reset are different\r
+ to the ATA device and ATAPI device.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaSoftReset (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+\r
+ UINT8 DeviceControl;\r
+\r
+ DeviceControl = 0;\r
+ //\r
+ // set SRST bit to initiate soft reset\r
+ //\r
+ DeviceControl |= SRST;\r
+\r
+ //\r
+ // disable Interrupt\r
+ //\r
+ DeviceControl |= bit1;\r
+\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+ //\r
+ // SRST should assert for at least 5 us, we use 10 us for\r
+ // better compatibility\r
+ //\r
+ gBS->Stall (10);\r
+\r
+ //\r
+ // Enable interrupt to support UDMA, and clear SRST bit\r
+ //\r
+ DeviceControl = 0;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+ //\r
+ // Wait for at least 2 ms to check BSY status, we use 10 ms\r
+ // for better compatibility\r
+ //\r
+ gBS->Stall(10000);\r
+ //\r
+ // slave device needs at most 31s to clear BSY\r
+ //\r
+ if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is the ATA implementation for ReadBlocks in the\r
+ Block I/O Protocol interface.\r
+\r
+ @param[in] *IdeBlkIoDevice\r
+ Indicates the calling context.\r
+\r
+ @param[in] MediaId\r
+ The media id that the read request is for.\r
+\r
+ @param[in] LBA\r
+ The starting logical block address to read from\r
+ on the device.\r
+\r
+ @param[in] BufferSize\r
+ The size of the Buffer in bytes. This must be a\r
+ multiple of the intrinsic block size of the device.\r
+\r
+ @param[out] *Buffer\r
+ A pointer to the destination buffer for the data.\r
+ The caller is responsible for either having implicit\r
+ or explicit ownership of the memory that data is read into.\r
+\r
+ @retval EFI_SUCCESS Read Blocks successfully.\r
+ @retval EFI_DEVICE_ERROR Read Blocks failed.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.\r
+\r
+ @retval EFI_BAD_BUFFER_SIZE\r
+ The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+\r
+ @retval EFI_INVALID_PARAMETER\r
+ The read request contains LBAs that are not valid,\r
+ or the data buffer is not valid.\r
+\r
+ @note\r
+ If Read Block error because of device error, this function will call\r
+ AtaSoftReset() function to reset device.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaBlkIoReadBlocks (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ EFI_STATUS Status;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Get the intrinsic block size\r
+ //\r
+ Media = IdeBlkIoDevice->BlkIo.Media;\r
+ BlockSize = Media->BlockSize;\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (BufferSize % BlockSize != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (!(Media->MediaPresent)) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ if (LBA > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
+ //\r
+ // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism\r
+ //\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ } else {\r
+ Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ }\r
+ } else {\r
+ //\r
+ // For ATA-3 compatible device, use ATA-3 read block mechanism\r
+ //\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ } else {\r
+ Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ AtaSoftReset (IdeBlkIoDevice);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+ This function is the ATA implementation for WriteBlocks in the\r
+ Block I/O Protocol interface.\r
+\r
+ @param[in] *IdeBlkIoDevice\r
+ Indicates the calling context.\r
+\r
+ @param[in] MediaId\r
+ The media id that the write request is for.\r
+\r
+ @param[in] LBA\r
+ The starting logical block address to write onto\r
+ the device.\r
+\r
+ @param[in] BufferSize\r
+ The size of the Buffer in bytes. This must be a\r
+ multiple of the intrinsic block size of the device.\r
+\r
+ @param[out] *Buffer\r
+ A pointer to the source buffer for the data.\r
+ The caller is responsible for either having implicit\r
+ or explicit ownership of the memory that data is\r
+ written from.\r
+\r
+ @retval EFI_SUCCESS Write Blocks successfully.\r
+ @retval EFI_DEVICE_ERROR Write Blocks failed.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.\r
+\r
+ @retval EFI_BAD_BUFFER_SIZE\r
+ The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+\r
+ @retval EFI_INVALID_PARAMETER\r
+ The write request contains LBAs that are not valid,\r
+ or the data buffer is not valid.\r
+\r
+ @note\r
+ If Write Block error because of device error, this function will call\r
+ AtaSoftReset() function to reset device.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaBlkIoWriteBlocks (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ EFI_STATUS Status;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Get the intrinsic block size\r
+ //\r
+ Media = IdeBlkIoDevice->BlkIo.Media;\r
+ BlockSize = Media->BlockSize;\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (BufferSize % BlockSize != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (LBA > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
+ //\r
+ // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism\r
+ //\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ } else {\r
+ Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ }\r
+ } else {\r
+ //\r
+ // For ATA-3 compatible device, use ATA-3 write block mechanism\r
+ //\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ } else {\r
+ Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ AtaSoftReset (IdeBlkIoDevice);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoReadBlocks() to perform\r
+ reading from media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer A pointer to the destination buffer for the data.\r
+ @param[in] StartLba The starting logical block address to read from\r
+ on the device media.\r
+ @param[in] NumberOfBlocks The number of transfer data blocks.\r
+\r
+ @return return status is fully dependent on the return status\r
+ of AtaPioDataInExt() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaReadSectorsExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BlocksRemaining;\r
+ EFI_LBA Lba64;\r
+ UINT8 AtaCommand;\r
+ UINT16 SectorCount;\r
+ UINT32 ByteCount;\r
+ VOID *Buffer;\r
+\r
+ //\r
+ // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol\r
+ //\r
+ AtaCommand = READ_SECTORS_EXT_CMD;\r
+ Buffer = DataBuffer;\r
+ BlocksRemaining = NumberOfBlocks;\r
+ Lba64 = StartLba;\r
+ Status = EFI_SUCCESS;\r
+\r
+ while (BlocksRemaining > 0) {\r
+\r
+ if (BlocksRemaining >= 0x10000) {\r
+ //\r
+ // SectorCount is used to record the number of sectors to be read\r
+ // Max 65536 sectors can be transfered at a time.\r
+ //\r
+ SectorCount = 0xffff;\r
+ } else {\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ }\r
+\r
+ //\r
+ // ByteCount is the number of bytes that will be read\r
+ //\r
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+\r
+ //\r
+ // call AtaPioDataInExt() to send Read Sector Command and receive data read\r
+ //\r
+ Status = AtaPioDataInExt (\r
+ IdeDev,\r
+ Buffer,\r
+ ByteCount,\r
+ AtaCommand,\r
+ Lba64,\r
+ SectorCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Lba64 += SectorCount;\r
+ Buffer = ((UINT8 *) Buffer + ByteCount);\r
+ BlocksRemaining -= SectorCount;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoWriteBlocks() to perform\r
+ writing onto media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer\r
+ A pointer to the source buffer for the data.\r
+\r
+ @param[in] Lba\r
+ The starting logical block address to write onto\r
+ the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+\r
+ @return status is fully dependent on the return status\r
+ of AtaPioDataOutExt() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaWriteSectorsExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_LBA Lba64;\r
+ UINTN BlocksRemaining;\r
+ UINT8 AtaCommand;\r
+ UINT16 SectorCount;\r
+ UINT32 ByteCount;\r
+ VOID *Buffer;\r
+\r
+ //\r
+ // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol\r
+ //\r
+ AtaCommand = WRITE_SECTORS_EXT_CMD;\r
+ Lba64 = StartLba;\r
+ Buffer = DataBuffer;\r
+ BlocksRemaining = NumberOfBlocks;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ while (BlocksRemaining > 0) {\r
+\r
+ if (BlocksRemaining >= 0x10000) {\r
+ //\r
+ // SectorCount is used to record the number of sectors to be written.\r
+ // Max 65536 sectors can be transfered at a time.\r
+ //\r
+ SectorCount = 0xffff;\r
+ } else {\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ }\r
+\r
+ //\r
+ // ByteCount is the number of bytes that will be written\r
+ //\r
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+\r
+ //\r
+ // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command\r
+ //\r
+ Status = AtaPioDataOutExt (\r
+ IdeDev,\r
+ Buffer,\r
+ ByteCount,\r
+ AtaCommand,\r
+ Lba64,\r
+ SectorCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Lba64 += SectorCount;\r
+ Buffer = ((UINT8 *) Buffer + ByteCount);\r
+ BlocksRemaining -= SectorCount;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function is used to send out ATA commands conforms to the\r
+ PIO Data In Protocol, supporting ATA/ATAPI-6 standard\r
+\r
+ Comparing with ATA-3 data in protocol, we have two differents here:<BR>\r
+ 1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
+ wait will frequently fail... cause writing function return error)\r
+\r
+ 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
+ slow down writing performance by 100 times!)\r
+\r
+ @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in,out] *Buffer buffer contained data transferred from device to host.\r
+ @param[in] ByteCount data size in byte unit of the buffer.\r
+ @param[in] AtaCommand value of the Command Register\r
+ @param[in] StartLba the start LBA of this transaction\r
+ @param[in] SectorCount the count of sectors to be transfered\r
+\r
+ @retval EFI_SUCCESS send out the ATA command and device send required\r
+ data successfully.\r
+\r
+ @retval EFI_DEVICE_ERROR command sent failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataInExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN OUT VOID *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINT8 AtaCommand,\r
+ IN EFI_LBA StartLba,\r
+ IN UINT16 SectorCount\r
+ )\r
+{\r
+ UINT8 DevSel;\r
+ UINT8 SectorCount8;\r
+ UINT8 LbaLow;\r
+ UINT8 LbaMid;\r
+ UINT8 LbaHigh;\r
+ UINTN WordCount;\r
+ UINTN Increment;\r
+ UINT16 *Buffer16;\r
+ EFI_STATUS Status;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Select device, set bit6 as 1 to indicate LBA mode is used\r
+ //\r
+ DevSel = (UINT8) (IdeDev->Device << 4);\r
+ DevSel |= 0x40;\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ DevSel\r
+ );\r
+\r
+ //\r
+ // Wait for DRDY singnal asserting. ATAPI device needn't wait\r
+ //\r
+ if ( (IdeDev->Type == IdeHardDisk) ||\r
+ (IdeDev->Type == Ide48bitAddressingHardDisk)) {\r
+\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Fill feature register if needed\r
+ //\r
+ if (AtaCommand == SET_FEATURES_CMD) {\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
+ }\r
+\r
+ //\r
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ SectorCount8 = (UINT8) (SectorCount >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ SectorCount8 = (UINT8) SectorCount;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ //\r
+ // Fill the start LBA registers, which are also two-byte FIFO\r
+ //\r
+ LbaLow = (UINT8) RShiftU64 (StartLba, 24);\r
+ LbaMid = (UINT8) RShiftU64 (StartLba, 32);\r
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ LbaLow = (UINT8) StartLba;\r
+ LbaMid = (UINT8) RShiftU64 (StartLba, 8);\r
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ //\r
+ // Send command via Command Register, invoking the processing of this command\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ Buffer16 = (UINT16 *) Buffer;\r
+\r
+ //\r
+ // According to PIO data in protocol, host can perform a series of reads to\r
+ // the data register after each time device set DRQ ready;\r
+ //\r
+\r
+ //\r
+ // 256 words\r
+ //\r
+ Increment = 256;\r
+\r
+ //\r
+ // used to record bytes of currently transfered data\r
+ //\r
+ WordCount = 0;\r
+\r
+ while (WordCount < ByteCount / 2) {\r
+ //\r
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+ //\r
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = CheckErrorStatus (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Get the byte count for one series of read\r
+ //\r
+ if ((WordCount + Increment) > ByteCount / 2) {\r
+ Increment = ByteCount / 2 - WordCount;\r
+ }\r
+\r
+ IDEReadPortWMultiple (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Data,\r
+ Increment,\r
+ Buffer16\r
+ );\r
+\r
+ WordCount += Increment;\r
+ Buffer16 += Increment;\r
+\r
+ }\r
+\r
+ return CheckErrorStatus (IdeDev);\r
+}\r
+\r
+/**\r
+ This function is used to send out ATA commands conforms to the\r
+ PIO Data Out Protocol, supporting ATA/ATAPI-6 standard\r
+\r
+ Comparing with ATA-3 data out protocol, we have two differents here:<BR>\r
+ 1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
+ wait will frequently fail... cause writing function return error)\r
+\r
+ 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
+ slow down writing performance by 100 times!)\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Buffer buffer contained data transferred from host to device.\r
+ @param[in] ByteCount data size in byte unit of the buffer.\r
+ @param[in] AtaCommand value of the Command Register\r
+ @param[in] StartLba the start LBA of this transaction\r
+ @param[in] SectorCount the count of sectors to be transfered\r
+\r
+ @retval EFI_SUCCESS send out the ATA command and device receive required\r
+ data successfully.\r
+\r
+ @retval EFI_DEVICE_ERROR command sent failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataOutExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINT8 AtaCommand,\r
+ IN EFI_LBA StartLba,\r
+ IN UINT16 SectorCount\r
+ )\r
+{\r
+ UINT8 DevSel;\r
+ UINT8 SectorCount8;\r
+ UINT8 LbaLow;\r
+ UINT8 LbaMid;\r
+ UINT8 LbaHigh;\r
+ UINTN WordCount;\r
+ UINTN Increment;\r
+ UINT16 *Buffer16;\r
+ EFI_STATUS Status;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Select device. Set bit6 as 1 to indicate LBA mode is used\r
+ //\r
+ DevSel = (UINT8) (IdeDev->Device << 4);\r
+ DevSel |= 0x40;\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ DevSel\r
+ );\r
+\r
+ //\r
+ // Wait for DRDY singnal asserting.\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Fill feature register if needed\r
+ //\r
+ if (AtaCommand == SET_FEATURES_CMD) {\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
+ }\r
+\r
+ //\r
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ SectorCount8 = (UINT8) (SectorCount >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ SectorCount8 = (UINT8) SectorCount;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ //\r
+ // Fill the start LBA registers, which are also two-byte FIFO\r
+ //\r
+ LbaLow = (UINT8) RShiftU64 (StartLba, 24);\r
+ LbaMid = (UINT8) RShiftU64 (StartLba, 32);\r
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ LbaLow = (UINT8) StartLba;\r
+ LbaMid = (UINT8) RShiftU64 (StartLba, 8);\r
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ //\r
+ // Send command via Command Register, invoking the processing of this command\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ Buffer16 = (UINT16 *) Buffer;\r
+\r
+ //\r
+ // According to PIO Data Out protocol, host can perform a series of writes to\r
+ // the data register after each time device set DRQ ready;\r
+ //\r
+ Increment = 256;\r
+\r
+ //\r
+ // used to record bytes of currently transfered data\r
+ //\r
+ WordCount = 0;\r
+\r
+ while (WordCount < ByteCount / 2) {\r
+ //\r
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+ //\r
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = CheckErrorStatus (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Write data into device by one series of writing to data register\r
+ //\r
+ if ((WordCount + Increment) > ByteCount / 2) {\r
+ Increment = ByteCount / 2 - WordCount;\r
+ }\r
+\r
+ IDEWritePortWMultiple (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Data,\r
+ Increment,\r
+ Buffer16\r
+ );\r
+\r
+ WordCount += Increment;\r
+ Buffer16 += Increment;\r
+\r
+ }\r
+ //\r
+ // while\r
+ //\r
+\r
+ return CheckErrorStatus (IdeDev);\r
+}\r
+\r
+\r
+/**\r
+ Enable SMART of the disk if supported\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+ to record all the information of the IDE device.\r
+\r
+**/\r
+VOID\r
+AtaSMARTSupport (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN SMARTSupported;\r
+ UINT8 Device;\r
+ EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;\r
+ UINT8 DeviceSelect;\r
+ UINT8 LBAMid;\r
+ UINT8 LBAHigh;\r
+\r
+ //\r
+ // Detect if the device supports S.M.A.R.T.\r
+ //\r
+ if ((IdeDev->pIdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {\r
+ //\r
+ // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)\r
+ //\r
+ return ;\r
+ } else {\r
+ if ((IdeDev->pIdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
+ //\r
+ // S.M.A.R.T is not supported by the device\r
+ //\r
+ SMARTSupported = FALSE;\r
+ } else {\r
+ SMARTSupported = TRUE;\r
+ }\r
+ }\r
+\r
+ if (!SMARTSupported) {\r
+ //\r
+ // Report nonsupport status code\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
+ );\r
+ } else {\r
+ //\r
+ // Enable this feature\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
+ );\r
+\r
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
+ Status = AtaNonDataCommandIn (\r
+ IdeDev,\r
+ ATA_SMART_CMD,\r
+ Device,\r
+ ATA_SMART_ENABLE_OPERATION,\r
+ 0,\r
+ 0,\r
+ ATA_CONSTANT_4F,\r
+ ATA_CONSTANT_C2\r
+ );\r
+ //\r
+ // Detect if this feature is enabled\r
+ //\r
+ TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
+\r
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
+ Status = AtaPioDataIn (\r
+ IdeDev,\r
+ (VOID *) TmpAtaIdentifyPointer,\r
+ sizeof (EFI_IDENTIFY_DATA),\r
+ IDENTIFY_DRIVE_CMD,\r
+ DeviceSelect,\r
+ 0,\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (TmpAtaIdentifyPointer);\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Check if the feature is enabled\r
+ //\r
+ if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {\r
+ //\r
+ // Read status data\r
+ //\r
+ AtaNonDataCommandIn (\r
+ IdeDev,\r
+ ATA_SMART_CMD,\r
+ Device,\r
+ ATA_SMART_RETURN_STATUS,\r
+ 0,\r
+ 0,\r
+ ATA_CONSTANT_4F,\r
+ ATA_CONSTANT_C2\r
+ );\r
+ LBAMid = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r
+ LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);\r
+\r
+ if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
+ //\r
+ // The threshold exceeded condition is not detected by the device\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
+ );\r
+\r
+ } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
+ //\r
+ // The threshold exceeded condition is detected by the device\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_PROGRESS_CODE,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
+ );\r
+ }\r
+\r
+ } else {\r
+ //\r
+ // Report disabled status code\r
+ //\r
+ REPORT_STATUS_CODE (\r
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
+ );\r
+ }\r
+\r
+ gBS->FreePool (TmpAtaIdentifyPointer);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Send ATA Ext command into device with NON_DATA protocol\r
+\r
+ @param IdeDev Standard IDE device private data structure\r
+ @param AtaCommand The ATA command to be sent\r
+ @param Device The value in Device register\r
+ @param Feature The value in Feature register\r
+ @param SectorCount The value in SectorCount register\r
+ @param LbaAddress The LBA address in 48-bit mode\r
+\r
+ @retval EFI_SUCCESS Reading succeed\r
+ @retval EFI_DEVICE_ERROR Error executing commands on this device\r
+\r
+**/\r
+EFI_STATUS\r
+AtaCommandIssueExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT16 Feature,\r
+ IN UINT16 SectorCount,\r
+ IN EFI_LBA LbaAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 SectorCount8;\r
+ UINT8 Feature8;\r
+ UINT8 LbaLow;\r
+ UINT8 LbaMid;\r
+ UINT8 LbaHigh;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+ );\r
+\r
+ //\r
+ // ATA commands for ATA device must be issued when DRDY is set\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Pass parameter into device register block\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+\r
+ //\r
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ Feature8 = (UINT8) (Feature >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+ Feature8 = (UINT8) Feature;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+ //\r
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ SectorCount8 = (UINT8) (SectorCount >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ SectorCount8 = (UINT8) SectorCount;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ //\r
+ // Fill the start LBA registers, which are also two-byte FIFO\r
+ //\r
+ LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ LbaLow = (UINT8) LbaAddress;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+\r
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+\r
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ //\r
+ // Work around for Segate 160G disk writing\r
+ //\r
+ gBS->Stall (1800);\r
+\r
+ //\r
+ // Send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ //\r
+ // Stall at least 400ns\r
+ //\r
+ gBS->Stall (100);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send ATA Ext command into device with NON_DATA protocol\r
+\r
+ @param IdeDev Standard IDE device private data structure\r
+ @param AtaCommand The ATA command to be sent\r
+ @param Device The value in Device register\r
+ @param Feature The value in Feature register\r
+ @param SectorCount The value in SectorCount register\r
+ @param LbaAddress The LBA address in 48-bit mode\r
+\r
+ @retval EFI_SUCCESS Reading succeed\r
+ @retval EFI_DEVICE_ERROR Error executing commands on this device\r
+\r
+**/\r
+EFI_STATUS\r
+AtaCommandIssue (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT16 Feature,\r
+ IN UINT16 SectorCount,\r
+ IN EFI_LBA LbaAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 SectorCount8;\r
+ UINT8 Feature8;\r
+ UINT8 Lba0;\r
+ UINT8 Lba1;\r
+ UINT8 Lba2;\r
+ UINT8 Lba3;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+ );\r
+\r
+ //\r
+ // ATA commands for ATA device must be issued when DRDY is set\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Lba0 = (UINT8) LbaAddress;\r
+ Lba1 = (UINT8) RShiftU64 (LbaAddress, 8);\r
+ Lba2 = (UINT8) RShiftU64 (LbaAddress, 16);\r
+ Lba3 = (UINT8) RShiftU64 (LbaAddress, 24);\r
+ Device = (UINT8) (Device | Lba3);\r
+\r
+ //\r
+ // Pass parameter into device register block\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+\r
+ //\r
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ Feature8 = (UINT8) Feature;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+ //\r
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ SectorCount8 = (UINT8) SectorCount;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ //\r
+ // Fill the start LBA registers, which are also two-byte FIFO\r
+ //\r
+\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);\r
+\r
+ //\r
+ // Send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ //\r
+ // Stall at least 400ns\r
+ //\r
+ gBS->Stall (100);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoReadBlocks() to perform\r
+ reading from media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
+\r
+ @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer A pointer to the destination buffer for the data.\r
+\r
+ @param[in] StartLba The starting logical block address to read from\r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks The number of transfer data blocks.\r
+\r
+ @return The device status of UDMA operation. If the operation is\r
+ successful, return EFI_SUCCESS.\r
+\r
+ TODO: EFI_UNSUPPORTED - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaReadExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoReadBlocks() to perform\r
+ reading from media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer A pointer to the destination buffer for the data.\r
+ @param[in] StartLba The starting logical block address to read from\r
+ on the device media.\r
+ @param[in] NumberOfBlocks The number of transfer data blocks.\r
+\r
+ @return The device status of UDMA operation. If the operation is\r
+ successful, return EFI_SUCCESS.\r
+\r
+ TODO: EFI_UNSUPPORTED - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaRead (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoWriteBlocks() to perform\r
+ writing to media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
+\r
+ @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer A pointer to the source buffer for the data.\r
+\r
+ @param[in] StartLba The starting logical block address to write to\r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks The number of transfer data blocks.\r
+\r
+ @return The device status of UDMA operation. If the operation is\r
+ successful, return EFI_SUCCESS.\r
+\r
+ TODO: EFI_UNSUPPORTED - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWriteExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoWriteBlocks() to perform\r
+ writing to media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer\r
+ A pointer to the source buffer for the data.\r
+\r
+ @param[in] StartLba\r
+ The starting logical block address to write to\r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+\r
+ @return The device status of UDMA operation. If the operation is\r
+ successful, return EFI_SUCCESS.\r
+\r
+ TODO: EFI_UNSUPPORTED - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWrite (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);\r
+}\r
+\r
+/**\r
+ Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer\r
+ A pointer to the source buffer for the data.\r
+\r
+ @param[in] StartLba\r
+ The starting logical block address to write to\r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+\r
+ @param[in] UdmaOp\r
+ The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r
+ AtaUdmaWriteOp, AtaUdmaWriteExOp\r
+\r
+ @return The device status of UDMA operation. If the operation is\r
+ successful, return EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+DoAtaUdma (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks,\r
+ IN ATA_UDMA_OPERATION UdmaOp\r
+ )\r
+{\r
+ IDE_DMA_PRD *PrdAddr;\r
+ IDE_DMA_PRD *UsedPrdAddr;\r
+ IDE_DMA_PRD *TempPrdAddr;\r
+ UINT8 RegisterValue;\r
+ UINT8 Device;\r
+ UINT64 IoPortForBmic;\r
+ UINT64 IoPortForBmis;\r
+ UINT64 IoPortForBmid;\r
+ EFI_STATUS Status;\r
+ UINTN PrdTableNum;\r
+ UINTN ByteCount;\r
+ UINTN ByteAvailable;\r
+ UINT8 *PrdBuffer;\r
+ UINTN RemainBlockNum;\r
+ UINT8 DeviceControl;\r
+ UINT32 Count;\r
+ UINTN PageCount;\r
+ VOID *Map;\r
+ VOID *MemPage;\r
+ EFI_PHYSICAL_ADDRESS DeviceAddress;\r
+ UINTN MaxDmaCommandSectors;\r
+ EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;\r
+ UINT8 AtaCommand;\r
+\r
+ switch (UdmaOp) {\r
+ case AtaUdmaReadOp:\r
+ MaxDmaCommandSectors = MAX_DMA_COMMAND_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;\r
+ AtaCommand = READ_DMA_CMD;\r
+ break;\r
+ case AtaUdmaReadExtOp:\r
+ MaxDmaCommandSectors = MAX_DMA_EXT_COMMAND_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;\r
+ AtaCommand = READ_DMA_EXT_CMD;\r
+ break;\r
+ case AtaUdmaWriteOp:\r
+ MaxDmaCommandSectors = MAX_DMA_COMMAND_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterRead;\r
+ AtaCommand = WRITE_DMA_CMD;\r
+ break;\r
+ case AtaUdmaWriteExtOp:\r
+ MaxDmaCommandSectors = MAX_DMA_EXT_COMMAND_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterRead;\r
+ AtaCommand = WRITE_DMA_EXT_CMD;\r
+ break;\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Channel and device differential\r
+ //\r
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
+\r
+ //\r
+ // Enable interrupt to support UDMA and Select device\r
+ //\r
+ DeviceControl = 0;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+\r
+ if (IdePrimary == IdeDev->Channel) {\r
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
+ } else {\r
+ if (IdeSecondary == IdeDev->Channel) {\r
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ RemainBlockNum = NumberOfBlocks;\r
+ while (RemainBlockNum > 0) {\r
+\r
+ if (RemainBlockNum >= MaxDmaCommandSectors) {\r
+ //\r
+ // SectorCount is used to record the number of sectors to be read\r
+ // Max 65536 sectors can be transfered at a time.\r
+ //\r
+ NumberOfBlocks = MaxDmaCommandSectors;\r
+ RemainBlockNum -= MaxDmaCommandSectors;\r
+ } else {\r
+ NumberOfBlocks = (UINT16) RemainBlockNum;\r
+ RemainBlockNum = 0;\r
+ }\r
+\r
+ //\r
+ // Calculate the number of PRD table to make sure the memory region\r
+ // not cross 64K boundary\r
+ //\r
+ ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
+ PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
+\r
+ //\r
+ // Build PRD table\r
+ //\r
+ PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
+ Status = IdeDev->PciIo->AllocateBuffer (\r
+ IdeDev->PciIo,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ PageCount,\r
+ &MemPage,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r
+\r
+ PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r
+ //\r
+ // To make sure PRD is allocated in one 64K page\r
+ //\r
+ if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
+ } else {\r
+ if ((UINTN) PrdAddr & 0x03) {\r
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
+ } else {\r
+ UsedPrdAddr = PrdAddr;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Build the PRD table\r
+ //\r
+ Status = IdeDev->PciIo->Map (\r
+ IdeDev->PciIo,\r
+ PciIoProtocolOp,\r
+ DataBuffer,\r
+ &ByteCount,\r
+ &DeviceAddress,\r
+ &Map\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ PrdBuffer = (VOID *) ((UINTN) DeviceAddress);\r
+ TempPrdAddr = UsedPrdAddr;\r
+ while (TRUE) {\r
+\r
+ ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
+\r
+ if (ByteCount <= ByteAvailable) {\r
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
+ TempPrdAddr->ByteCount = (UINT16) ByteCount;\r
+ TempPrdAddr->EndOfTable = 0x8000;\r
+ break;\r
+ }\r
+\r
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
+ TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r
+\r
+ ByteCount -= ByteAvailable;\r
+ PrdBuffer += ByteAvailable;\r
+ TempPrdAddr++;\r
+ }\r
+\r
+ //\r
+ // Set the base address to BMID register\r
+ //\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint32,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmid,\r
+ 1,\r
+ &UsedPrdAddr\r
+ );\r
+\r
+ //\r
+ // Set BMIC register to identify the operation direction\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {\r
+ RegisterValue |= BMIC_nREAD;\r
+ } else {\r
+ RegisterValue &= ~((UINT8) BMIC_nREAD);\r
+ }\r
+\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ //\r
+ // Read BMIS register and clear ERROR and INTR bit\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {\r
+ Status = AtaCommandIssueExt (\r
+ IdeDev,\r
+ AtaCommand,\r
+ Device,\r
+ 0,\r
+ (UINT16) NumberOfBlocks,\r
+ StartLba\r
+ );\r
+ } else {\r
+ Status = AtaCommandIssue (\r
+ IdeDev,\r
+ AtaCommand,\r
+ Device,\r
+ 0,\r
+ (UINT16) NumberOfBlocks,\r
+ StartLba\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+ IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Set START bit of BMIC register\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ RegisterValue |= BMIC_START;\r
+\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ //\r
+ // Check the INTERRUPT and ERROR bit of BMIS\r
+ // Max transfer number of sectors for one command is 65536(32Mbyte),\r
+ // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
+ // So set the variable Count to 2000, for about 2 second timeout time.\r
+ //\r
+ Count = 2000;\r
+ while (TRUE) {\r
+\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+ if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {\r
+ if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {\r
+ //\r
+ // Clear START bit of BMIC register before return EFI_DEVICE_ERROR\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ RegisterValue &= ~((UINT8)BMIC_START);\r
+\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+ IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (1000);\r
+ Count --;\r
+ }\r
+\r
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+ IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
+ //\r
+ // Read Status Register of IDE device to clear interrupt\r
+ //\r
+ RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r
+ //\r
+ // Clear START bit of BMIC register\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ RegisterValue &= ~((UINT8) BMIC_START);\r
+\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmic,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ if (RegisterValue & BMIS_ERROR) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
+ StartLba += NumberOfBlocks;\r
+ }\r
+\r
+ //\r
+ // Disable interrupt of Select device\r
+ //\r
+ IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);\r
+ DeviceControl |= IEN_L;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ Copyright (c) 2006 - 2007, Intel Corporation \r
+ All rights reserved. This program and the accompanying materials \r
+ are licensed and made available under the terms and conditions of the BSD License \r
+ which accompanies this distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "idebus.h"\r
+\r
+/**\r
+ This function is used to get the current status of the media residing\r
+ in the LS-120 drive or ZIP drive. The media status is returned in the \r
+ Error Status.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @retval EFI_SUCCESS\r
+ The media status is achieved successfully and the media\r
+ can be read/written.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Get Media Status Command is failed.\r
+ \r
+ @retval EFI_NO_MEDIA\r
+ There is no media in the drive.\r
+ \r
+ @retval EFI_WRITE_PROTECTED\r
+ The media is writing protected.\r
+\r
+ @note\r
+ This function must be called after the LS120EnableMediaStatus() \r
+ with second parameter set to TRUE \r
+ (means enable media status notification) is called.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+LS120GetMediaStatus (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ UINT8 DeviceSelect;\r
+ UINT8 StatusValue;\r
+ EFI_STATUS EfiStatus;\r
+ //\r
+ // Poll Alternate Register for BSY clear within timeout.\r
+ //\r
+ EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Select device via Device/Head Register.\r
+ //\r
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
+\r
+ //\r
+ // Poll Alternate Register for DRDY set within timeout.\r
+ // After device is selected, DRDY set indicates the device is ready to\r
+ // accept command.\r
+ //\r
+ EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Get Media Status Command is sent\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA);\r
+\r
+ //\r
+ // BSY bit will clear after command is complete.\r
+ //\r
+ EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (EfiStatus)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // the media status is returned by the command in the ERROR register\r
+ //\r
+ StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+\r
+ if (StatusValue & bit1) {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ if (StatusValue & bit6) {\r
+ return EFI_WRITE_PROTECTED;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r
+\r
+/**\r
+ This function is used to send Enable Media Status Notification Command\r
+ or Disable Media Status Notification Command.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] Enable\r
+ a flag that indicates whether enable or disable media\r
+ status notification.\r
+\r
+ @retval EFI_SUCCESS\r
+ If command completes successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ If command failed.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+LS120EnableMediaStatus (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN BOOLEAN Enable\r
+ )\r
+{\r
+ UINT8 DeviceSelect;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Poll Alternate Register for BSY clear within timeout.\r
+ //\r
+ Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Select device via Device/Head Register.\r
+ //\r
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
+\r
+ //\r
+ // Poll Alternate Register for DRDY set within timeout.\r
+ // After device is selected, DRDY set indicates the device is ready to\r
+ // accept command.\r
+ //\r
+ Status = DRDYReady2 (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (Enable) {\r
+ //\r
+ // 0x95: Enable media status notification\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95);\r
+ } else {\r
+ //\r
+ // 0x31: Disable media status notification\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31);\r
+ }\r
+ //\r
+ // Set Feature Command is sent\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF);\r
+\r
+ //\r
+ // BSY bit will clear after command is complete.\r
+ //\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is called by DiscoverIdeDevice() during its device\r
+ identification.\r
+\r
+ Its main purpose is to get enough information for the device media\r
+ to fill in the Media data structure of the Block I/O Protocol interface.\r
+\r
+ There are 5 steps to reach such objective:\r
+\r
+ 1. Sends out the ATAPI Identify Command to the specified device. \r
+ Only ATAPI device responses to this command. If the command succeeds,\r
+ it returns the Identify data structure which filled with information \r
+ about the device. Since the ATAPI device contains removable media, \r
+ the only meaningful information is the device module name.\r
+\r
+ 2. Sends out ATAPI Inquiry Packet Command to the specified device.\r
+ This command will return inquiry data of the device, which contains\r
+ the device type information.\r
+\r
+ 3. Allocate sense data space for future use. We don't detect the media\r
+ presence here to improvement boot performance, especially when CD \r
+ media is present. The media detection will be performed just before\r
+ each BLK_IO read/write\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @retval EFI_SUCCESS\r
+ Identify ATAPI device successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ ATAPI Identify Device Command failed or device type\r
+ is not supported by this IDE driver.\r
+\r
+ @note\r
+ Parameter "IdeDev" will be updated in this function.\r
+\r
+ TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
+ TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+ATAPIIdentify (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ EFI_IDENTIFY_DATA *AtapiIdentifyPointer;\r
+ UINT8 DeviceSelect;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // device select bit\r
+ //\r
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
+\r
+ AtapiIdentifyPointer = AllocatePool (sizeof (EFI_IDENTIFY_DATA));\r
+ if (AtapiIdentifyPointer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Send ATAPI Identify Command to get IDENTIFY data.\r
+ //\r
+ Status = AtaPioDataIn (\r
+ IdeDev,\r
+ (VOID *) AtapiIdentifyPointer,\r
+ sizeof (EFI_IDENTIFY_DATA),\r
+ ATAPI_IDENTIFY_DEVICE_CMD,\r
+ DeviceSelect,\r
+ 0,\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (AtapiIdentifyPointer);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ IdeDev->pIdData = AtapiIdentifyPointer;\r
+ PrintAtaModuleName (IdeDev);\r
+\r
+ //\r
+ // Send ATAPI Inquiry Packet Command to get INQUIRY data.\r
+ //\r
+ Status = AtapiInquiry (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (IdeDev->pIdData);\r
+ //\r
+ // Make sure the pIdData will not be freed again.\r
+ //\r
+ IdeDev->pIdData = NULL;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Get media removable info from INQUIRY data.\r
+ //\r
+ IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80);\r
+\r
+ //\r
+ // Identify device type via INQUIRY data.\r
+ //\r
+ switch (IdeDev->pInquiryData->peripheral_type & 0x1f) {\r
+\r
+ //\r
+ // Magnetic Disk\r
+ //\r
+ case 0x00:\r
+\r
+ //\r
+ // device is LS120 or ZIP drive.\r
+ //\r
+ IdeDev->Type = IdeMagnetic;\r
+\r
+ IdeDev->BlkIo.Media->MediaId = 0;\r
+ //\r
+ // Give initial value\r
+ //\r
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+\r
+ IdeDev->BlkIo.Media->LastBlock = 0;\r
+ IdeDev->BlkIo.Media->BlockSize = 0x200;\r
+ break;\r
+\r
+ //\r
+ // CD-ROM\r
+ //\r
+ case 0x05:\r
+\r
+ IdeDev->Type = IdeCdRom;\r
+ IdeDev->BlkIo.Media->MediaId = 0;\r
+ //\r
+ // Give initial value\r
+ //\r
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+\r
+ IdeDev->BlkIo.Media->LastBlock = 0;\r
+ IdeDev->BlkIo.Media->BlockSize = 0x800;\r
+ IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
+ break;\r
+\r
+ //\r
+ // Tape\r
+ //\r
+ case 0x01:\r
+\r
+ //\r
+ // WORM\r
+ //\r
+ case 0x04:\r
+ \r
+ //\r
+ // Optical\r
+ //\r
+ case 0x07:\r
+\r
+ default:\r
+ IdeDev->Type = IdeUnknown;\r
+ gBS->FreePool (IdeDev->pIdData);\r
+ gBS->FreePool (IdeDev->pInquiryData);\r
+ //\r
+ // Make sure the pIdData and pInquiryData will not be freed again.\r
+ //\r
+ IdeDev->pIdData = NULL;\r
+ IdeDev->pInquiryData = NULL;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // original sense data numbers\r
+ //\r
+ IdeDev->SenseDataNumber = 20;\r
+\r
+ IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (REQUEST_SENSE_DATA));\r
+ if (IdeDev->SenseData == NULL) {\r
+ gBS->FreePool (IdeDev->pIdData);\r
+ gBS->FreePool (IdeDev->pInquiryData);\r
+ //\r
+ // Make sure the pIdData and pInquiryData will not be freed again.\r
+ //\r
+ IdeDev->pIdData = NULL;\r
+ IdeDev->pInquiryData = NULL;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sends out ATAPI Inquiry Packet Command to the specified device.\r
+ This command will return INQUIRY data of the device.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @retval EFI_SUCCESS\r
+ Inquiry command completes successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Inquiry command failed.\r
+\r
+ @note\r
+ Parameter "IdeDev" will be updated in this function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiInquiry (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ EFI_STATUS Status;\r
+ INQUIRY_DATA *InquiryData;\r
+\r
+ //\r
+ // prepare command packet for the ATAPI Inquiry Packet Command.\r
+ //\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ Packet.Inquiry.opcode = INQUIRY;\r
+ Packet.Inquiry.page_code = 0;\r
+ Packet.Inquiry.allocation_length = sizeof (INQUIRY_DATA);\r
+\r
+ InquiryData = AllocatePool (sizeof (INQUIRY_DATA));\r
+ if (InquiryData == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Send command packet and get requested Inquiry data.\r
+ //\r
+ Status = AtapiPacketCommandIn (\r
+ IdeDev,\r
+ &Packet,\r
+ (UINT16 *) InquiryData,\r
+ sizeof (INQUIRY_DATA),\r
+ ATAPITIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (InquiryData);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ IdeDev->pInquiryData = InquiryData;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to send out ATAPI commands conforms to the \r
+ Packet Command with PIO Data In Protocol.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Packet\r
+ pointer pointing to ATAPI_PACKET_COMMAND data structure\r
+ which contains the contents of the command. \r
+\r
+ @param[in] *Buffer\r
+ buffer contained data transferred from device to host.\r
+\r
+ @param[in] ByteCount\r
+ data size in byte unit of the buffer.\r
+\r
+ @param[in] TimeOut\r
+ this parameter is used to specify the timeout \r
+ value for the PioReadWriteData() function. \r
+\r
+ @retval EFI_SUCCESS\r
+ send out the ATAPI packet command successfully\r
+ and device sends data successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ the device failed to send data.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiPacketCommandIn (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN ATAPI_PACKET_COMMAND *Packet,\r
+ IN UINT16 *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINTN TimeOut\r
+ )\r
+{\r
+ UINT16 *CommandIndex;\r
+ EFI_STATUS Status;\r
+ UINT32 Count;\r
+\r
+ //\r
+ // Set all the command parameters by fill related registers.\r
+ // Before write to all the following registers, BSY and DRQ must be 0.\r
+ //\r
+ Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Select device via Device/Head Register.\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)\r
+ );\r
+\r
+ //\r
+ // No OVL; No DMA\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);\r
+\r
+ //\r
+ // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device\r
+ // determine how many data should be transferred.\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderLsb,\r
+ (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
+ );\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderMsb,\r
+ (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
+ );\r
+\r
+ //\r
+ // DEFAULT_CTL:0x0a (0000,1010)\r
+ // Disable interrupt\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL);\r
+\r
+ //\r
+ // Send Packet command to inform device\r
+ // that the following data bytes are command packet.\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD);\r
+\r
+ Status = DRQReady (IdeDev, ATAPITIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Send out command packet\r
+ //\r
+ CommandIndex = Packet->Data16;\r
+ for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
+\r
+ IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);\r
+ gBS->Stall (10);\r
+ }\r
+\r
+ //\r
+ // call PioReadWriteData() function to get\r
+ // requested transfer data form device.\r
+ //\r
+ return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut);\r
+}\r
+\r
+/**\r
+ This function is used to send out ATAPI commands conforms to the \r
+ Packet Command with PIO Data Out Protocol.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Packet\r
+ pointer pointing to ATAPI_PACKET_COMMAND data structure\r
+ which contains the contents of the command.\r
+\r
+ @param[in] *Buffer\r
+ buffer contained data transferred from host to device.\r
+\r
+ @param[in] ByteCount\r
+ data size in byte unit of the buffer.\r
+\r
+ @param[in] TimeOut\r
+ this parameter is used to specify the timeout \r
+ value for the PioReadWriteData() function. \r
+\r
+ @retval EFI_SUCCESS\r
+ send out the ATAPI packet command successfully\r
+ and device received data successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ the device failed to send data.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiPacketCommandOut (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN ATAPI_PACKET_COMMAND *Packet,\r
+ IN UINT16 *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINTN TimeOut\r
+ )\r
+{\r
+ UINT16 *CommandIndex;\r
+ EFI_STATUS Status;\r
+ UINT32 Count;\r
+\r
+ //\r
+ // set all the command parameters\r
+ // Before write to all the following registers, BSY and DRQ must be 0.\r
+ //\r
+ Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Select device via Device/Head Register.\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)\r
+ );\r
+\r
+ //\r
+ // No OVL; No DMA\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);\r
+\r
+ //\r
+ // set the transfersize to MAX_ATAPI_BYTE_COUNT to\r
+ // let the device determine how many data should be transferred.\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderLsb,\r
+ (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
+ );\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderMsb,\r
+ (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
+ );\r
+\r
+ //\r
+ // DEFAULT_CTL:0x0a (0000,1010)\r
+ // Disable interrupt\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL);\r
+\r
+ //\r
+ // Send Packet command to inform device\r
+ // that the following data bytes are command packet.\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD);\r
+\r
+ Status = DRQReady2 (IdeDev, ATAPITIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Send out command packet\r
+ //\r
+ CommandIndex = Packet->Data16;\r
+ for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
+ IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);\r
+ gBS->Stall (10);\r
+ }\r
+\r
+ //\r
+ // call PioReadWriteData() function to send requested transfer data to device.\r
+ //\r
+ return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut);\r
+}\r
+\r
+/**\r
+ This function is called by either AtapiPacketCommandIn() or \r
+ AtapiPacketCommandOut(). It is used to transfer data between\r
+ host and device. The data direction is specified by the fourth\r
+ parameter.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Buffer\r
+ buffer contained data transferred between host and device.\r
+\r
+ @param[in] ByteCount\r
+ data size in byte unit of the buffer.\r
+\r
+ @param[in] Read\r
+ flag used to determine the data transfer direction.\r
+ Read equals 1, means data transferred from device to host;\r
+ Read equals 0, means data transferred from host to device.\r
+\r
+ @param[in] TimeOut\r
+ timeout value for wait DRQ ready before each data \r
+ stream's transfer.\r
+\r
+ @retval EFI_SUCCESS\r
+ data is transferred successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ the device failed to transfer data.\r
+\r
+**/\r
+EFI_STATUS\r
+PioReadWriteData (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT16 *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN BOOLEAN Read,\r
+ IN UINTN TimeOut\r
+ )\r
+{\r
+ //\r
+ // required transfer data in word unit.\r
+ //\r
+ UINT32 RequiredWordCount;\r
+\r
+ //\r
+ // actual transfer data in word unit.\r
+ //\r
+ UINT32 ActualWordCount;\r
+ UINT32 WordCount;\r
+ EFI_STATUS Status;\r
+ UINT16 *PtrBuffer;\r
+\r
+ //\r
+ // No data transfer is premitted.\r
+ //\r
+ if (ByteCount == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // for performance, we assert the ByteCount is an even number\r
+ // which is actually a resonable assumption \r
+ ASSERT((ByteCount%2) == 0);\r
+ \r
+ PtrBuffer = Buffer;\r
+ RequiredWordCount = ByteCount / 2;\r
+ //\r
+ // ActuralWordCount means the word count of data really transferred.\r
+ //\r
+ ActualWordCount = 0;\r
+\r
+ while (ActualWordCount < RequiredWordCount) {\r
+ \r
+ //\r
+ // before each data transfer stream, the host should poll DRQ bit ready,\r
+ // to see whether indicates device is ready to transfer data.\r
+ //\r
+ Status = DRQReady2 (IdeDev, TimeOut);\r
+ if (EFI_ERROR (Status)) {\r
+ return CheckErrorStatus (IdeDev);\r
+ }\r
+ \r
+ //\r
+ // read Status Register will clear interrupt\r
+ //\r
+ IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+ //\r
+ // get current data transfer size from Cylinder Registers.\r
+ //\r
+ WordCount = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8;\r
+ WordCount = WordCount | IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r
+ WordCount = WordCount & 0xffff;\r
+ WordCount /= 2;\r
+\r
+ WordCount = EFI_MIN (WordCount, (RequiredWordCount - ActualWordCount));\r
+\r
+ if (Read) {\r
+ IDEReadPortWMultiple (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Data,\r
+ WordCount,\r
+ PtrBuffer\r
+ );\r
+ } else {\r
+ IDEWritePortWMultiple (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Data,\r
+ WordCount,\r
+ PtrBuffer\r
+ );\r
+ }\r
+\r
+ PtrBuffer += WordCount;\r
+ ActualWordCount += WordCount;\r
+ }\r
+ \r
+ if (Read) {\r
+ //\r
+ // In the case where the drive wants to send more data than we need to read,\r
+ // the DRQ bit will be set and cause delays from DRQClear2().\r
+ // We need to read data from the drive until it clears DRQ so we can move on.\r
+ //\r
+ AtapiReadPendingData (IdeDev);\r
+ }\r
+\r
+ //\r
+ // After data transfer is completed, normally, DRQ bit should clear.\r
+ //\r
+ Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // read status register to check whether error happens.\r
+ //\r
+ return CheckErrorStatus (IdeDev);\r
+}\r
+\r
+/**\r
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
+ to find out whether device is accessible.\r
+\r
+ @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+ @param[in] *SenseCount Sense count for this packet command\r
+\r
+ @retval EFI_SUCCESS Device is accessible.\r
+ @retval EFI_DEVICE_ERROR Device is not accessible.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiTestUnitReady (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT UINTN *SenseCount\r
+ )\r
+{\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ EFI_STATUS Status;\r
+\r
+ *SenseCount = 0;\r
+\r
+ //\r
+ // fill command packet\r
+ //\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ Packet.TestUnitReady.opcode = TEST_UNIT_READY;\r
+\r
+ //\r
+ // send command packet\r
+ //\r
+ Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = AtapiRequestSense (IdeDev, SenseCount);\r
+ if (EFI_ERROR (Status)) {\r
+ *SenseCount = 0;\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sends out ATAPI Request Sense Packet Command to the specified device.\r
+ This command will return all the current Sense data in the device. \r
+ This function will pack all the Sense data in one single buffer.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[out] **SenseBuffers\r
+ allocated in this function, and freed by the calling function.\r
+ This buffer is used to accommodate all the sense data returned \r
+ by the device.\r
+\r
+ @param[out] *BufUnit\r
+ record the unit size of the sense data block in the SenseBuffers,\r
+\r
+ @param[out] *BufNumbers\r
+ record the number of units in the SenseBuffers.\r
+\r
+ @retval EFI_SUCCESS\r
+ Request Sense command completes successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Request Sense command failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiRequestSense (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT UINTN *SenseCounts\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ REQUEST_SENSE_DATA *Sense;\r
+ UINT16 *Ptr;\r
+ BOOLEAN FetchSenseData;\r
+ ATAPI_PACKET_COMMAND Packet;\r
+\r
+ *SenseCounts = 0;\r
+\r
+ ZeroMem (IdeDev->SenseData, sizeof (REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));\r
+ //\r
+ // fill command packet for Request Sense Packet Command\r
+ //\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ Packet.RequestSence.opcode = REQUEST_SENSE;\r
+ Packet.RequestSence.allocation_length = sizeof (REQUEST_SENSE_DATA);\r
+\r
+ //\r
+ // initialize pointer\r
+ //\r
+ Ptr = (UINT16 *) IdeDev->SenseData;\r
+ //\r
+ // request sense data from device continuously until no sense data\r
+ // exists in the device.\r
+ //\r
+ for (FetchSenseData = TRUE; FetchSenseData;) {\r
+\r
+ Sense = (REQUEST_SENSE_DATA *) Ptr;\r
+\r
+ //\r
+ // send out Request Sense Packet Command and get one Sense data form device\r
+ //\r
+ Status = AtapiPacketCommandIn (\r
+ IdeDev,\r
+ &Packet,\r
+ Ptr,\r
+ sizeof (REQUEST_SENSE_DATA),\r
+ ATAPITIMEOUT\r
+ );\r
+ //\r
+ // failed to get Sense data\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ if (*SenseCounts == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ (*SenseCounts)++;\r
+ //\r
+ // We limit MAX sense data count to 20 in order to avoid dead loop. Some\r
+ // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.\r
+ // In this case, dead loop occurs if we don't have a gatekeeper. 20 is\r
+ // supposed to be large enough for any ATAPI device.\r
+ //\r
+ if ((Sense->sense_key != SK_NO_SENSE) && ((*SenseCounts) < 20)) {\r
+ //\r
+ // Ptr is word-based pointer\r
+ //\r
+ Ptr += (sizeof (REQUEST_SENSE_DATA) + 1) >> 1;\r
+\r
+ } else {\r
+ //\r
+ // when no sense key, skip out the loop\r
+ //\r
+ FetchSenseData = FALSE;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sends out ATAPI Read Capacity Packet Command to the specified device.\r
+ This command will return the information regarding the capacity of the\r
+ media in the device.\r
+\r
+ Current device status will impact device's response to the Read Capacity\r
+ Command. For example, if the device once reset, the Read Capacity\r
+ Command will fail. The Sense data record the current device status, so \r
+ if the Read Capacity Command failed, the Sense data must be requested\r
+ and be analyzed to determine if the Read Capacity Command should retry.\r
+\r
+ @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+ @param[in] SenseCount Sense count for this packet command\r
+\r
+ @retval EFI_SUCCESS Read Capacity Command finally completes successfully.\r
+ @retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error.\r
+\r
+ @note Parameter "IdeDev" will be updated in this function.\r
+\r
+ TODO: EFI_NOT_READY - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtapiReadCapacity (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT UINTN *SenseCount\r
+ )\r
+{\r
+ //\r
+ // status returned by Read Capacity Packet Command\r
+ //\r
+ EFI_STATUS Status;\r
+ EFI_STATUS SenseStatus;\r
+ ATAPI_PACKET_COMMAND Packet;\r
+\r
+ //\r
+ // used for capacity data returned from ATAPI device\r
+ //\r
+ READ_CAPACITY_DATA Data;\r
+ READ_FORMAT_CAPACITY_DATA FormatData;\r
+\r
+ *SenseCount = 0;\r
+\r
+ ZeroMem (&Data, sizeof (Data));\r
+ ZeroMem (&FormatData, sizeof (FormatData));\r
+\r
+ if (IdeDev->Type == IdeCdRom) {\r
+\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ Packet.Inquiry.opcode = READ_CAPACITY;\r
+ Status = AtapiPacketCommandIn (\r
+ IdeDev,\r
+ &Packet,\r
+ (UINT16 *) &Data,\r
+ sizeof (READ_CAPACITY_DATA),\r
+ ATAPITIMEOUT\r
+ );\r
+\r
+ } else {\r
+ //\r
+ // Type == IdeMagnetic\r
+ //\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY;\r
+ Packet.ReadFormatCapacity.allocation_length_lo = 12;\r
+ Status = AtapiPacketCommandIn (\r
+ IdeDev,\r
+ &Packet,\r
+ (UINT16 *) &FormatData,\r
+ sizeof (READ_FORMAT_CAPACITY_DATA),\r
+ ATAPITIMEOUT\r
+ );\r
+ }\r
+\r
+ if (Status == EFI_TIMEOUT) {\r
+ *SenseCount = 0;\r
+ return Status;\r
+ }\r
+\r
+ SenseStatus = AtapiRequestSense (IdeDev, SenseCount);\r
+\r
+ if (!EFI_ERROR (SenseStatus)) {\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ if (IdeDev->Type == IdeCdRom) {\r
+\r
+ IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |\r
+ (Data.LastLba2 << 16) |\r
+ (Data.LastLba1 << 8) |\r
+ Data.LastLba0;\r
+\r
+ if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
+\r
+ IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) |\r
+ (Data.BlockSize2 << 16) |\r
+ (Data.BlockSize1 << 8) |\r
+ Data.BlockSize0;\r
+\r
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
+ } else {\r
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
+\r
+ //\r
+ // Because the user data portion in the sector of the Data CD supported\r
+ // is always 0x800\r
+ //\r
+ IdeDev->BlkIo.Media->BlockSize = 0x800;\r
+ }\r
+\r
+ if (IdeDev->Type == IdeMagnetic) {\r
+\r
+ if (FormatData.DesCode == 3) {\r
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+ IdeDev->BlkIo.Media->LastBlock = 0;\r
+ } else {\r
+\r
+ IdeDev->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) |\r
+ (FormatData.LastLba2 << 16) | \r
+ (FormatData.LastLba1 << 8) |\r
+ FormatData.LastLba0;\r
+ if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
+ IdeDev->BlkIo.Media->LastBlock--;\r
+\r
+ IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |\r
+ (FormatData.BlockSize1 << 8) |\r
+ FormatData.BlockSize0;\r
+\r
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
+ } else {\r
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+ //\r
+ // Return EFI_NOT_READY operation succeeds but returned capacity is 0\r
+ //\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ IdeDev->BlkIo.Media->BlockSize = 0x200;\r
+\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ } else {\r
+ *SenseCount = 0;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+}\r
+\r
+/**\r
+ Used before read/write blocks from/to ATAPI device media. \r
+ Since ATAPI device media is removable, it is necessary to detect\r
+ whether media is present and get current present media's\r
+ information, and if media has been changed, Block I/O Protocol\r
+ need to be reinstalled.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[out] *MediaChange\r
+ return value that indicates if the media of the device has been\r
+ changed.\r
+\r
+ @retval EFI_SUCCESS\r
+ media found successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ any error encounters during media detection.\r
+ \r
+ @retval EFI_NO_MEDIA\r
+ media not found.\r
+\r
+ @note\r
+ parameter IdeDev may be updated in this function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiDetectMedia (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT BOOLEAN *MediaChange\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS CleanStateStatus;\r
+ EFI_BLOCK_IO_MEDIA OldMediaInfo;\r
+ UINTN RetryTimes;\r
+ UINTN RetryNotReady;\r
+ UINTN SenseCount;\r
+ SENSE_RESULT SResult;\r
+ BOOLEAN WriteProtected;\r
+\r
+ CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
+ *MediaChange = FALSE;\r
+ //\r
+ // Retry for SenseDeviceNotReadyNeedRetry.\r
+ // Each retry takes 1s and we limit the upper boundary to\r
+ // 120 times about 2 min.\r
+ //\r
+ RetryNotReady = 120;\r
+\r
+ //\r
+ // Do Test Unit Ready\r
+ //\r
+ DoTUR:\r
+ //\r
+ // Retry 5 times\r
+ //\r
+ RetryTimes = 5;\r
+ while (RetryTimes != 0) {\r
+\r
+ Status = AtapiTestUnitReady (IdeDev, &SenseCount);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Test Unit Ready error without sense data.\r
+ // For some devices, this means there's extra data\r
+ // that has not been read, so we read these extra\r
+ // data out before going on.\r
+ //\r
+ CleanStateStatus = AtapiReadPendingData (IdeDev);\r
+ if (EFI_ERROR (CleanStateStatus)) {\r
+ //\r
+ // Busy wait failed, try again\r
+ //\r
+ RetryTimes--;\r
+ }\r
+ //\r
+ // Try again without counting down RetryTimes\r
+ //\r
+ continue;\r
+ } else {\r
+\r
+ ParseSenseData (IdeDev, SenseCount, &SResult);\r
+\r
+ switch (SResult) {\r
+ case SenseNoSenseKey:\r
+ if (IdeDev->BlkIo.Media->MediaPresent) {\r
+ goto Done;\r
+ } else {\r
+ //\r
+ // Media present but the internal structure need refreshed.\r
+ // Try Read Capacity\r
+ //\r
+ goto DoRC;\r
+ }\r
+ break;\r
+\r
+ case SenseDeviceNotReadyNeedRetry:\r
+ if (--RetryNotReady == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ gBS->Stall (1000 * STALL_1_MILLI_SECOND);\r
+ continue;\r
+ break;\r
+\r
+ case SenseNoMedia:\r
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+ IdeDev->BlkIo.Media->LastBlock = 0;\r
+ goto Done;\r
+ break;\r
+\r
+ case SenseDeviceNotReadyNoRetry:\r
+ case SenseMediaError:\r
+ return EFI_DEVICE_ERROR;\r
+\r
+ case SenseMediaChange:\r
+ IdeDev->BlkIo.Media->MediaId++;\r
+ goto DoRC;\r
+ break;\r
+\r
+ default:\r
+ RetryTimes--;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_DEVICE_ERROR;\r
+\r
+ //\r
+ // Do Read Capacity\r
+ //\r
+ DoRC:\r
+ RetryTimes = 5;\r
+\r
+ while (RetryTimes != 0) {\r
+\r
+ Status = AtapiReadCapacity (IdeDev, &SenseCount);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ RetryTimes--;\r
+ continue;\r
+ } else {\r
+\r
+ ParseSenseData (IdeDev, SenseCount, &SResult);\r
+\r
+ switch (SResult) {\r
+ case SenseNoSenseKey:\r
+ goto Done;\r
+ break;\r
+\r
+ case SenseDeviceNotReadyNeedRetry:\r
+ //\r
+ // We use Test Unit Ready to retry which\r
+ // is faster.\r
+ //\r
+ goto DoTUR;\r
+ break;\r
+\r
+ case SenseNoMedia:\r
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+ IdeDev->BlkIo.Media->LastBlock = 0;\r
+ goto Done;\r
+ break;\r
+\r
+ case SenseDeviceNotReadyNoRetry:\r
+ case SenseMediaError:\r
+ return EFI_DEVICE_ERROR;\r
+\r
+ case SenseMediaChange:\r
+ IdeDev->BlkIo.Media->MediaId++;\r
+ continue;\r
+ break;\r
+\r
+ default:\r
+ RetryTimes--;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_DEVICE_ERROR;\r
+\r
+ Done:\r
+ //\r
+ // the following code is to check the write-protected for LS120 media\r
+ //\r
+ if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) {\r
+\r
+ Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected);\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ if (WriteProtected) {\r
+\r
+ IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
+ } else {\r
+\r
+ IdeDev->BlkIo.Media->ReadOnly = FALSE;\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) {\r
+ //\r
+ // Media change information got from the device\r
+ //\r
+ *MediaChange = TRUE;\r
+ }\r
+\r
+ if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) {\r
+ *MediaChange = TRUE;\r
+ IdeDev->BlkIo.Media->MediaId += 1;\r
+ }\r
+\r
+ if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) {\r
+ *MediaChange = TRUE;\r
+ IdeDev->BlkIo.Media->MediaId += 1;\r
+ }\r
+\r
+ if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) {\r
+ *MediaChange = TRUE;\r
+ IdeDev->BlkIo.Media->MediaId += 1;\r
+ }\r
+\r
+ if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) {\r
+ if (IdeDev->BlkIo.Media->MediaPresent) {\r
+ //\r
+ // when change from no media to media present, reset the MediaId to 1.\r
+ //\r
+ IdeDev->BlkIo.Media->MediaId = 1;\r
+ } else {\r
+ //\r
+ // when no media, reset the MediaId to zero.\r
+ //\r
+ IdeDev->BlkIo.Media->MediaId = 0;\r
+ }\r
+\r
+ *MediaChange = TRUE;\r
+ }\r
+\r
+ //\r
+ // if any change on current existing media,\r
+ // the Block I/O protocol need to be reinstalled.\r
+ //\r
+ if (*MediaChange) {\r
+ gBS->ReinstallProtocolInterface (\r
+ IdeDev->Handle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &IdeDev->BlkIo,\r
+ &IdeDev->BlkIo\r
+ );\r
+ }\r
+\r
+ if (IdeDev->BlkIo.Media->MediaPresent) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_NO_MEDIA;\r
+ }\r
+}\r
+\r
+/**\r
+ This function is called by the AtapiBlkIoReadBlocks() to perform\r
+ read from media in block unit.\r
+\r
+ The main command used to access media here is READ(10) Command. \r
+ READ(10) Command requests that the ATAPI device media transfer \r
+ specified data to the host. Data is transferred in block(sector) \r
+ unit. The maximum number of blocks that can be transferred once is\r
+ 65536. This is the main difference between READ(10) and READ(12) \r
+ Command. The maximum number of blocks in READ(12) is 2 power 32.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Buffer\r
+ A pointer to the destination buffer for the data. \r
+\r
+ @param[in] Lba\r
+ The starting logical block address to read from \r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+\r
+ @return status is fully dependent on the return status\r
+ of AtapiPacketCommandIn() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiReadSectors (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *Buffer,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ READ10_CMD *Read10Packet;\r
+ EFI_STATUS Status;\r
+ UINTN BlocksRemaining;\r
+ UINT32 Lba32;\r
+ UINT32 BlockSize;\r
+ UINT32 ByteCount;\r
+ UINT16 SectorCount;\r
+ VOID *PtrBuffer;\r
+ UINT16 MaxBlock;\r
+ UINTN TimeOut;\r
+\r
+ //\r
+ // fill command packet for Read(10) command\r
+ //\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ Read10Packet = &Packet.Read10;\r
+ Lba32 = (UINT32) Lba;\r
+ PtrBuffer = Buffer;\r
+\r
+ BlockSize = IdeDev->BlkIo.Media->BlockSize;\r
+\r
+ //\r
+ // limit the data bytes that can be transferred by one Read(10) Command\r
+ //\r
+ MaxBlock = 65535;\r
+\r
+ BlocksRemaining = NumberOfBlocks;\r
+\r
+ Status = EFI_SUCCESS;\r
+ while (BlocksRemaining > 0) {\r
+\r
+ if (BlocksRemaining <= MaxBlock) {\r
+\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ } else {\r
+\r
+ SectorCount = MaxBlock;\r
+ }\r
+\r
+ //\r
+ // fill the Packet data structure\r
+ //\r
+\r
+ Read10Packet->opcode = READ_10;\r
+\r
+ //\r
+ // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
+ // Lba0 is MSB, Lba3 is LSB\r
+ //\r
+ Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r
+ Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r
+ Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r
+ Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r
+\r
+ //\r
+ // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
+ // TranLen0 is MSB, TranLen is LSB\r
+ //\r
+ Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r
+ Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r
+\r
+ ByteCount = SectorCount * BlockSize;\r
+\r
+ if (IdeDev->Type == IdeCdRom) {\r
+ TimeOut = CDROMLONGTIMEOUT;\r
+ } else {\r
+ TimeOut = ATAPILONGTIMEOUT;\r
+ }\r
+\r
+ Status = AtapiPacketCommandIn (\r
+ IdeDev,\r
+ &Packet,\r
+ (UINT16 *) PtrBuffer,\r
+ ByteCount,\r
+ TimeOut\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Lba32 += SectorCount;\r
+ PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;\r
+ BlocksRemaining -= SectorCount;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function is called by the AtapiBlkIoWriteBlocks() to perform\r
+ write onto media in block unit.\r
+ The main command used to access media here is Write(10) Command. \r
+ Write(10) Command requests that the ATAPI device media transfer \r
+ specified data to the host. Data is transferred in block (sector) \r
+ unit. The maximum number of blocks that can be transferred once is\r
+ 65536. \r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *Buffer\r
+ A pointer to the source buffer for the data. \r
+\r
+ @param[in] Lba\r
+ The starting logical block address to write onto \r
+ the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+\r
+ @return status is fully dependent on the return status\r
+ of AtapiPacketCommandOut() function.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiWriteSectors (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *Buffer,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+\r
+ ATAPI_PACKET_COMMAND Packet;\r
+ READ10_CMD *Read10Packet;\r
+\r
+ EFI_STATUS Status;\r
+ UINTN BlocksRemaining;\r
+ UINT32 Lba32;\r
+ UINT32 BlockSize;\r
+ UINT32 ByteCount;\r
+ UINT16 SectorCount;\r
+ VOID *PtrBuffer;\r
+ UINT16 MaxBlock;\r
+\r
+ //\r
+ // fill command packet for Write(10) command\r
+ // Write(10) command packet has the same data structure as\r
+ // Read(10) command packet,\r
+ // so here use the Read10Packet data structure\r
+ // for the Write(10) command packet.\r
+ //\r
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
+ Read10Packet = &Packet.Read10;\r
+\r
+ Lba32 = (UINT32) Lba;\r
+ PtrBuffer = Buffer;\r
+\r
+ BlockSize = IdeDev->BlkIo.Media->BlockSize;\r
+\r
+ //\r
+ // limit the data bytes that can be transferred by one Read(10) Command\r
+ //\r
+ MaxBlock = (UINT16) (65536 / BlockSize);\r
+\r
+ BlocksRemaining = NumberOfBlocks;\r
+\r
+ Status = EFI_SUCCESS;\r
+ while (BlocksRemaining > 0) {\r
+\r
+ if (BlocksRemaining >= MaxBlock) {\r
+ SectorCount = MaxBlock;\r
+ } else {\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ }\r
+ \r
+ //\r
+ // Command code is WRITE_10.\r
+ //\r
+ Read10Packet->opcode = WRITE_10;\r
+\r
+ //\r
+ // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
+ // Lba0 is MSB, Lba3 is LSB\r
+ //\r
+ Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r
+ Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r
+ Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r
+ Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r
+\r
+ //\r
+ // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
+ // TranLen0 is MSB, TranLen is LSB\r
+ //\r
+ Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r
+ Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r
+\r
+ ByteCount = SectorCount * BlockSize;\r
+\r
+ Status = AtapiPacketCommandOut (\r
+ IdeDev,\r
+ &Packet,\r
+ (UINT16 *) PtrBuffer,\r
+ ByteCount,\r
+ ATAPILONGTIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Lba32 += SectorCount;\r
+ PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize);\r
+ BlocksRemaining -= SectorCount;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function is used to implement the Soft Reset on the specified\r
+ ATAPI device. Different from the AtaSoftReset(), here reset is a ATA\r
+ Soft Reset Command special for ATAPI device, and it only take effects\r
+ on the specified ATAPI device, not on the whole IDE bus.\r
+ Since the ATAPI soft reset is needed when device is in exceptional\r
+ condition (such as BSY bit is always set ), I think the Soft Reset\r
+ command should be sent without waiting for the BSY clear and DRDY\r
+ set.\r
+ This function is called by IdeBlkIoReset(), \r
+ a interface function of Block I/O protocol.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @retval EFI_SUCCESS\r
+ Soft reset completes successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Any step during the reset process is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiSoftReset (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ UINT8 Command;\r
+ UINT8 DeviceSelect;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // for ATAPI device, no need to wait DRDY ready after device selecting.\r
+ // (bit7 and bit5 are both set to 1 for backward compatibility)\r
+ //\r
+ DeviceSelect = (UINT8) (((bit7 | bit5) | (IdeDev->Device << 4)));\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
+\r
+ Command = ATAPI_SOFT_RESET_CMD;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command);\r
+\r
+ //\r
+ // BSY cleared is the only status return to the host by the device\r
+ // when reset is completed.\r
+ // slave device needs at most 31s to clear BSY\r
+ //\r
+ Status = WaitForBSYClear (IdeDev, 31000);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ \r
+ //\r
+ // stall 5 seconds to make the device status stable\r
+ //\r
+ gBS->Stall (5000000);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is the ATAPI implementation for ReadBlocks in the\r
+ Block I/O Protocol interface.\r
+\r
+ @param[in] *IdeBlkIoDev\r
+ Indicates the calling context.\r
+\r
+ @param[in] MediaId\r
+ The media id that the read request is for.\r
+\r
+ @param[in] LBA\r
+ The starting logical block address to read from \r
+ on the device.\r
+\r
+ @param[in] BufferSize\r
+ The size of the Buffer in bytes. This must be a\r
+ multiple of the intrinsic block size of the device.\r
+\r
+ @param[out] *Buffer\r
+ A pointer to the destination buffer for the data. \r
+ The caller is responsible for either having implicit\r
+ or explicit ownership of the memory that data is read into.\r
+\r
+ @retval EFI_SUCCESS\r
+ Read Blocks successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Read Blocks failed.\r
+ \r
+ @retval EFI_NO_MEDIA\r
+ There is no media in the device.\r
+ \r
+ @retval EFI_MEDIA_CHANGED\r
+ The MediaId is not for the current media.\r
+ \r
+ @retval EFI_BAD_BUFFER_SIZE\r
+ The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ \r
+ @retval EFI_INVALID_PARAMETER\r
+ The read request contains LBAs that are not valid,\r
+ or the data buffer is not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiBlkIoReadBlocks (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ EFI_STATUS Status;\r
+\r
+ BOOLEAN MediaChange;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // ATAPI device media is removable, so it is a must\r
+ // to detect media first before read operation\r
+ //\r
+ MediaChange = FALSE;\r
+ Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ if (IdeBlkIoDevice->Cache != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->Cache);\r
+ IdeBlkIoDevice->Cache = NULL;\r
+ }\r
+\r
+ return Status;\r
+ }\r
+ //\r
+ // Get the intrinsic block size\r
+ //\r
+ Media = IdeBlkIoDevice->BlkIo.Media;\r
+ BlockSize = Media->BlockSize;\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+ if (!(Media->MediaPresent)) {\r
+\r
+ if (IdeBlkIoDevice->Cache != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->Cache);\r
+ IdeBlkIoDevice->Cache = NULL;\r
+ }\r
+ return EFI_NO_MEDIA;\r
+\r
+ }\r
+\r
+ if ((MediaId != Media->MediaId) || MediaChange) {\r
+\r
+ if (IdeBlkIoDevice->Cache != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->Cache);\r
+ IdeBlkIoDevice->Cache = NULL;\r
+ }\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (BufferSize % BlockSize != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (LBA > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // if all the parameters are valid, then perform read sectors command\r
+ // to transfer data from device to host.\r
+ //\r
+ Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ \r
+ //\r
+ // Read blocks succeeded\r
+ //\r
+ \r
+ //\r
+ // save the first block to the cache for performance\r
+ //\r
+ if (LBA == 0 && !IdeBlkIoDevice->Cache) {\r
+ IdeBlkIoDevice->Cache = AllocatePool (BlockSize);\r
+ if (IdeBlkIoDevice != NULL) {\r
+ CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+ This function is the ATAPI implementation for WriteBlocks in the\r
+ Block I/O Protocol interface.\r
+\r
+ @param[in] *This\r
+ Indicates the calling context.\r
+\r
+ @param[in] MediaId\r
+ The media id that the write request is for.\r
+\r
+ @param[in] LBA\r
+ The starting logical block address to write onto \r
+ the device.\r
+\r
+ @param[in] BufferSize\r
+ The size of the Buffer in bytes. This must be a\r
+ multiple of the intrinsic block size of the device.\r
+\r
+ @param[out] *Buffer\r
+ A pointer to the source buffer for the data. \r
+ The caller is responsible for either having implicit\r
+ or explicit ownership of the memory that data is \r
+ written from.\r
+\r
+ @retval EFI_SUCCESS\r
+ Write Blocks successfully.\r
+ \r
+ @retval EFI_DEVICE_ERROR\r
+ Write Blocks failed.\r
+ \r
+ @retval EFI_NO_MEDIA\r
+ There is no media in the device.\r
+ \r
+ @retval EFI_MEDIA_CHANGE\r
+ The MediaId is not for the current media.\r
+ \r
+ @retval EFI_BAD_BUFFER_SIZE\r
+ The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ \r
+ @retval EFI_INVALID_PARAMETER\r
+ The write request contains LBAs that are not valid,\r
+ or the data buffer is not valid.\r
+\r
+ TODO: EFI_MEDIA_CHANGED - add return value to function comment\r
+ TODO: EFI_WRITE_PROTECTED - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtapiBlkIoWriteBlocks (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ EFI_STATUS Status;\r
+ BOOLEAN MediaChange;\r
+\r
+ if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
+ gBS->FreePool (IdeBlkIoDevice->Cache);\r
+ IdeBlkIoDevice->Cache = NULL;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // ATAPI device media is removable,\r
+ // so it is a must to detect media first before write operation\r
+ //\r
+ MediaChange = FALSE;\r
+ Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
+ gBS->FreePool (IdeBlkIoDevice->Cache);\r
+ IdeBlkIoDevice->Cache = NULL;\r
+ }\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Get the intrinsic block size\r
+ //\r
+ Media = IdeBlkIoDevice->BlkIo.Media;\r
+ BlockSize = Media->BlockSize;\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+ if (!(Media->MediaPresent)) {\r
+\r
+ if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
+ gBS->FreePool (IdeBlkIoDevice->Cache);\r
+ IdeBlkIoDevice->Cache = NULL;\r
+ }\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ if ((MediaId != Media->MediaId) || MediaChange) {\r
+\r
+ if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
+ gBS->FreePool (IdeBlkIoDevice->Cache);\r
+ IdeBlkIoDevice->Cache = NULL;\r
+ }\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (Media->ReadOnly) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ if (BufferSize % BlockSize != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (LBA > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // if all the parameters are valid,\r
+ // then perform write sectors command to transfer data from host to device.\r
+ //\r
+ Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+ This function is used to parse sense data. Only the first\r
+ sense data is honoured.\r
+\r
+ @param[in] IdeDev Indicates the calling context.\r
+ @param[in] SenseCount Count of sense data.\r
+ @param[out] Result The parsed result.\r
+\r
+ @retval EFI_SUCCESS Successfully parsed.\r
+ @retval EFI_INVALID_PARAMETER Count of sense data is zero.\r
+\r
+**/\r
+EFI_STATUS\r
+ParseSenseData (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN SenseCount,\r
+ OUT SENSE_RESULT *Result\r
+ )\r
+{\r
+ REQUEST_SENSE_DATA *SenseData;\r
+\r
+ if (SenseCount == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Only use the first sense data\r
+ //\r
+ SenseData = IdeDev->SenseData;\r
+ *Result = SenseOtherSense;\r
+\r
+ switch (SenseData->sense_key) {\r
+ case SK_NO_SENSE:\r
+ *Result = SenseNoSenseKey;\r
+ break;\r
+ case SK_NOT_READY:\r
+ switch (SenseData->addnl_sense_code) {\r
+ case ASC_NO_MEDIA:\r
+ *Result = SenseNoMedia;\r
+ break;\r
+ case ASC_MEDIA_UPSIDE_DOWN:\r
+ *Result = SenseMediaError;\r
+ break;\r
+ case ASC_NOT_READY:\r
+ if (SenseData->addnl_sense_code_qualifier == ASCQ_IN_PROGRESS) {\r
+ *Result = SenseDeviceNotReadyNeedRetry;\r
+ } else {\r
+ *Result = SenseDeviceNotReadyNoRetry;\r
+ }\r
+ break;\r
+ }\r
+ break;\r
+ case SK_UNIT_ATTENTION:\r
+ if (SenseData->addnl_sense_code == ASC_MEDIA_CHANGE) {\r
+ *Result = SenseMediaChange;\r
+ }\r
+ break;\r
+ case SK_MEDIUM_ERROR:\r
+ switch (SenseData->addnl_sense_code) {\r
+ case ASC_MEDIA_ERR1:\r
+ case ASC_MEDIA_ERR2:\r
+ case ASC_MEDIA_ERR3:\r
+ case ASC_MEDIA_ERR4:\r
+ *Result = SenseMediaError;\r
+ break;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function reads the pending data in the device.\r
+\r
+ @param[in] IdeDev Indicates the calling context.\r
+\r
+ @retval EFI_SUCCESS Successfully read.\r
+ @retval EFI_NOT_READY The BSY is set avoiding reading.\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiReadPendingData (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ UINT8 AltRegister;\r
+ UINT16 TempWordBuffer;\r
+\r
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+ if ((AltRegister & BSY) == BSY) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ if ((AltRegister & (BSY | DRQ)) == DRQ) {\r
+ TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r
+ while ((TempWordBuffer & (BSY | DRQ)) == DRQ) {\r
+ IDEReadPortWMultiple (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Data, \r
+ 1, \r
+ &TempWordBuffer\r
+ );\r
+ TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r
+ }\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param WriteProtected TODO: add argument description\r
+\r
+ @retval EFI_DEVICE_ERROR TODO: Add description for return value\r
+ @retval EFI_DEVICE_ERROR TODO: Add description for return value\r
+ @retval EFI_SUCCESS TODO: Add description for return value\r
+\r
+**/\r
+EFI_STATUS\r
+IsLS120orZipWriteProtected (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT BOOLEAN *WriteProtected\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ *WriteProtected = FALSE;\r
+\r
+ Status = LS120EnableMediaStatus (IdeDev, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // the Get Media Status Command is only valid\r
+ // if a Set Features/Enable Media Status Command has been priviously issued.\r
+ //\r
+ if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) {\r
+\r
+ *WriteProtected = TRUE;\r
+ } else {\r
+\r
+ *WriteProtected = FALSE;\r
+ }\r
+\r
+ //\r
+ // After Get Media Status Command completes,\r
+ // Set Features/Disable Media Command should be sent.\r
+ //\r
+ Status = LS120EnableMediaStatus (IdeDev, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ Copyright (c) 2006, Intel Corporation\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "idebus.h"\r
+\r
+BOOLEAN ChannelDeviceDetected = FALSE;\r
+BOOLEAN SlaveDeviceExist = FALSE;\r
+UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;\r
+BOOLEAN MasterDeviceExist = FALSE;\r
+UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+UINT8\r
+IDEReadPortB (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port\r
+ )\r
+{\r
+ UINT8 Data;\r
+\r
+ Data = 0;\r
+ //\r
+ // perform 1-byte data read from register\r
+ //\r
+ PciIo->Io.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ (UINT64) Port,\r
+ 1,\r
+ &Data\r
+ );\r
+ return Data;\r
+}\r
+\r
+/**\r
+ Reads multiple words of data from the IDE data port.\r
+ Call the IO abstraction once to do the complete read,\r
+ not one word at a time\r
+\r
+ @param PciIo Pointer to the EFI_PCI_IO instance\r
+ @param Port IO port to read\r
+ @param Count No. of UINT16's to read\r
+ @param Buffer Pointer to the data buffer for read\r
+\r
+**/\r
+VOID\r
+IDEReadPortWMultiple (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINTN Count,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ UINT16 *AlignedBuffer;\r
+ UINT16 *WorkingBuffer;\r
+ UINTN Size;\r
+\r
+ //\r
+ // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
+ // not perform actual I/O operations if buffer pointer passed in is not at\r
+ // natural boundary. The "Buffer" argument is passed in by user and may not\r
+ // at 16-bit natural boundary.\r
+ //\r
+ Size = sizeof (UINT16) * Count;\r
+\r
+ gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ Size + 1,\r
+ (VOID**)&WorkingBuffer\r
+ );\r
+\r
+ AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
+\r
+ //\r
+ // Perform UINT16 data read from FIFO\r
+ //\r
+ PciIo->Io.Read (\r
+ PciIo,\r
+ EfiPciIoWidthFifoUint16,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ (UINT64) Port,\r
+ Count,\r
+ (UINT16*)AlignedBuffer\r
+ );\r
+\r
+ //\r
+ // Copy data to user buffer\r
+ //\r
+ CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);\r
+ gBS->FreePool (WorkingBuffer);\r
+}\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+ @param Data TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortB (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINT8 Data\r
+ )\r
+{\r
+ //\r
+ // perform 1-byte data write to register\r
+ //\r
+ PciIo->Io.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ (UINT64) Port,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+ @param Data TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortW (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINT16 Data\r
+ )\r
+{\r
+ //\r
+ // perform 1-word data write to register\r
+ //\r
+ PciIo->Io.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ (UINT64) Port,\r
+ 1,\r
+ &Data\r
+ );\r
+}\r
+\r
+/**\r
+ Write multiple words of data to the IDE data port.\r
+ Call the IO abstraction once to do the complete read,\r
+ not one word at a time\r
+\r
+ @param PciIo Pointer to the EFI_PCI_IO instance\r
+ @param Port IO port to read\r
+ @param Count No. of UINT16's to read\r
+ @param Buffer Pointer to the data buffer for read\r
+\r
+**/\r
+VOID\r
+IDEWritePortWMultiple (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINTN Count,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ UINT16 *AlignedBuffer;\r
+ UINT32 *WorkingBuffer;\r
+ UINTN Size;\r
+\r
+ //\r
+ // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
+ // not perform actual I/O operations if buffer pointer passed in is not at\r
+ // natural boundary. The "Buffer" argument is passed in by user and may not\r
+ // at 16-bit natural boundary.\r
+ //\r
+ Size = sizeof (UINT16) * Count;\r
+\r
+ gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ Size + 1,\r
+ (VOID **) &WorkingBuffer\r
+ );\r
+\r
+ AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
+\r
+ //\r
+ // Copy data from user buffer to working buffer\r
+ //\r
+ CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);\r
+\r
+ //\r
+ // perform UINT16 data write to the FIFO\r
+ //\r
+ PciIo->Io.Write (\r
+ PciIo,\r
+ EfiPciIoWidthFifoUint16,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ (UINT64) Port,\r
+ Count,\r
+ (UINT16 *) AlignedBuffer\r
+ );\r
+\r
+ gBS->FreePool (WorkingBuffer);\r
+}\r
+\r
+//\r
+// GetIdeRegistersBaseAddr\r
+//\r
+/**\r
+ Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
+ use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
+ the PCI IDE controller's Configuration Space.\r
+\r
+ The steps to get IDE IO port registers' base addresses for each channel\r
+ as follows:\r
+\r
+ 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
+ controller's Configuration Space to determine the operating mode.\r
+\r
+ 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
+ <pre>\r
+ ___________________________________________\r
+ | | Command Block | Control Block |\r
+ | Channel | Registers | Registers |\r
+ |___________|_______________|_______________|\r
+ | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
+ |___________|_______________|_______________|\r
+ | Secondary | 170h - 177h | 376h - 377h |\r
+ |___________|_______________|_______________|\r
+\r
+ Table 1. Compatibility resource mappings\r
+ </pre>\r
+\r
+ b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
+ in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
+ <pre>\r
+ ___________________________________________________\r
+ | | Command Block | Control Block |\r
+ | Channel | Registers | Registers |\r
+ |___________|___________________|___________________|\r
+ | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
+ |___________|___________________|___________________|\r
+ | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
+ |___________|___________________|___________________|\r
+\r
+ Table 2. BARs for Register Mapping\r
+ </pre>\r
+ @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for\r
+ primary, 0374h for secondary. So 2 bytes extra offset should be\r
+ added to the base addresses read from BARs.\r
+\r
+ For more details, please refer to PCI IDE Controller Specification and Intel\r
+ ICH4 Datasheet.\r
+\r
+ @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
+ @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to\r
+ receive IDE IO port registers' base addresses\r
+\r
+**/\r
+EFI_STATUS\r
+GetIdeRegistersBaseAddr (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
+ )\r
+// TODO: EFI_UNSUPPORTED - add return value to function comment\r
+// TODO: EFI_UNSUPPORTED - add return value to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ EFI_STATUS Status;\r
+ PCI_TYPE00 PciData;\r
+\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ sizeof (PciData),\r
+ &PciData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
+ IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;\r
+ IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;\r
+ IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
+ (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
+ } else {\r
+ //\r
+ // The BARs should be of IO type\r
+ //\r
+ if ((PciData.Device.Bar[0] & bit0) == 0 ||\r
+ (PciData.Device.Bar[1] & bit0) == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =\r
+ (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
+ IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =\r
+ (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
+ IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
+ }\r
+\r
+ if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
+ IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;\r
+ IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;\r
+ IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
+ } else {\r
+ //\r
+ // The BARs should be of IO type\r
+ //\r
+ if ((PciData.Device.Bar[2] & bit0) == 0 ||\r
+ (PciData.Device.Bar[3] & bit0) == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =\r
+ (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
+ IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =\r
+ (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
+ IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to requery IDE resources. The IDE controller will\r
+ probably switch between native and legacy modes during the EFI->CSM->OS\r
+ transfer. We do this everytime before an BlkIo operation to ensure its\r
+ succeess.\r
+\r
+ @param IdeDev The BLK_IO private data which specifies the IDE device\r
+\r
+**/\r
+EFI_STATUS\r
+ReassignIdeResources (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ EFI_STATUS Status;\r
+ IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];\r
+ UINT16 CommandBlockBaseAddr;\r
+ UINT16 ControlBlockBaseAddr;\r
+\r
+ //\r
+ // Requery IDE IO port registers' base addresses in case of the switch of\r
+ // native and legacy modes\r
+ //\r
+ Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));\r
+ CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;\r
+ ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;\r
+\r
+ IdeDev->IoPort->Data = CommandBlockBaseAddr;\r
+ (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
+ IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
+ IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
+ IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
+ IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
+ IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
+\r
+ (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
+ (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;\r
+ IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
+ IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);\r
+\r
+ IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// DiscoverIdeDevice\r
+//\r
+/**\r
+ Detect if there is disk connected to this port\r
+\r
+ @param IdeDev The BLK_IO private data which specifies the IDE device\r
+\r
+**/\r
+EFI_STATUS\r
+DiscoverIdeDevice (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+// TODO: EFI_NOT_FOUND - add return value to function comment\r
+// TODO: EFI_NOT_FOUND - add return value to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // If a channel has not been checked, check it now. Then set it to "checked" state\r
+ // After this step, all devices in this channel have been checked.\r
+ //\r
+ if (ChannelDeviceDetected == FALSE) {\r
+ Status = DetectIDEController (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ //\r
+ // Device exists. test if it is an ATA device.\r
+ // Prefer the result from DetectIDEController,\r
+ // if failed, try another device type to handle\r
+ // devices that not follow the spec.\r
+ //\r
+ if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
+ if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
+ Status = ATAIdentify (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ATAPIIdentify (IdeDev);\r
+ if (!EFI_ERROR (Status)) {\r
+ MasterDeviceType = ATAPI_DEVICE_TYPE;\r
+ }\r
+ }\r
+ } else {\r
+ Status = ATAPIIdentify (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ATAIdentify (IdeDev);\r
+ if (!EFI_ERROR (Status)) {\r
+ MasterDeviceType = ATA_DEVICE_TYPE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
+ if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
+ Status = ATAIdentify (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ATAPIIdentify (IdeDev);\r
+ if (!EFI_ERROR (Status)) {\r
+ SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
+ }\r
+ }\r
+ } else {\r
+ Status = ATAPIIdentify (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ATAIdentify (IdeDev);\r
+ if (!EFI_ERROR (Status)) {\r
+ SlaveDeviceType = ATA_DEVICE_TYPE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Init Block I/O interface\r
+ //\r
+ IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
+ IdeDev->BlkIo.Reset = IDEBlkIoReset;\r
+ IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;\r
+ IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;\r
+ IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;\r
+\r
+ IdeDev->BlkMedia.LogicalPartition = FALSE;\r
+ IdeDev->BlkMedia.WriteCaching = FALSE;\r
+\r
+ //\r
+ // Init Disk Info interface\r
+ //\r
+ gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));\r
+ IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;\r
+ IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;\r
+ IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;\r
+ IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This interface is used to initialize all state data related to the detection of one\r
+ channel.\r
+\r
+ @retval EFI_SUCCESS Completed Successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeIDEChannelData (\r
+ VOID\r
+ )\r
+{\r
+ ChannelDeviceDetected = FALSE;\r
+ MasterDeviceExist = FALSE;\r
+ MasterDeviceType = 0xff;\r
+ SlaveDeviceExist = FALSE;\r
+ SlaveDeviceType = 0xff;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is called by DiscoverIdeDevice(). It is used for detect\r
+ whether the IDE device exists in the specified Channel as the specified\r
+ Device Number.\r
+\r
+ There is two IDE channels: one is Primary Channel, the other is\r
+ Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
+ Different channel has different register group.\r
+\r
+ On each IDE channel, at most two IDE devices attach,\r
+ one is called Device 0 (Master device), the other is called Device 1\r
+ (Slave device). The devices on the same channel co-use the same register\r
+ group, so before sending out a command for a specified device via command\r
+ register, it is a must to select the current device to accept the command\r
+ by set the device number in the Head/Device Register.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @retval TRUE\r
+ successfully detects device.\r
+\r
+ @retval FALSE\r
+ any failure during detection process will return this\r
+ value.\r
+\r
+ @note\r
+ TODO: EFI_SUCCESS - add return value to function comment\r
+ TODO: EFI_NOT_FOUND - add return value to function comment\r
+\r
+**/\r
+EFI_STATUS\r
+DetectIDEController (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 SectorCountReg;\r
+ UINT8 LBALowReg;\r
+ UINT8 LBAMidReg;\r
+ UINT8 LBAHighReg;\r
+ UINT8 InitStatusReg;\r
+ UINT8 StatusReg;\r
+\r
+ //\r
+ // Select slave device\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((1 << 4) | 0xe0)\r
+ );\r
+ gBS->Stall (100);\r
+\r
+ //\r
+ // Save the init slave status register\r
+ //\r
+ InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+ //\r
+ // Select Master back\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((0 << 4) | 0xe0)\r
+ );\r
+ gBS->Stall (100);\r
+\r
+ //\r
+ // Send ATA Device Execut Diagnostic command.\r
+ // This command should work no matter DRDY is ready or not\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
+\r
+ Status = WaitForBSYClear (IdeDev, 3500);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Read device signature\r
+ //\r
+ //\r
+ // Select Master\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((0 << 4) | 0xe0)\r
+ );\r
+ gBS->Stall (100);\r
+ SectorCountReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->SectorCount\r
+ );\r
+ LBALowReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->SectorNumber\r
+ );\r
+ LBAMidReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderLsb\r
+ );\r
+ LBAHighReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderMsb\r
+ );\r
+ if ((SectorCountReg == 0x1) &&\r
+ (LBALowReg == 0x1) &&\r
+ (LBAMidReg == 0x0) &&\r
+ (LBAHighReg == 0x0)) {\r
+ MasterDeviceExist = TRUE;\r
+ MasterDeviceType = ATA_DEVICE_TYPE;\r
+ } else {\r
+ if ((LBAMidReg == 0x14) &&\r
+ (LBAHighReg == 0xeb)) {\r
+ MasterDeviceExist = TRUE;\r
+ MasterDeviceType = ATAPI_DEVICE_TYPE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // For some Hard Drive, it takes some time to get\r
+ // the right signature when operating in single slave mode.\r
+ // We stall 20ms to work around this.\r
+ //\r
+ if (!MasterDeviceExist) {\r
+ gBS->Stall (20000);\r
+ }\r
+\r
+ //\r
+ // Select Slave\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((1 << 4) | 0xe0)\r
+ );\r
+ gBS->Stall (100);\r
+ SectorCountReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->SectorCount\r
+ );\r
+ LBALowReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->SectorNumber\r
+ );\r
+ LBAMidReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderLsb\r
+ );\r
+ LBAHighReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderMsb\r
+ );\r
+ StatusReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Reg.Status\r
+ );\r
+ if ((SectorCountReg == 0x1) &&\r
+ (LBALowReg == 0x1) &&\r
+ (LBAMidReg == 0x0) &&\r
+ (LBAHighReg == 0x0)) {\r
+ SlaveDeviceExist = TRUE;\r
+ SlaveDeviceType = ATA_DEVICE_TYPE;\r
+ } else {\r
+ if ((LBAMidReg == 0x14) &&\r
+ (LBAHighReg == 0xeb)) {\r
+ SlaveDeviceExist = TRUE;\r
+ SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // When single master is plugged, slave device\r
+ // will be wrongly detected. Here's the workaround\r
+ // for ATA devices by detecting DRY bit in status\r
+ // register.\r
+ // NOTE: This workaround doesn't apply to ATAPI.\r
+ //\r
+ if (MasterDeviceExist && SlaveDeviceExist &&\r
+ (StatusReg & DRDY) == 0 &&\r
+ (InitStatusReg & DRDY) == 0 &&\r
+ MasterDeviceType == SlaveDeviceType &&\r
+ SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
+ SlaveDeviceExist = FALSE;\r
+ }\r
+\r
+ //\r
+ // Indicate this channel has been detected\r
+ //\r
+ ChannelDeviceDetected = TRUE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to poll for the DRQ bit clear in the Status\r
+ Register. DRQ is cleared when the device is finished transferring data.\r
+ So this function is called after data transfer is finished.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ clear.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRQ bit clear within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRQ bit not clear within the time out.\r
+\r
+ @note\r
+ Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQClear (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+// TODO: EFI_ABORTED - add return value to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 StatusRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+ //\r
+ // wait for BSY == 0 and DRQ == 0\r
+ //\r
+ if ((StatusRegister & (DRQ | BSY)) == 0) {\r
+ break;\r
+ }\r
+\r
+ if ((StatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Stall for 30 us\r
+ //\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to poll for the DRQ bit clear in the Alternate\r
+ Status Register. DRQ is cleared when the device is finished\r
+ transferring data. So this function is called after data transfer\r
+ is finished.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ clear.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRQ bit clear within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRQ bit not clear within the time out.\r
+\r
+ @note\r
+ Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQClear2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+// TODO: EFI_ABORTED - add return value to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 AltRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+\r
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+\r
+ //\r
+ // wait for BSY == 0 and DRQ == 0\r
+ //\r
+ if ((AltRegister & (DRQ | BSY)) == 0) {\r
+ break;\r
+ }\r
+\r
+ if ((AltRegister & (BSY | ERR)) == ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Stall for 30 us\r
+ //\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to poll for the DRQ bit set in the\r
+ Status Register.\r
+ DRQ is set when the device is ready to transfer data. So this function\r
+ is called after the command is sent to the device and before required\r
+ data is transferred.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRQ bit set within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRQ bit not set within the time out.\r
+\r
+ @retval EFI_ABORTED\r
+ DRQ bit not set caused by the command abort.\r
+\r
+ @note\r
+ Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQReady (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 StatusRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+ //\r
+ // read Status Register will clear interrupt\r
+ //\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+ //\r
+ // BSY==0,DRQ==1\r
+ //\r
+ if ((StatusRegister & (BSY | DRQ)) == DRQ) {\r
+ break;\r
+ }\r
+\r
+ if ((StatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Stall for 30 us\r
+ //\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to poll for the DRQ bit set in the\r
+ Alternate Status Register. DRQ is set when the device is ready to\r
+ transfer data. So this function is called after the command\r
+ is sent to the device and before required data is transferred.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRQ bit set within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRQ bit not set within the time out.\r
+\r
+ @retval EFI_ABORTED\r
+ DRQ bit not set caused by the command abort.\r
+\r
+ @note\r
+ Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQReady2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 AltRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+\r
+ do {\r
+ //\r
+ // Read Alternate Status Register will not clear interrupt status\r
+ //\r
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+ //\r
+ // BSY == 0 , DRQ == 1\r
+ //\r
+ if ((AltRegister & (BSY | DRQ)) == DRQ) {\r
+ break;\r
+ }\r
+\r
+ if ((AltRegister & (BSY | ERR)) == ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Stall for 30 us\r
+ //\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to poll for the BSY bit clear in the\r
+ Status Register. BSY is clear when the device is not busy.\r
+ Every command must be sent after device is not busy.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ BSY bit clear within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ BSY bit not clear within the time out.\r
+\r
+ @note\r
+ Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 StatusRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+ if ((StatusRegister & BSY) == 0x00) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Stall for 30 us\r
+ //\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+//\r
+// WaitForBSYClear2\r
+//\r
+/**\r
+ This function is used to poll for the BSY bit clear in the\r
+ Alternate Status Register. BSY is clear when the device is not busy.\r
+ Every command must be sent after device is not busy.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ BSY bit clear within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ BSY bit not clear within the time out.\r
+\r
+ @note\r
+ Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 AltRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+ if ((AltRegister & BSY) == 0x00) {\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// DRDYReady\r
+//\r
+/**\r
+ This function is used to poll for the DRDY bit set in the\r
+ Status Register. DRDY bit is set when the device is ready\r
+ to accept command. Most ATA commands must be sent after\r
+ DRDY set except the ATAPI Packet Command.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRDY bit set within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRDY bit not set within the time out.\r
+\r
+ @note\r
+ Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRDYReady (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN DelayInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: DelayInMilliSeconds - add argument and description to function comment\r
+// TODO: EFI_ABORTED - add return value to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 StatusRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+ //\r
+ // BSY == 0 , DRDY == 1\r
+ //\r
+ if ((StatusRegister & (DRDY | BSY)) == DRDY) {\r
+ break;\r
+ }\r
+\r
+ if ((StatusRegister & (BSY | ERR)) == ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// DRDYReady2\r
+//\r
+/**\r
+ This function is used to poll for the DRDY bit set in the\r
+ Alternate Status Register. DRDY bit is set when the device is ready\r
+ to accept command. Most ATA commands must be sent after\r
+ DRDY set except the ATAPI Packet Command.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRDY bit set within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRDY bit not set within the time out.\r
+\r
+ @note\r
+ Read Alternate Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRDYReady2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN DelayInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: DelayInMilliSeconds - add argument and description to function comment\r
+// TODO: EFI_ABORTED - add return value to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 AltRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+ //\r
+ // BSY == 0 , DRDY == 1\r
+ //\r
+ if ((AltRegister & (DRDY | BSY)) == DRDY) {\r
+ break;\r
+ }\r
+\r
+ if ((AltRegister & (BSY | ERR)) == ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// SwapStringChars\r
+//\r
+/**\r
+ This function is a helper function used to change the char order in a\r
+ string. It is designed specially for the PrintAtaModuleName() function.\r
+ After the IDE device is detected, the IDE driver gets the device module\r
+ name by sending ATA command called ATA Identify Command or ATAPI\r
+ Identify Command to the specified IDE device. The module name returned\r
+ is a string of ASCII characters: the first character is bit8--bit15\r
+ of the first word, the second character is bit0--bit7 of the first word\r
+ and so on. Thus the string can not be print directly before it is\r
+ preprocessed by this func to change the order of characters in\r
+ each word in the string.\r
+\r
+ @param[in] CHAR8 IN *Destination\r
+ Indicates the destination string.\r
+\r
+ @param[in] CHAR8 IN *Source\r
+ Indicates the source string.\r
+\r
+ @param[in] UINT8 IN Size\r
+ the length of the string\r
+\r
+**/\r
+VOID\r
+SwapStringChars (\r
+ IN CHAR8 *Destination,\r
+ IN CHAR8 *Source,\r
+ IN UINT32 Size\r
+ )\r
+{\r
+ UINT32 Index;\r
+ CHAR8 Temp;\r
+\r
+ for (Index = 0; Index < Size; Index += 2) {\r
+\r
+ Temp = Source[Index + 1];\r
+ Destination[Index + 1] = Source[Index];\r
+ Destination[Index] = Temp;\r
+ }\r
+}\r
+\r
+//\r
+// ReleaseIdeResources\r
+//\r
+/**\r
+ Release resources of an IDE device before stopping it.\r
+\r
+ @param[in] *IdeBlkIoDevice Standard IDE device private data structure\r
+\r
+**/\r
+VOID\r
+ReleaseIdeResources (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
+ )\r
+{\r
+ if (IdeBlkIoDevice == NULL) {\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
+ //\r
+\r
+ if (IdeBlkIoDevice->SenseData != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->SenseData);\r
+ IdeBlkIoDevice->SenseData = NULL;\r
+ }\r
+\r
+ if (IdeBlkIoDevice->Cache != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->Cache);\r
+ IdeBlkIoDevice->Cache = NULL;\r
+ }\r
+\r
+ if (IdeBlkIoDevice->pIdData != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->pIdData);\r
+ IdeBlkIoDevice->pIdData = NULL;\r
+ }\r
+\r
+ if (IdeBlkIoDevice->pInquiryData != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->pInquiryData);\r
+ IdeBlkIoDevice->pInquiryData = NULL;\r
+ }\r
+\r
+ if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
+ FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
+ IdeBlkIoDevice->ControllerNameTable = NULL;\r
+ }\r
+\r
+ if (IdeBlkIoDevice->IoPort != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->IoPort);\r
+ }\r
+\r
+ if (IdeBlkIoDevice->DevicePath != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
+ }\r
+\r
+ if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
+ gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
+ IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
+ }\r
+\r
+ gBS->FreePool (IdeBlkIoDevice);\r
+ IdeBlkIoDevice = NULL;\r
+\r
+ return ;\r
+}\r
+\r
+//\r
+// SetDeviceTransferMode\r
+//\r
+/**\r
+ Set the calculated Best transfer mode to a detected device\r
+\r
+ @param[in] *IdeDev Standard IDE device private data structure\r
+ @param[in] *TransferMode The device transfer mode to be set\r
+\r
+ @return Set transfer mode Command execute status\r
+\r
+**/\r
+EFI_STATUS\r
+SetDeviceTransferMode (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN ATA_TRANSFER_MODE *TransferMode\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 DeviceSelect;\r
+ UINT8 SectorCount;\r
+\r
+ DeviceSelect = 0;\r
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
+ SectorCount = *((UINT8 *) TransferMode);\r
+\r
+ //\r
+ // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
+ //\r
+ Status = AtaNonDataCommandIn (\r
+ IdeDev,\r
+ SET_FEATURES_CMD,\r
+ DeviceSelect,\r
+ 0x03,\r
+ SectorCount,\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send ATA command into device with NON_DATA protocol\r
+\r
+ @param IdeDev Standard IDE device private data structure\r
+ @param AtaCommand The ATA command to be sent\r
+ @param Device The value in Device register\r
+ @param Feature The value in Feature register\r
+ @param SectorCount The value in SectorCount register\r
+ @param LbaLow The value in LBA_LOW register\r
+ @param LbaMiddle The value in LBA_MIDDLE register\r
+ @param LbaHigh The value in LBA_HIGH register\r
+\r
+ @retval EFI_SUCCESS Reading succeed\r
+ @retval EFI_ABORTED Command failed\r
+ @retval EFI_DEVICE_ERROR Device status error\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandIn (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT8 Feature,\r
+ IN UINT8 SectorCount,\r
+ IN UINT8 LbaLow,\r
+ IN UINT8 LbaMiddle,\r
+ IN UINT8 LbaHigh\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 StatusRegister;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+ );\r
+\r
+ //\r
+ // ATA commands for ATA device must be issued when DRDY is set\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Pass parameter into device register block\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ //\r
+ // Send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ //\r
+ // Wait for command completion\r
+ // For ATA_SMART_CMD, we may need more timeout to let device\r
+ // adjust internal states.\r
+ //\r
+ if (AtaCommand == ATA_SMART_CMD) {\r
+ Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r
+ } else {\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+ if ((StatusRegister & ERR) == ERR) {\r
+ //\r
+ // Failed to execute command, abort operation\r
+ //\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send ATA Ext command into device with NON_DATA protocol\r
+\r
+ @param IdeDev Standard IDE device private data structure\r
+ @param AtaCommand The ATA command to be sent\r
+ @param Device The value in Device register\r
+ @param Feature The value in Feature register\r
+ @param SectorCount The value in SectorCount register\r
+ @param LbaAddress The LBA address in 48-bit mode\r
+\r
+ @retval EFI_SUCCESS Reading succeed\r
+ @retval EFI_ABORTED Command failed\r
+ @retval EFI_DEVICE_ERROR Device status error\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandInExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT16 Feature,\r
+ IN UINT16 SectorCount,\r
+ IN EFI_LBA LbaAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 StatusRegister;\r
+ UINT8 SectorCount8;\r
+ UINT8 Feature8;\r
+ UINT8 LbaLow;\r
+ UINT8 LbaMid;\r
+ UINT8 LbaHigh;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+ );\r
+\r
+ //\r
+ // ATA commands for ATA device must be issued when DRDY is set\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Pass parameter into device register block\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+\r
+ //\r
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ Feature8 = (UINT8) (Feature >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+ Feature8 = (UINT8) Feature;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+ //\r
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ SectorCount8 = (UINT8) (SectorCount >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ SectorCount8 = (UINT8) SectorCount;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ //\r
+ // Fill the start LBA registers, which are also two-byte FIFO\r
+ //\r
+ LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ LbaLow = (UINT8) LbaAddress;\r
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ //\r
+ // Send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ //\r
+ // Wait for command completion\r
+ //\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+ if ((StatusRegister & ERR) == ERR) {\r
+ //\r
+ // Failed to execute command, abort operation\r
+ //\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// SetDriveParameters\r
+//\r
+/**\r
+ Set drive parameters for devices not support PACKETS command\r
+\r
+ @param[in] IdeDev Standard IDE device private data structure\r
+ @param[in] DriveParameters The device parameters to be set into the disk\r
+\r
+ @return SetParameters Command execute status\r
+\r
+**/\r
+EFI_STATUS\r
+SetDriveParameters (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN ATA_DRIVE_PARMS *DriveParameters\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 DeviceSelect;\r
+\r
+ DeviceSelect = 0;\r
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
+\r
+ //\r
+ // Send Init drive parameters\r
+ //\r
+ Status = AtaNonDataCommandIn (\r
+ IdeDev,\r
+ INIT_DRIVE_PARAM_CMD,\r
+ (UINT8) (DeviceSelect + DriveParameters->Heads),\r
+ 0,\r
+ DriveParameters->Sector,\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+\r
+ //\r
+ // Send Set Multiple parameters\r
+ //\r
+ Status = AtaNonDataCommandIn (\r
+ IdeDev,\r
+ SET_MULTIPLE_MODE_CMD,\r
+ DeviceSelect,\r
+ 0,\r
+ DriveParameters->MultipleSector,\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ @retval EFI_SUCCESS TODO: Add description for return value\r
+\r
+**/\r
+EFI_STATUS\r
+EnableInterrupt (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ UINT8 DeviceControl;\r
+\r
+ //\r
+ // Enable interrupt for DMA operation\r
+ //\r
+ DeviceControl = 0;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.\r
+\r
+ @param[in] Event Pointer to this event\r
+ @param[in] Context Event hanlder private data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ClearInterrupt (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 IoPortForBmis;\r
+ UINT8 RegisterValue;\r
+ IDE_BLK_IO_DEV *IdeDev;\r
+\r
+ //\r
+ // Get our context\r
+ //\r
+ IdeDev = (IDE_BLK_IO_DEV *) Context;\r
+\r
+ //\r
+ // Obtain IDE IO port registers' base addresses\r
+ //\r
+ Status = ReassignIdeResources (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Check whether interrupt is pending\r
+ //\r
+\r
+ //\r
+ // Reset IDE device to force it de-assert interrupt pin\r
+ // Note: this will reset all devices on this IDE channel\r
+ //\r
+ AtaSoftReset (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Get base address of IDE Bus Master Status Regsiter\r
+ //\r
+ if (IdePrimary == IdeDev->Channel) {\r
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
+ } else {\r
+ if (IdeSecondary == IdeDev->Channel) {\r
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
+ } else {\r
+ return;\r
+ }\r
+ }\r
+ //\r
+ // Read BMIS register and clear ERROR and INTR bit\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ //\r
+ // Select the other device on this channel to ensure this device to release the interrupt pin\r
+ //\r
+ if (IdeDev->Device == 0) {\r
+ RegisterValue = (1 << 4) | 0xe0;\r
+ } else {\r
+ RegisterValue = (0 << 4) | 0xe0;\r
+ }\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ RegisterValue\r
+ );\r
+\r
+}\r
--- /dev/null
+/** @file\r
+ Header file for IDE Bus Driver, containing the helper functions'\r
+ entire prototype.\r
+\r
+ Copyright (c) 2006 - 2007 Intel Corporation. <BR>\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+ @par Revision Reference:\r
+ 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including\r
+ Add - IDEBlkIoReadBlocksExt() func definition\r
+ Add - IDEBlkIoWriteBlocksExt() func definition\r
+\r
+**/\r
+\r
+#ifndef _IDE_H\r
+#define _IDE_H\r
+\r
+//\r
+// Helper functions Prototype\r
+//\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param This TODO: add argument description\r
+ @param Controller TODO: add argument description\r
+ @param Handle TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DeRegisterIdeDevice (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_HANDLE Handle\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param Controller TODO: add argument description\r
+ @param PciIo TODO: add argument description\r
+ @param ParentDevicePath TODO: add argument description\r
+ @param RemainingDevicePath TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+EnableIdeDevice (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+UINT8\r
+IDEReadPortB (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+ @param Count TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEReadPortWMultiple (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINTN Count,\r
+ OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+ @param Data TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortB (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINT8 Data\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+ @param Data TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortW (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINT16 Data\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+ @param Count TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortWMultiple (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINTN Count,\r
+ IN VOID *Buffer\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param IdeRegsBaseAddr TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+GetIdeRegistersBaseAddr (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+ReassignIdeResources (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DiscoverIdeDevice (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ This interface is used to initialize all state data related to the\r
+ detection of one channel.\r
+\r
+ @retval EFI_SUCCESS Completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeIDEChannelData (\r
+ VOID\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DetectIDEController (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param TimeoutInMilliSeconds TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRQClear (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param TimeoutInMilliSeconds TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRQClear2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param TimeoutInMilliSeconds TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRQReady (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param TimeoutInMilliSeconds TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRQReady2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param TimeoutInMilliSeconds TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param TimeoutInMilliSeconds TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param DelayInMilliSeconds TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRDYReady (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN DelayInMilliSeconds\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param DelayInMilliSeconds TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+DRDYReady2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN DelayInMilliSeconds\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param Destination TODO: add argument description\r
+ @param Source TODO: add argument description\r
+ @param Size TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+SwapStringChars (\r
+ IN CHAR8 *Destination,\r
+ IN CHAR8 *Source,\r
+ IN UINT32 Size\r
+ )\r
+;\r
+\r
+//\r
+// ATA device functions' prototype\r
+//\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+ATAIdentify (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+PrintAtaModuleName (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+ @param ByteCount TODO: add argument description\r
+ @param AtaCommand TODO: add argument description\r
+ @param Head TODO: add argument description\r
+ @param SectorCount TODO: add argument description\r
+ @param SectorNumber TODO: add argument description\r
+ @param CylinderLsb TODO: add argument description\r
+ @param CylinderMsb TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataIn (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Head,\r
+ IN UINT8 SectorCount,\r
+ IN UINT8 SectorNumber,\r
+ IN UINT8 CylinderLsb,\r
+ IN UINT8 CylinderMsb\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+ @param ByteCount TODO: add argument description\r
+ @param AtaCommand TODO: add argument description\r
+ @param Head TODO: add argument description\r
+ @param SectorCount TODO: add argument description\r
+ @param SectorNumber TODO: add argument description\r
+ @param CylinderLsb TODO: add argument description\r
+ @param CylinderMsb TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataOut (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Head,\r
+ IN UINT8 SectorCount,\r
+ IN UINT8 SectorNumber,\r
+ IN UINT8 CylinderLsb,\r
+ IN UINT8 CylinderMsb\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+CheckErrorStatus (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param DataBuffer TODO: add argument description\r
+ @param Lba TODO: add argument description\r
+ @param NumberOfBlocks TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaReadSectors (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param BufferData TODO: add argument description\r
+ @param Lba TODO: add argument description\r
+ @param NumberOfBlocks TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaWriteSectors (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *BufferData,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaSoftReset (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeBlkIoDevice TODO: add argument description\r
+ @param MediaId TODO: add argument description\r
+ @param LBA TODO: add argument description\r
+ @param BufferSize TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaBlkIoReadBlocks (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeBlkIoDevice TODO: add argument description\r
+ @param MediaId TODO: add argument description\r
+ @param LBA TODO: add argument description\r
+ @param BufferSize TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaBlkIoWriteBlocks (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+//\r
+// ATAPI device functions' prototype\r
+//\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+ATAPIIdentify (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiInquiry (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param Packet TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+ @param ByteCount TODO: add argument description\r
+ @param TimeOut TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiPacketCommandIn (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN ATAPI_PACKET_COMMAND *Packet,\r
+ IN UINT16 *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINTN TimeOut\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param Packet TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+ @param ByteCount TODO: add argument description\r
+ @param TimeOut TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiPacketCommandOut (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN ATAPI_PACKET_COMMAND *Packet,\r
+ IN UINT16 *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN UINTN TimeOut\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+ @param ByteCount TODO: add argument description\r
+ @param Read TODO: add argument description\r
+ @param TimeOut TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+PioReadWriteData (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT16 *Buffer,\r
+ IN UINT32 ByteCount,\r
+ IN BOOLEAN Read,\r
+ IN UINTN TimeOut\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiTestUnitReady (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT UINTN *SenseCount\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param SenseCounts TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiRequestSense (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT UINTN *SenseCounts\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiReadCapacity (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT UINTN *SenseCount\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param MediaChange TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiDetectMedia (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT BOOLEAN *MediaChange\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+ @param Lba TODO: add argument description\r
+ @param NumberOfBlocks TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiReadSectors (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *Buffer,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+ @param Lba TODO: add argument description\r
+ @param NumberOfBlocks TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiWriteSectors (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *Buffer,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiSoftReset (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeBlkIoDevice TODO: add argument description\r
+ @param MediaId TODO: add argument description\r
+ @param LBA TODO: add argument description\r
+ @param BufferSize TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiBlkIoReadBlocks (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeBlkIoDevice TODO: add argument description\r
+ @param MediaId TODO: add argument description\r
+ @param LBA TODO: add argument description\r
+ @param BufferSize TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiBlkIoWriteBlocks (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param SenseCount TODO: add argument description\r
+ @param Result TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+ParseSenseData (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN SenseCount,\r
+ OUT SENSE_RESULT *Result\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtapiReadPendingData (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param WriteProtected TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+IsLS120orZipWriteProtected (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT BOOLEAN *WriteProtected\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeBlkIoDevice TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+ReleaseIdeResources (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param TransferMode TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+SetDeviceTransferMode (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN ATA_TRANSFER_MODE *TransferMode\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param NativeMaxAddress TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+ReadNativeMaxAddress (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ OUT EFI_LBA *NativeMaxAddress\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param MaxAddress TODO: add argument description\r
+ @param bVolatile TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+SetMaxAddress (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN EFI_LBA MaxAddress,\r
+ IN BOOLEAN bVolatile\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param AtaCommand TODO: add argument description\r
+ @param Device TODO: add argument description\r
+ @param Feature TODO: add argument description\r
+ @param SectorCount TODO: add argument description\r
+ @param LbaLow TODO: add argument description\r
+ @param LbaMiddle TODO: add argument description\r
+ @param LbaHigh TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandIn (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT8 Feature,\r
+ IN UINT8 SectorCount,\r
+ IN UINT8 LbaLow,\r
+ IN UINT8 LbaMiddle,\r
+ IN UINT8 LbaHigh\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param AtaCommand TODO: add argument description\r
+ @param Device TODO: add argument description\r
+ @param Feature TODO: add argument description\r
+ @param SectorCount TODO: add argument description\r
+ @param LbaAddress TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandInExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT16 Feature,\r
+ IN UINT16 SectorCount,\r
+ IN EFI_LBA LbaAddress\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param DataBuffer TODO: add argument description\r
+ @param StartLba TODO: add argument description\r
+ @param NumberOfBlocks TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaReadSectorsExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param DataBuffer TODO: add argument description\r
+ @param StartLba TODO: add argument description\r
+ @param NumberOfBlocks TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaWriteSectorsExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param DataBuffer TODO: add argument description\r
+ @param StartLba TODO: add argument description\r
+ @param NumberOfBlocks TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmaReadExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param DataBuffer TODO: add argument description\r
+ @param StartLba TODO: add argument description\r
+ @param NumberOfBlocks TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmaRead (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param DataBuffer TODO: add argument description\r
+ @param StartLba TODO: add argument description\r
+ @param NumberOfBlocks TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWriteExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+;\r
+\r
+/**\r
+ Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
+ \r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer\r
+ A pointer to the source buffer for the data.\r
+\r
+ @param[in] StartLba\r
+ The starting logical block address to write to\r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+ \r
+ @param[in] UdmaOp\r
+ The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r
+ AtaUdmaWriteOp, AtaUdmaWriteExOp\r
+\r
+ @return The device status of UDMA operation. If the operation is\r
+ successful, return EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+DoAtaUdma (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks,\r
+ IN ATA_UDMA_OPERATION UdmaOp\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param DataBuffer TODO: add argument description\r
+ @param StartLba TODO: add argument description\r
+ @param NumberOfBlocks TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWrite (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param AtaCommand TODO: add argument description\r
+ @param Device TODO: add argument description\r
+ @param Feature TODO: add argument description\r
+ @param SectorCount TODO: add argument description\r
+ @param LbaAddress TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaCommandIssueExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT16 Feature,\r
+ IN UINT16 SectorCount,\r
+ IN EFI_LBA LbaAddress\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param AtaCommand TODO: add argument description\r
+ @param Device TODO: add argument description\r
+ @param Feature TODO: add argument description\r
+ @param SectorCount TODO: add argument description\r
+ @param LbaAddress TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaCommandIssue (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT16 Feature,\r
+ IN UINT16 SectorCount,\r
+ IN EFI_LBA LbaAddress\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaAtapi6Identify (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+AtaSMARTSupport (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+ @param Buffer TODO: add argument description\r
+ @param ByteCount TODO: add argument description\r
+ @param AtaCommand TODO: add argument description\r
+ @param StartLba TODO: add argument description\r
+ @param SectorCount TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPioDataInExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r