From ad86a50ae7fb2ef9db89b22e0b94d54748ffb24f Mon Sep 17 00:00:00 2001 From: qhuang8 Date: Tue, 22 Dec 2009 07:35:49 +0000 Subject: [PATCH] Add new UEFI driver AtaBusDxe: 1. Layer on UEFI 2.2 ATA pass through protocol to perform ATA transaction. 2. Produce Block IO and DiskInfo protocol for each ATA devices. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9585 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c | 1117 +++++++++++++++++ MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h | 647 ++++++++++ MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf | 70 ++ .../Bus/Ata/AtaBusDxe/AtaPassThruExecute.c | 498 ++++++++ .../Bus/Ata/AtaBusDxe/ComponentName.c | 238 ++++ MdeModulePkg/MdeModulePkg.dsc | 1 + 6 files changed, 2571 insertions(+) create mode 100644 MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c create mode 100644 MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h create mode 100644 MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf create mode 100644 MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c create mode 100644 MdeModulePkg/Bus/Ata/AtaBusDxe/ComponentName.c diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c new file mode 100644 index 0000000000..e46b071a73 --- /dev/null +++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c @@ -0,0 +1,1117 @@ +/** @file + This file implements protocol interfaces for ATA bus driver. + + This file implements protocol interfaces: Driver Binding protocol, + Block IO protocol and DiskInfo protocol. + + Copyright (c) 2009, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#include "AtaBus.h" + +// +// ATA Bus Driver Binding Protocol Instance +// +EFI_DRIVER_BINDING_PROTOCOL gAtaBusDriverBinding = { + AtaBusDriverBindingSupported, + AtaBusDriverBindingStart, + AtaBusDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// Template for ATA Child Device. +// +ATA_DEVICE gAtaDeviceTemplate = { + ATA_DEVICE_SIGNATURE, // Signature; + NULL, // Handle; + { // BlockIo + EFI_BLOCK_IO_PROTOCOL_REVISION, + NULL, + AtaBlockIoReset, + AtaBlockIoReadBlocks, + AtaBlockIoWriteBlocks, + AtaBlockIoFlushBlocks + }, + { // BlockMedia + 0, // MediaId + FALSE, // RemovableMedia + TRUE, // MediaPresent + FALSE, // LogicPartition + FALSE, // ReadOnly + FALSE, // WritingCache + 0x200, // BlockSize + 0, // LastBlock + 4, // IoAlign + 1, // LogicalBlocksPerPhysicalBlock + 0 // LowestAlignedLba + }, + { // DiskInfo + EFI_DISK_INFO_IDE_INTERFACE_GUID, + AtaDiskInfoInquiry, + AtaDiskInfoIdentify, + AtaDiskInfoSenseData, + AtaDiskInfoWhichIde + }, + NULL, // DevicePath; + NULL, // AtaBusDriverData; + 0, // Port, + 0, // PortMultiplierPort; + { 0, }, // Packet + {{ 0}, }, // Acb + NULL, // Asb + FALSE, // UdmaValid + FALSE, // Lba48Bit + NULL, // IdentifyData + NULL, // ControllerNameTable + {L'\0', } // ModelName +}; + +/** + Allocates an aligned buffer for ATA device. + + This function allocates an aligned buffer for the ATA device to perform + ATA pass through operations. The alignment requirement is from ATA pass + through interface. + + @param AtaDevice The ATA child device involved for the operation. + @param BufferSize The request buffer size. + + @return A pointer to the aligned buffer or NULL if the allocation fails. + +**/ +VOID * +AllocateAlignedBuffer ( + IN ATA_DEVICE *AtaDevice, + IN UINTN BufferSize + ) +{ + return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), AtaDevice->AtaBusDriverData->AtaPassThru->Mode->IoAlign); +} + +/** + Frees an aligned buffer for ATA device. + + This function frees an aligned buffer for the ATA device to perform + ATA pass through operations. + + @param AtaDevice The ATA child device involved for the operation. + @param BufferSize The request buffer size. + +**/ +VOID +FreeAlignedBuffer ( + IN VOID *Buffer, + IN UINTN BufferSize + ) +{ + if (Buffer != NULL) { + FreePages (Buffer, EFI_SIZE_TO_PAGES (BufferSize)); + } +} + + +/** + Release all the resources allocated for the ATA device. + + This function releases all the resources allocated for the ATA device. + + @param AtaDevice The ATA child device involved for the operation. + +**/ +VOID +ReleaseAtaResources ( + IN ATA_DEVICE *AtaDevice + ) +{ + FreeUnicodeStringTable (AtaDevice->ControllerNameTable); + FreeAlignedBuffer (AtaDevice->Asb, sizeof (*AtaDevice->Asb)); + FreeAlignedBuffer (AtaDevice->IdentifyData, sizeof (*AtaDevice->IdentifyData)); + if (AtaDevice->DevicePath != NULL) { + FreePool (AtaDevice->DevicePath); + } + FreePool (AtaDevice); +} + + +/** + Registers an ATA device. + + This function allocates an ATA device structure for the ATA device specified by + Port and PortMultiplierPort if the ATA device is identified as a valid one. + Then it will create child handle and install Block IO and Disk Info protocol on + it. + + @param AtaDevice The ATA child device involved for the operation. + @param Port The port number of the ATA device. + @param PortMultiplierPort The port multiplier port number of the ATA device. + + @retval EFI_SUCCESS The ATA device is successfully registered. + @retval EFI_OUT_OF_RESOURCES There is not enough memory to allocate the ATA device + and related data structures. + @return Others Some error occurs when registering the ATA device. +**/ +EFI_STATUS +RegisterAtaDevice ( + IN OUT ATA_BUS_DRIVER_DATA *AtaBusDriverData, + IN UINT16 Port, + IN UINT16 PortMultiplierPort + ) +{ + EFI_STATUS Status; + ATA_DEVICE *AtaDevice; + EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; + + NewDevicePathNode = NULL; + + // + // Allocate ATA device from the template. + // + AtaDevice = AllocateCopyPool (sizeof (gAtaDeviceTemplate), &gAtaDeviceTemplate); + if (AtaDevice == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Initializes ATA device structures and allocates the required buffer. + // + AtaDevice->BlockIo.Media = &AtaDevice->BlockMedia; + AtaDevice->AtaBusDriverData = AtaBusDriverData; + AtaDevice->Port = Port; + AtaDevice->PortMultiplierPort = PortMultiplierPort; + AtaDevice->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->Asb)); + if (AtaDevice->Asb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + AtaDevice->IdentifyData = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->IdentifyData)); + if (AtaDevice->IdentifyData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Try to identify the ATA device via the ATA pass through command. + // + Status = DiscoverAtaDevice (AtaDevice); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Build controller name for Component Name (2) protocol. + // + Status = AddUnicodeString2 ( + "eng", + gAtaBusComponentName.SupportedLanguages, + &AtaDevice->ControllerNameTable, + AtaDevice->ModelName, + TRUE + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = AddUnicodeString2 ( + "en", + gAtaBusComponentName2.SupportedLanguages, + &AtaDevice->ControllerNameTable, + AtaDevice->ModelName, + FALSE + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Build device path + // + AtaPassThru = AtaBusDriverData->AtaPassThru; + Status = AtaPassThru->BuildDevicePath (AtaPassThru, Port, PortMultiplierPort, &NewDevicePathNode); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Update to AHCI interface GUID based on device path node. The default one + // is IDE interface GUID copied from template. + // + if (NewDevicePathNode->SubType == MSG_SATA_DP) { + CopyGuid (&AtaDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid); + } + + AtaDevice->DevicePath = AppendDevicePathNode (AtaBusDriverData->ParentDevicePath, NewDevicePathNode); + if (AtaDevice->DevicePath == NULL) { + goto Done; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &AtaDevice->Handle, + &gEfiDevicePathProtocolGuid, + AtaDevice->DevicePath, + &gEfiBlockIoProtocolGuid, + &AtaDevice->BlockIo, + &gEfiDiskInfoProtocolGuid, + &AtaDevice->DiskInfo, + NULL + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + gBS->OpenProtocol ( + AtaBusDriverData->Controller, + &gEfiAtaPassThruProtocolGuid, + (VOID **) &AtaPassThru, + AtaBusDriverData->DriverBindingHandle, + AtaDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + +Done: + if (NewDevicePathNode != NULL) { + FreePool (NewDevicePathNode); + } + + if (EFI_ERROR (Status)) { + ReleaseAtaResources (AtaDevice); + DEBUG ((DEBUG_ERROR | DEBUG_INIT, "Failed to initialize Port %x PortMultiplierPort %x, status = %r\n", Port, PortMultiplierPort, Status)); + } + return Status; +} + + +/** + Unregisters an ATA device. + + This function removes the protocols installed on the controller handle and + frees the resources allocated for the ATA device. + + @param AtaDevice The ATA child device involved for the operation. + @param Controller The controller handle of the ATA device. + @param Handle The child handle. + + @retval EFI_SUCCESS The ATA device is successfully unregistered. + @return Others Some error occurs when unregistering the ATA device. + +**/ +EFI_STATUS +UnregisterAtaDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + ATA_DEVICE *AtaDevice; + EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; + + Status = gBS->OpenProtocol ( + Handle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (BlockIo); + + // + // Close the child handle + // + gBS->CloseProtocol ( + Controller, + &gEfiAtaPassThruProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handle, + &gEfiDevicePathProtocolGuid, + AtaDevice->DevicePath, + &gEfiBlockIoProtocolGuid, + &AtaDevice->BlockIo, + &gEfiDiskInfoProtocolGuid, + &AtaDevice->DiskInfo, + NULL + ); + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + &gEfiAtaPassThruProtocolGuid, + (VOID **) &AtaPassThru, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + return Status; + } + + ReleaseAtaResources (AtaDevice); + + return Status; +} + + + +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Since ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +AtaBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; + UINT16 Port; + UINT16 PortMultiplierPort; + + // + // Test EFI_ATA_PASS_THRU_PROTOCOL on controller handle. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiAtaPassThruProtocolGuid, + (VOID **) &AtaPassThru, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Test RemainingDevicePath is valid or not. + // + if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) { + Status = AtaPassThru->GetDevice (AtaPassThru, RemainingDevicePath, &Port, &PortMultiplierPort); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Close the I/O Abstraction(s) used to perform the supported test + // + gBS->CloseProtocol ( + Controller, + &gEfiAtaPassThruProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Open the EFI Device Path protocol needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + return Status; +} + + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +AtaBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + ATA_BUS_DRIVER_DATA *AtaBusDriverData; + UINT16 Port; + UINT16 PortMultiplierPort; + + AtaBusDriverData = NULL; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + Controller, + &gEfiAtaPassThruProtocolGuid, + (VOID **) &AtaPassThru, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) { + goto ErrorExit; + } + + // + // Check EFI_ALREADY_STARTED to reuse the original ATA_BUS_DRIVER_DATA. + // + if (Status != EFI_ALREADY_STARTED) { + AtaBusDriverData = AllocateZeroPool (sizeof (ATA_BUS_DRIVER_DATA)); + if (AtaBusDriverData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + AtaBusDriverData->AtaPassThru = AtaPassThru; + AtaBusDriverData->Controller = Controller; + AtaBusDriverData->ParentDevicePath = ParentDevicePath; + AtaBusDriverData->DriverBindingHandle = This->DriverBindingHandle; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiCallerIdGuid, + AtaBusDriverData, + NULL + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + } else { + Status = gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + (VOID **) &AtaBusDriverData, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + AtaBusDriverData = NULL; + goto ErrorExit; + } + } + + if (RemainingDevicePath == NULL) { + Port = 0xFFFF; + while (TRUE) { + Status = AtaPassThru->GetNextPort (AtaPassThru, &Port); + if (EFI_ERROR (Status)) { + // + // We cannot find more legal port then we are done. + // + break; + } + + PortMultiplierPort = 0xFFFF; + while (TRUE) { + Status = AtaPassThru->GetNextDevice (AtaPassThru, Port, &PortMultiplierPort); + if (EFI_ERROR (Status)) { + // + // We cannot find more legal port multiplier port number for ATA device + // on the port, then we are done. + // + break; + } + RegisterAtaDevice (AtaBusDriverData, Port, PortMultiplierPort); + } + } + Status = EFI_SUCCESS; + } else if (!IsDevicePathEnd (RemainingDevicePath)) { + Status = AtaPassThru->GetDevice (AtaPassThru, RemainingDevicePath, &Port, &PortMultiplierPort); + if (!EFI_ERROR (Status)) { + Status = RegisterAtaDevice (AtaBusDriverData,Port, PortMultiplierPort); + } + } + + return Status; + +ErrorExit: + + if (AtaBusDriverData != NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiCallerIdGuid, + AtaBusDriverData, + NULL + ); + FreePool (AtaBusDriverData); + } + + gBS->CloseProtocol ( + Controller, + &gEfiAtaPassThruProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; + +} + + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +AtaBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + BOOLEAN AllChildrenStopped; + UINTN Index; + ATA_BUS_DRIVER_DATA *AtaBusDriverData; + + if (NumberOfChildren == 0) { + Status = gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + (VOID **) &AtaBusDriverData, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiCallerIdGuid, + AtaBusDriverData, + NULL + ); + FreePool (AtaBusDriverData); + } + + gBS->CloseProtocol ( + Controller, + &gEfiAtaPassThruProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + + Status = UnregisterAtaDevice (This, Controller, ChildHandleBuffer[Index]); + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +/** + Reset the Block Device. + + @param This Indicates a pointer to the calling context. + @param ExtendedVerification Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and could + not be reset. + +**/ +EFI_STATUS +EFIAPI +AtaBlockIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_STATUS Status; + ATA_DEVICE *AtaDevice; + EFI_TPL OldTpl; + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This); + + Status = ResetAtaDevice (AtaDevice); + + gBS->RestoreTPL (OldTpl); + return Status; +} + + +/** + Read/Write BufferSize bytes from Lba from/into Buffer. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the read/write request is for. + @param Lba The starting logical block address to be read/written. The caller is + responsible for reading/writing to only legitimate locations. + @param BufferSize Size of Buffer, must be a multiple of device block size. + @param Buffer A pointer to the destination/source buffer for the data. + + @retval EFI_SUCCESS The data was read/written correctly to the device. + @retval EFI_WRITE_PROTECTED The device can not be read/written to. + @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +BlockIoReadWrite ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer, + IN BOOLEAN IsWrite + ) +{ + ATA_DEVICE *AtaDevice; + EFI_STATUS Status; + EFI_TPL OldTpl; + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + UINTN IoAlign; + + // + // Check parameters. + // + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + Media = This->Media; + if (MediaId != Media->MediaId) { + return EFI_MEDIA_CHANGED; + } + + BlockSize = Media->BlockSize; + if ((BufferSize % BlockSize) != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + NumberOfBlocks = BufferSize / BlockSize; + if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + IoAlign = Media->IoAlign; + if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This); + + // + // Invoke low level AtaDevice Access Routine. + // + Status = AccessAtaDevice (AtaDevice, Buffer, Lba, NumberOfBlocks, IsWrite); + + gBS->RestoreTPL (OldTpl); + + return Status; +} + + +/** + Read BufferSize bytes from Lba into Buffer. + + @param This Indicates a pointer to the calling context. + @param MediaId Id of the media, changes every time the media is replaced. + @param Lba The starting Logical Block Address to read from + @param BufferSize Size of Buffer, must be a multiple of device block size. + @param Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while performing the read. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +AtaBlockIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + return BlockIoReadWrite (This, MediaId, Lba, BufferSize, Buffer, FALSE); +} + + +/** + Write BufferSize bytes from Lba into Buffer. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the write request is for. + @param Lba The starting logical block address to be written. The caller is + responsible for writing to only legitimate locations. + @param BufferSize Size of Buffer, must be a multiple of device block size. + @param Buffer A pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data was written correctly to the device. + @retval EFI_WRITE_PROTECTED The device can not be written to. + @retval EFI_DEVICE_ERROR The device reported an error while performing the write. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +AtaBlockIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + return BlockIoReadWrite (This, MediaId, Lba, BufferSize, Buffer, TRUE); +} + + +/** + Flush the Block Device. + + @param This Indicates a pointer to the calling context. + + @retval EFI_SUCCESS All outstanding data was written to the device + @retval EFI_DEVICE_ERROR The device reported an error while writing back the data + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +AtaBlockIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + // + // return directly + // + return EFI_SUCCESS; +} + + +/** + Provides inquiry information for the controller type. + + This function is used by the IDE bus driver to get inquiry data. Data format + of Identify data is defined by the Interface GUID. + + @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. + @param[in,out] InquiryData Pointer to a buffer for the inquiry data. + @param[in,out] InquiryDataSize Pointer to the value for the inquiry data size. + + @retval EFI_SUCCESS The command was accepted without any errors. + @retval EFI_NOT_FOUND Device does not support this data class + @retval EFI_DEVICE_ERROR Error reading InquiryData from device + @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough + +**/ +EFI_STATUS +EFIAPI +AtaDiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *InquiryDataSize + ) +{ + return EFI_NOT_FOUND; +} + + +/** + Provides identify information for the controller type. + + This function is used by the IDE bus driver to get identify data. Data format + of Identify data is defined by the Interface GUID. + + @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL + instance. + @param[in,out] IdentifyData Pointer to a buffer for the identify data. + @param[in,out] IdentifyDataSize Pointer to the value for the identify data + size. + + @retval EFI_SUCCESS The command was accepted without any errors. + @retval EFI_NOT_FOUND Device does not support this data class + @retval EFI_DEVICE_ERROR Error reading IdentifyData from device + @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough + +**/ +EFI_STATUS +EFIAPI +AtaDiskInfoIdentify ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize + ) +{ + EFI_STATUS Status; + ATA_DEVICE *AtaDevice; + + AtaDevice = ATA_DEVICE_FROM_DISK_INFO (This); + + Status = EFI_BUFFER_TOO_SMALL; + if (*IdentifyDataSize >= sizeof (*AtaDevice->IdentifyData)) { + Status = EFI_SUCCESS; + CopyMem (IdentifyData, AtaDevice->IdentifyData, sizeof (*AtaDevice->IdentifyData)); + } + *IdentifyDataSize = sizeof (*AtaDevice->IdentifyData); + + return Status; +} + + +/** + Provides sense data information for the controller type. + + This function is used by the IDE bus driver to get sense data. + Data format of Sense data is defined by the Interface GUID. + + @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. + @param[in,out] SenseData Pointer to the SenseData. + @param[in,out] SenseDataSize Size of SenseData in bytes. + @param[out] SenseDataNumber Pointer to the value for the sense data size. + + @retval EFI_SUCCESS The command was accepted without any errors. + @retval EFI_NOT_FOUND Device does not support this data class. + @retval EFI_DEVICE_ERROR Error reading SenseData from device. + @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough. + +**/ +EFI_STATUS +EFIAPI +AtaDiskInfoSenseData ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *SenseData, + IN OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber + ) +{ + return EFI_NOT_FOUND; +} + + +/** + This function is used by the IDE bus driver to get controller information. + + @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. + @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary. + @param[out] IdeDevice Pointer to the Ide Device number. Master or slave. + + @retval EFI_SUCCESS IdeChannel and IdeDevice are valid. + @retval EFI_UNSUPPORTED This is not an IDE device. + +**/ +EFI_STATUS +EFIAPI +AtaDiskInfoWhichIde ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice + ) +{ + ATA_DEVICE *AtaDevice; + + AtaDevice = ATA_DEVICE_FROM_DISK_INFO (This); + *IdeChannel = AtaDevice->Port; + *IdeDevice = AtaDevice->PortMultiplierPort; + + return EFI_SUCCESS; +} + + +/** + The user Entry Point for module AtaBus. The user code starts with this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeAtaBus( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gAtaBusDriverBinding, + ImageHandle, + &gAtaBusComponentName, + &gAtaBusComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h new file mode 100644 index 0000000000..eff49a69e2 --- /dev/null +++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h @@ -0,0 +1,647 @@ +/** @file + Master header file for ATA Bus Driver. + + This file defines common data structures, macro definitions and some module + internal function header files. + + Copyright (c) 2009 Intel Corporation.
+ All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _ATA_BUS_H_ +#define _ATA_BUS_H_ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Time out value for ATA pass through protocol +// +#define ATA_TIMEOUT EFI_TIMER_PERIOD_SECONDS (1) + +// +// Maximum number of times to retry ATA command +// +#define MAX_RETRY_TIMES 3 + +// +// The maximum total sectors count in 28 bit addressing mode +// +#define MAX_28BIT_ADDRESSING_CAPACITY 0xfffffff + +// +// The maximum ATA transaction sector count in 28 bit addressing mode. +// +#define MAX_28BIT_TRANSFER_BLOCK_NUM 0x100 + +// +// The maximum ATA transaction sector count in 48 bit addressing mode. +// +#define MAX_48BIT_TRANSFER_BLOCK_NUM 0x10000 + +// +// The maximum model name in ATA identify data +// +#define MAX_MODEL_NAME_LEN 40 + + +// +// ATA bus data structure for ATA controller +// +typedef struct { + EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; + EFI_HANDLE Controller; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_HANDLE DriverBindingHandle; +} ATA_BUS_DRIVER_DATA; + +#define ATA_DEVICE_SIGNATURE SIGNATURE_32 ('A', 'B', 'I', 'D') + +// +// ATA device data structure for each child device +// +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + EFI_BLOCK_IO_PROTOCOL BlockIo; + EFI_BLOCK_IO_MEDIA BlockMedia; + EFI_DISK_INFO_PROTOCOL DiskInfo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + ATA_BUS_DRIVER_DATA *AtaBusDriverData; + UINT16 Port; + UINT16 PortMultiplierPort; + + // + // Buffer for the execution of ATA pass through protocol + // + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; + EFI_ATA_COMMAND_BLOCK Acb; + EFI_ATA_STATUS_BLOCK *Asb; + + BOOLEAN UdmaValid; + BOOLEAN Lba48Bit; + + // + // Cached data for ATA identify data + // + EFI_IDENTIFY_DATA *IdentifyData; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + CHAR16 ModelName[MAX_MODEL_NAME_LEN + 1]; + +} ATA_DEVICE; + +#define ATA_DEVICE_FROM_BLOCK_IO(a) CR (a, ATA_DEVICE, BlockIo, ATA_DEVICE_SIGNATURE) +#define ATA_DEVICE_FROM_DISK_INFO(a) CR (a, ATA_DEVICE, DiskInfo, ATA_DEVICE_SIGNATURE) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gAtaBusDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gAtaBusComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gAtaBusComponentName2; + + +/** + Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.ResetDevice(). + + This function wraps the ResetDevice() invocation for ATA pass through function + for an ATA device. + + @param AtaDevice The ATA child device involved for the operation. + + @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru(). + +**/ +EFI_STATUS +ResetAtaDevice ( + IN ATA_DEVICE *AtaDevice + ); + + +/** + Discovers whether it is a valid ATA device. + + This function issues ATA_CMD_IDENTIFY_DRIVE command to the ATA device to identify it. + If the command is executed successfully, it then identifies it and initializes + the Media information in Block IO protocol interface. + + @param AtaDevice The ATA child device involved for the operation. + + @retval EFI_SUCCESS The device is successfully identified and Media information + is correctly initialized. + @return others Some error occurs when discovering the ATA device. + +**/ +EFI_STATUS +DiscoverAtaDevice ( + IN OUT ATA_DEVICE *AtaDevice + ); + + +/** + Read or write a number of blocks from ATA device. + + This function performs ATA pass through transactions to read/write data from/to + ATA device. It may separate the read/write request into several ATA pass through + transactions. + + @param AtaDevice The ATA child device involved for the operation. + @param Buffer The pointer to the current transaction buffer. + @param StartLba The starting logical block address to be accessed. + @param NumberOfBlocks The block number or sector count of the transfer. + @param IsWrite Indicates whether it is a write operation. + + @retval EFI_SUCCESS The data transfer is complete successfully. + @return others Some error occurs when transferring data. + +**/ +EFI_STATUS +AccessAtaDevice( + IN OUT ATA_DEVICE *AtaDevice, + IN OUT UINT8 *Buffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks, + IN BOOLEAN IsWrite + ); + +// +// Protocol interface prototypes +// +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Since ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +AtaBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +AtaBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +AtaBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +AtaBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +AtaBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + + +/** + Reset the Block Device. + + @param This Indicates a pointer to the calling context. + @param ExtendedVerification Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and could + not be reset. + +**/ +EFI_STATUS +EFIAPI +AtaBlockIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + + +/** + Read BufferSize bytes from Lba into Buffer. + + @param This Indicates a pointer to the calling context. + @param MediaId Id of the media, changes every time the media is replaced. + @param Lba The starting Logical Block Address to read from + @param BufferSize Size of Buffer, must be a multiple of device block size. + @param Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while performing the read. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +AtaBlockIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + + +/** + Write BufferSize bytes from Lba into Buffer. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the write request is for. + @param Lba The starting logical block address to be written. The caller is + responsible for writing to only legitimate locations. + @param BufferSize Size of Buffer, must be a multiple of device block size. + @param Buffer A pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data was written correctly to the device. + @retval EFI_WRITE_PROTECTED The device can not be written to. + @retval EFI_DEVICE_ERROR The device reported an error while performing the write. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +AtaBlockIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ); + + +/** + Flush the Block Device. + + @param This Indicates a pointer to the calling context. + + @retval EFI_SUCCESS All outstanding data was written to the device + @retval EFI_DEVICE_ERROR The device reported an error while writing back the data + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +AtaBlockIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ); + + +/** + Provides inquiry information for the controller type. + + This function is used by the IDE bus driver to get inquiry data. Data format + of Identify data is defined by the Interface GUID. + + @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. + @param[in,out] InquiryData Pointer to a buffer for the inquiry data. + @param[in,out] InquiryDataSize Pointer to the value for the inquiry data size. + + @retval EFI_SUCCESS The command was accepted without any errors. + @retval EFI_NOT_FOUND Device does not support this data class + @retval EFI_DEVICE_ERROR Error reading InquiryData from device + @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough + +**/ +EFI_STATUS +EFIAPI +AtaDiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *InquiryDataSize + ); + + +/** + Provides identify information for the controller type. + + This function is used by the IDE bus driver to get identify data. Data format + of Identify data is defined by the Interface GUID. + + @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL + instance. + @param[in,out] IdentifyData Pointer to a buffer for the identify data. + @param[in,out] IdentifyDataSize Pointer to the value for the identify data + size. + + @retval EFI_SUCCESS The command was accepted without any errors. + @retval EFI_NOT_FOUND Device does not support this data class + @retval EFI_DEVICE_ERROR Error reading IdentifyData from device + @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough + +**/ +EFI_STATUS +EFIAPI +AtaDiskInfoIdentify ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize + ); + + +/** + Provides sense data information for the controller type. + + This function is used by the IDE bus driver to get sense data. + Data format of Sense data is defined by the Interface GUID. + + @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. + @param[in,out] SenseData Pointer to the SenseData. + @param[in,out] SenseDataSize Size of SenseData in bytes. + @param[out] SenseDataNumber Pointer to the value for the sense data size. + + @retval EFI_SUCCESS The command was accepted without any errors. + @retval EFI_NOT_FOUND Device does not support this data class. + @retval EFI_DEVICE_ERROR Error reading SenseData from device. + @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough. + +**/ +EFI_STATUS +EFIAPI +AtaDiskInfoSenseData ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *SenseData, + IN OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber + ); + + +/** + This function is used by the IDE bus driver to get controller information. + + @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. + @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary. + @param[out] IdeDevice Pointer to the Ide Device number. Master or slave. + + @retval EFI_SUCCESS IdeChannel and IdeDevice are valid. + @retval EFI_UNSUPPORTED This is not an IDE device. + +**/ +EFI_STATUS +EFIAPI +AtaDiskInfoWhichIde ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice + ); + +#endif diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf new file mode 100644 index 0000000000..84dfe1f5e9 --- /dev/null +++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf @@ -0,0 +1,70 @@ +#/** @file +# ATA Bus driver to enumerate and identfy ATA devices. +# +# This driver follows UEFI driver model and layers on ATA Pass Thru protocol defined +# in UEFI spec 2.2. It installs Block IO and Disk Info protocol for each ATA device +# it enumerates and identifies successfully. +# +# Copyright (c) 2009, Intel Corporation +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AtaBusDxe + FILE_GUID = 19DF145A-B1D4-453f-8507-38816676D7F6 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeAtaBus + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# DRIVER_BINDING = gAtaBusDriverBinding +# COMPONENT_NAME = gAtaBusComponentName +# COMPONENT_NAME2 = gAtaBusComponentName2 +# +# + +[Sources.common] + AtaBus.h + AtaBus.c + AtaPassThruExecute.c + ComponentName.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + DevicePathLib + UefiBootServicesTableLib + MemoryAllocationLib + BaseMemoryLib + UefiLib + BaseLib + UefiDriverEntryPoint + DebugLib + + +[Guids] + gEfiDiskInfoIdeInterfaceGuid # CONSUMES ## GUID + gEfiDiskInfoAhciInterfaceGuid # CONSUMES ## GUID + +[Protocols] + gEfiDiskInfoProtocolGuid # BY_START + gEfiBlockIoProtocolGuid # BY_START + gEfiAtaPassThruProtocolGuid # TO_START + gEfiDevicePathProtocolGuid # TO_START + + + diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c new file mode 100644 index 0000000000..d2a9182712 --- /dev/null +++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c @@ -0,0 +1,498 @@ +/** @file + This file implements ATA pass through transaction for ATA bus driver. + + This file implements the low level execution of ATA pass through transaction. + It transforms the high level identity, read/write, reset command to ATA pass + through command and protocol. + + Copyright (c) 2009 Intel Corporation.
+ All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#include "AtaBus.h" + +// +// Look up table (UdmaValid, IsWrite) for EFI_ATA_PASS_THRU_CMD_PROTOCOL +// +EFI_ATA_PASS_THRU_CMD_PROTOCOL mAtaPassThruCmdProtocols[][2] = { + { + EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN, + EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT + }, + { + EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN, + EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT, + } +}; + +// +// Look up table (UdmaValid, Lba48Bit, IsIsWrite) for ATA_CMD +// +UINT8 mAtaCommands[][2][2] = { + { + { + ATA_CMD_READ_SECTORS, // 28-bit LBA; PIO read + ATA_CMD_WRITE_SECTORS // 28-bit LBA; PIO write + }, + { + ATA_CMD_READ_SECTORS_EXT, // 48-bit LBA; PIO read + ATA_CMD_WRITE_SECTORS_EXT // 48-bit LBA; PIO write + } + }, + { + { + ATA_CMD_READ_DMA, // 28-bit LBA; DMA read + ATA_CMD_WRITE_DMA // 28-bit LBA; DMA write + }, + { + ATA_CMD_READ_DMA_EXT, // 48-bit LBA; DMA read + ATA_CMD_WRITE_DMA_EXT // 48-bit LBA; DMA write + } + } +}; + +// +// Look up table (Lba48Bit) for maximum transfer block number +// +UINTN mMaxTransferBlockNumber[] = { + MAX_28BIT_TRANSFER_BLOCK_NUM, + MAX_48BIT_TRANSFER_BLOCK_NUM +}; + + +/** + Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.PassThru(). + + This function wraps the PassThru() invocation for ATA pass through function + for an ATA device. It assembles the ATA pass through command packet for ATA + transaction. + + @param AtaDevice The ATA child device involved for the operation. + + @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru(). + +**/ +EFI_STATUS +AtaDevicePassThru ( + IN OUT ATA_DEVICE *AtaDevice + ) +{ + EFI_STATUS Status; + EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; + EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet; + + // + // Assemble packet + // + Packet = &AtaDevice->Packet; + Packet->Asb = AtaDevice->Asb; + Packet->Acb = &AtaDevice->Acb; + Packet->Timeout = ATA_TIMEOUT; + + AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru; + + Status = AtaPassThru->PassThru ( + AtaPassThru, + AtaDevice->Port, + AtaDevice->PortMultiplierPort, + Packet, + NULL + ); + // + // Ensure ATA pass through caller and callee have the same + // interpretation of ATA pass through protocol. + // + ASSERT (Status != EFI_INVALID_PARAMETER); + ASSERT (Status != EFI_BAD_BUFFER_SIZE); + + return Status; +} + + +/** + Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.ResetDevice(). + + This function wraps the ResetDevice() invocation for ATA pass through function + for an ATA device. + + @param AtaDevice The ATA child device involved for the operation. + + @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru(). + +**/ +EFI_STATUS +ResetAtaDevice ( + IN ATA_DEVICE *AtaDevice + ) +{ + EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; + + AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru; + + return AtaPassThru->ResetDevice ( + AtaPassThru, + AtaDevice->Port, + AtaDevice->PortMultiplierPort + ); +} + + +/** + Prints ATA model name to ATA device structure. + + This function converts ATA device model name from ATA identify data + to a string in ATA device structure. It needs to change the character + order in the original model name string. + + @param AtaDevice The ATA child device involved for the operation. + +**/ +VOID +PrintAtaModelName ( + IN OUT ATA_DEVICE *AtaDevice + ) +{ + UINTN Index; + CHAR8 *Source; + CHAR16 *Destination; + + Source = AtaDevice->IdentifyData->AtaData.ModelName; + Destination = AtaDevice->ModelName; + + // + // Swap the byte order in the original module name. + // + for (Index = 0; Index < MAX_MODEL_NAME_LEN; Index += 2) { + Destination[Index] = Source[Index + 1]; + Destination[Index + 1] = Source[Index]; + } + AtaDevice->ModelName[MAX_MODEL_NAME_LEN] = L'\0'; +} + + +/** + Gets ATA device Capacity according to ATA 6. + + This function returns the capacity of the ATA device if it follows + ATA 6 to support 48 bit addressing. + + @param AtaDevice The ATA child device involved for the operation. + + @return The capacity of the ATA device or 0 if the device does not support + 48-bit addressing defined in ATA 6. + +**/ +EFI_LBA +GetAtapi6Capacity ( + IN ATA_DEVICE *AtaDevice + ) +{ + EFI_LBA Capacity; + EFI_LBA TmpLba; + UINTN Index; + ATAPI_IDENTIFY_DATA *IdentifyData; + + IdentifyData = (ATAPI_IDENTIFY_DATA *) AtaDevice->IdentifyData; + if ((IdentifyData->cmd_set_support_83 & BIT10) == 0) { + // + // The device doesn't support 48 bit addressing + // + return 0; + } + + // + // 48 bit address feature set is supported, get maximum capacity + // + Capacity = 0; + for (Index = 0; Index < 4; Index++) { + // + // Lower byte goes first: word[100] is the lowest word, word[103] is highest + // + TmpLba = IdentifyData->max_user_lba_for_48bit_addr[Index]; + Capacity |= LShiftU64 (TmpLba, 16 * Index); + } + + return Capacity; +} + + +/** + Identifies ATA device via the Identify data. + + This function identifies the ATA device and initializes the Media information in + Block IO protocol interface. + + @param AtaDevice The ATA child device involved for the operation. + + @retval EFI_UNSUPPORTED The device is not a valid ATA device (hard disk). + @retval EFI_SUCCESS The device is successfully identified and Media information + is correctly initialized. + +**/ +EFI_STATUS +IdentifyAtaDevice ( + IN OUT ATA_DEVICE *AtaDevice + ) +{ + EFI_ATA_IDENTIFY_DATA *IdentifyData; + EFI_BLOCK_IO_MEDIA *BlockMedia; + EFI_LBA Capacity; + UINT16 PhyLogicSectorSupport; + UINT16 UdmaMode; + + IdentifyData = &AtaDevice->IdentifyData->AtaData; + + if ((IdentifyData->config & BIT15) != 0) { + // + // This is not an hard disk + // + return EFI_UNSUPPORTED; + } + + // + // Check whether the WORD 88 (supported UltraDMA by drive) is valid + // + if ((IdentifyData->field_validity & BIT2) != 0) { + UdmaMode = IdentifyData->ultra_dma_mode; + if ((UdmaMode & (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0) { + // + // If BIT0~BIT6 is selected, then UDMA is supported + // + AtaDevice->UdmaValid = TRUE; + } + } + + Capacity = GetAtapi6Capacity (AtaDevice); + if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) { + // + // Capacity exceeds 120GB. 48-bit addressing is really needed + // + AtaDevice->Lba48Bit = TRUE; + } else { + // + // This is a hard disk <= 120GB capacity, treat it as normal hard disk + // + Capacity = ((UINT32)IdentifyData->user_addressable_sectors_hi << 16) | IdentifyData->user_addressable_sectors_lo; + AtaDevice->Lba48Bit = FALSE; + } + + // + // Block Media Information: + // + BlockMedia = &AtaDevice->BlockMedia; + BlockMedia->LastBlock = Capacity - 1; + // + // Check whether Long Physical Sector Feature is supported + // + PhyLogicSectorSupport = IdentifyData->phy_logic_sector_support; + if ((PhyLogicSectorSupport & (BIT14 | BIT15)) == BIT14) { + // + // Check whether one physical block contains multiple physical blocks + // + if ((PhyLogicSectorSupport & BIT13) != 0) { + BlockMedia->LogicalBlocksPerPhysicalBlock = (UINT32) (1 << (PhyLogicSectorSupport & 0x000f)); + // + // Check lowest alignment of logical blocks within physical block + // + if ((IdentifyData->alignment_logic_in_phy_blocks & (BIT14 | BIT15)) == BIT14) { + BlockMedia->LowestAlignedLba = (EFI_LBA) (IdentifyData->alignment_logic_in_phy_blocks & 0x3fff); + } + } + // + // Check logical block size + // + if ((PhyLogicSectorSupport & BIT12) != 0) { + BlockMedia->BlockSize = (UINT32) (((IdentifyData->logic_sector_size_hi << 16) | IdentifyData->logic_sector_size_lo) * sizeof (UINT16)); + } + AtaDevice->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2; + } + // + // Get ATA model name from identify data structure. + // + PrintAtaModelName (AtaDevice); + + return EFI_SUCCESS; +} + + +/** + Discovers whether it is a valid ATA device. + + This function issues ATA_CMD_IDENTIFY_DRIVE command to the ATA device to identify it. + If the command is executed successfully, it then identifies it and initializes + the Media information in Block IO protocol interface. + + @param AtaDevice The ATA child device involved for the operation. + + @retval EFI_SUCCESS The device is successfully identified and Media information + is correctly initialized. + @return others Some error occurs when discovering the ATA device. + +**/ +EFI_STATUS +DiscoverAtaDevice ( + IN OUT ATA_DEVICE *AtaDevice + ) +{ + EFI_STATUS Status; + EFI_ATA_COMMAND_BLOCK *Acb; + EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet; + UINTN Retry; + + // + // Prepare for ATA command block. + // + Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb)); + Acb->AtaCommand = ATA_CMD_IDENTIFY_DRIVE; + + // + // Prepare for ATA pass through packet. + // + Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet)); + Packet->InDataBuffer = AtaDevice->IdentifyData; + Packet->InTransferLength = sizeof (*AtaDevice->IdentifyData); + Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN; + Packet->Length = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT; + + Retry = MAX_RETRY_TIMES; + do { + Status = AtaDevicePassThru (AtaDevice); + if (!EFI_ERROR (Status)) { + // + // The command is issued successfully + // + Status = IdentifyAtaDevice (AtaDevice); + if (!EFI_ERROR (Status)) { + return Status; + } + } + } while (Retry-- > 0); + + return Status; +} + +/** + Transfer data from ATA device. + + This function performs one ATA pass through transaction to transfer data from/to + ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru + interface of ATA pass through. + + @param AtaDevice The ATA child device involved for the operation. + @param Buffer The pointer to the current transaction buffer. + @param StartLba The starting logical block address to be accessed. + @param TransferLength The block number or sector count of the transfer. + @param IsWrite Indicates whether it is a write operation. + + @retval EFI_SUCCESS The data transfer is complete successfully. + @return others Some error occurs when transferring data. + +**/ +EFI_STATUS +TransferAtaDevice ( + IN OUT ATA_DEVICE *AtaDevice, + IN OUT VOID *Buffer, + IN EFI_LBA StartLba, + IN UINT32 TransferLength, + IN BOOLEAN IsWrite + ) +{ + EFI_ATA_COMMAND_BLOCK *Acb; + EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet; + + // + // Prepare for ATA command block. + // + Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb)); + Acb->AtaCommand = mAtaCommands[AtaDevice->UdmaValid][AtaDevice->Lba48Bit][IsWrite]; + Acb->AtaSectorNumber = (UINT8) StartLba; + Acb->AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8); + Acb->AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16); + Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4)); + if (AtaDevice->Lba48Bit) { + Acb->AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24); + } else { + Acb->AtaDeviceHead = (UINT8) (Acb->AtaDeviceHead | RShiftU64 (StartLba, 24)); + } + Acb->AtaCylinderLowExp = (UINT8) RShiftU64 (StartLba, 32); + Acb->AtaCylinderHighExp = (UINT8) RShiftU64 (StartLba, 40); + Acb->AtaSectorCount = (UINT8) TransferLength; + Acb->AtaSectorCountExp = (UINT8) (TransferLength >> 8); + + // + // Prepare for ATA pass through packet. + // + Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet)); + if (IsWrite) { + Packet->OutDataBuffer = Buffer; + Packet->OutTransferLength = TransferLength; + } else { + Packet->InDataBuffer = Buffer; + Packet->InTransferLength = TransferLength; + } + Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsWrite]; + Packet->Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT; + + return AtaDevicePassThru (AtaDevice); +} + +/** + Read or write a number of blocks from ATA device. + + This function performs ATA pass through transactions to read/write data from/to + ATA device. It may separate the read/write request into several ATA pass through + transactions. + + @param AtaDevice The ATA child device involved for the operation. + @param Buffer The pointer to the current transaction buffer. + @param StartLba The starting logical block address to be accessed. + @param NumberOfBlocks The block number or sector count of the transfer. + @param IsWrite Indicates whether it is a write operation. + + @retval EFI_SUCCESS The data transfer is complete successfully. + @return others Some error occurs when transferring data. + +**/ +EFI_STATUS +AccessAtaDevice( + IN OUT ATA_DEVICE *AtaDevice, + IN OUT UINT8 *Buffer, + IN EFI_LBA StartLba, + IN UINTN NumberOfBlocks, + IN BOOLEAN IsWrite + ) +{ + EFI_STATUS Status; + UINTN MaxTransferBlockNumber; + UINTN TransferBlockNumber; + UINTN BlockSize; + + MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit]; + BlockSize = AtaDevice->BlockMedia.BlockSize; + do { + if (NumberOfBlocks > MaxTransferBlockNumber) { + TransferBlockNumber = MaxTransferBlockNumber; + NumberOfBlocks -= MaxTransferBlockNumber; + } else { + TransferBlockNumber = NumberOfBlocks; + NumberOfBlocks = 0; + } + + Status = TransferAtaDevice (AtaDevice, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite); + if (EFI_ERROR (Status)) { + return Status; + } + StartLba += TransferBlockNumber; + Buffer += TransferBlockNumber * BlockSize; + } while (NumberOfBlocks > 0); + + return Status; +} diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/ComponentName.c b/MdeModulePkg/Bus/Ata/AtaBusDxe/ComponentName.c new file mode 100644 index 0000000000..57d32c38a2 --- /dev/null +++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/ComponentName.c @@ -0,0 +1,238 @@ +/** @file + UEFI Component Name(2) protocol implementation for ConPlatform driver. + + Copyright (c) 2009, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "AtaBus.h" + +// +// Driver name table +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtaBusDriverNameTable[] = { + { "eng;en", L"ATA Bus Driver" }, + { NULL , NULL } +}; + +// +// Controller name table +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtaBusControllerNameTable[] = { + { "eng;en", L"ATA Controller" }, + { NULL , NULL } +}; + + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gAtaBusComponentName = { + AtaBusComponentNameGetDriverName, + AtaBusComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gAtaBusComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) AtaBusComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) AtaBusComponentNameGetControllerName, + "en" +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +AtaBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mAtaBusDriverNameTable, + DriverName, + (BOOLEAN)(This == &gAtaBusComponentName) + ); +} + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +AtaBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + ATA_DEVICE *AtaDevice; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + + // + // Make sure this driver is currently managing ControllHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gAtaBusDriverBinding.DriverBindingHandle, + &gEfiAtaPassThruProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ControllerNameTable = mAtaBusControllerNameTable; + if (ChildHandle != NULL) { + Status = EfiTestChildHandle ( + ControllerHandle, + ChildHandle, + &gEfiAtaPassThruProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the child context + // + Status = gBS->OpenProtocol ( + ChildHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + gAtaBusDriverBinding.DriverBindingHandle, + ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (BlockIo); + ControllerNameTable =AtaDevice->ControllerNameTable; + } + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + ControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gAtaBusComponentName) + ); +} diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index ecc76aadcb..5000934609 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -240,6 +240,7 @@ MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf + MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf -- 2.39.2