123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- /** @file
- The AhciPei driver is used to manage ATA hard disk device working under AHCI
- mode at PEI phase.
- Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "AhciPei.h"
- /**
- Traverse the attached ATA devices list to find out the device with given Port
- and PortMultiplierPort.
- @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
- instance.
- @param[in] Port The port number of the ATA device.
- @param[in] PortMultiplierPort The port multiplier port number of the ATA device.
- @retval The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of the device
- info to access.
- **/
- PEI_AHCI_ATA_DEVICE_DATA *
- SearchDeviceByPort (
- IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
- IN UINT16 Port,
- IN UINT16 PortMultiplierPort
- )
- {
- PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
- LIST_ENTRY *Node;
- Node = GetFirstNode (&Private->DeviceList);
- while (!IsNull (&Private->DeviceList, Node)) {
- DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
- if ((DeviceData->Port == Port) &&
- (DeviceData->PortMultiplier == PortMultiplierPort)) {
- return DeviceData;
- }
- Node = GetNextNode (&Private->DeviceList, Node);
- }
- return NULL;
- }
- /**
- Sends an ATA command to an ATA device that is attached to the ATA controller.
- @param[in] Private Pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA.
- @param[in] Port The port number of the ATA device.
- @param[in] PortMultiplierPort The port multiplier port number of the ATA
- device.
- @param[in] FisIndex The index of the FIS.
- @param[in,out] Packet A pointer to the ATA command to send to
- the ATA device specified by Port and
- PortMultiplierPort.
- @retval EFI_SUCCESS The ATA command was sent by the host. For
- bi-directional commands, InTransferLength bytes
- were transferred from InDataBuffer. For write
- and bi-directional commands, OutTransferLength
- bytes were transferred by OutDataBuffer.
- @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number
- of bytes that could be transferred is returned
- in InTransferLength. For write and bi-directional
- commands, OutTransferLength bytes were transferred
- by OutDataBuffer.
- @retval EFI_NOT_READY The ATA command could not be sent because there
- are too many ATA commands already queued. The
- caller may retry again later.
- @retval EFI_DEVICE_ERROR A device error occurred while attempting to
- send the ATA command.
- @retval EFI_INVALID_PARAMETER Port, PortMultiplierPort, or the contents of
- Acb are invalid. The ATA command was not sent,
- so no additional status information is available.
- **/
- EFI_STATUS
- AhciPassThruExecute (
- IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
- IN UINT16 Port,
- IN UINT16 PortMultiplierPort,
- IN UINT8 FisIndex,
- IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet
- )
- {
- EFI_STATUS Status;
- switch (Packet->Protocol) {
- case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:
- Status = AhciNonDataTransfer (
- Private,
- (UINT8) Port,
- (UINT8) PortMultiplierPort,
- FisIndex,
- Packet->Acb,
- Packet->Asb,
- Packet->Timeout
- );
- break;
- case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:
- Status = AhciPioTransfer (
- Private,
- (UINT8) Port,
- (UINT8) PortMultiplierPort,
- FisIndex,
- TRUE,
- Packet->Acb,
- Packet->Asb,
- Packet->InDataBuffer,
- Packet->InTransferLength,
- Packet->Timeout
- );
- break;
- case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:
- Status = AhciPioTransfer (
- Private,
- (UINT8) Port,
- (UINT8) PortMultiplierPort,
- FisIndex,
- FALSE,
- Packet->Acb,
- Packet->Asb,
- Packet->OutDataBuffer,
- Packet->OutTransferLength,
- Packet->Timeout
- );
- break;
- default:
- return EFI_UNSUPPORTED;
- }
- return Status;
- }
- /**
- Sends an ATA command to an ATA device that is attached to the ATA controller.
- @param[in] This The PPI instance pointer.
- @param[in] Port The port number of the ATA device to send
- the command.
- @param[in] PortMultiplierPort The port multiplier port number of the ATA
- device to send the command.
- If there is no port multiplier, then specify
- 0xFFFF.
- @param[in,out] Packet A pointer to the ATA command to send to
- the ATA device specified by Port and
- PortMultiplierPort.
- @retval EFI_SUCCESS The ATA command was sent by the host. For
- bi-directional commands, InTransferLength bytes
- were transferred from InDataBuffer. For write
- and bi-directional commands, OutTransferLength
- bytes were transferred by OutDataBuffer.
- @retval EFI_NOT_FOUND The specified ATA device is not found.
- @retval EFI_INVALID_PARAMETER The contents of Acb are invalid. The ATA command
- was not sent, so no additional status information
- is available.
- @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The number
- of bytes that could be transferred is returned
- in InTransferLength. For write and bi-directional
- commands, OutTransferLength bytes were transferred
- by OutDataBuffer.
- @retval EFI_NOT_READY The ATA command could not be sent because there
- are too many ATA commands already queued. The
- caller may retry again later.
- @retval EFI_DEVICE_ERROR A device error occurred while attempting to
- send the ATA command.
- **/
- EFI_STATUS
- EFIAPI
- AhciAtaPassThruPassThru (
- IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
- IN UINT16 Port,
- IN UINT16 PortMultiplierPort,
- IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet
- )
- {
- UINT32 IoAlign;
- PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
- PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
- UINT32 MaxSectorCount;
- UINT32 BlockSize;
- if (This == NULL || Packet == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- IoAlign = This->Mode->IoAlign;
- if ((IoAlign > 1) && !IS_ALIGNED (Packet->InDataBuffer, IoAlign)) {
- return EFI_INVALID_PARAMETER;
- }
- if ((IoAlign > 1) && !IS_ALIGNED (Packet->OutDataBuffer, IoAlign)) {
- return EFI_INVALID_PARAMETER;
- }
- if ((IoAlign > 1) && !IS_ALIGNED (Packet->Asb, IoAlign)) {
- return EFI_INVALID_PARAMETER;
- }
- Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
- DeviceData = SearchDeviceByPort (Private, Port, PortMultiplierPort);
- if (DeviceData == NULL) {
- return EFI_NOT_FOUND;
- }
- MaxSectorCount = mMaxTransferBlockNumber[DeviceData->Lba48Bit];
- BlockSize = DeviceData->Media.BlockSize;
- //
- // Convert the transfer length from sector count to byte.
- //
- if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&
- (Packet->InTransferLength != 0)) {
- Packet->InTransferLength = Packet->InTransferLength * BlockSize;
- }
- //
- // Convert the transfer length from sector count to byte.
- //
- if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&
- (Packet->OutTransferLength != 0)) {
- Packet->OutTransferLength = Packet->OutTransferLength * BlockSize;
- }
- //
- // If the data buffer described by InDataBuffer/OutDataBuffer and
- // InTransferLength/OutTransferLength is too big to be transferred in a single
- // command, then no data is transferred and EFI_BAD_BUFFER_SIZE is returned.
- //
- if (((Packet->InTransferLength != 0) && (Packet->InTransferLength > MaxSectorCount * BlockSize)) ||
- ((Packet->OutTransferLength != 0) && (Packet->OutTransferLength > MaxSectorCount * BlockSize))) {
- return EFI_BAD_BUFFER_SIZE;
- }
- return AhciPassThruExecute (
- Private,
- DeviceData->Port,
- DeviceData->PortMultiplier,
- DeviceData->FisIndex,
- Packet
- );
- }
- /**
- Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.
- These can either be the list of ports where ATA devices are actually present or the
- list of legal port numbers for the ATA controller. Regardless, the caller of this
- function must probe the port number returned to see if an ATA device is actually
- present at that location on the ATA controller.
- The GetNextPort() function retrieves the port number on an ATA controller. If on
- input Port is 0xFFFF, then the port number of the first port on the ATA controller
- is returned in Port and EFI_SUCCESS is returned.
- If Port is a port number that was returned on a previous call to GetNextPort(),
- then the port number of the next port on the ATA controller is returned in Port,
- and EFI_SUCCESS is returned. If Port is not 0xFFFF and Port was not returned on
- a previous call to GetNextPort(), then EFI_INVALID_PARAMETER is returned.
- If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND
- is returned.
- @param[in] This The PPI instance pointer.
- @param[in,out] Port On input, a pointer to the port number on the ATA controller.
- On output, a pointer to the next port number on the ATA
- controller. An input value of 0xFFFF retrieves the first
- port number on the ATA controller.
- @retval EFI_SUCCESS The next port number on the ATA controller was
- returned in Port.
- @retval EFI_NOT_FOUND There are no more ports on this ATA controller.
- @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned
- on a previous call to GetNextPort().
- **/
- EFI_STATUS
- EFIAPI
- AhciAtaPassThruGetNextPort (
- IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
- IN OUT UINT16 *Port
- )
- {
- PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
- PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
- LIST_ENTRY *Node;
- if (This == NULL || Port == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
- if (*Port == 0xFFFF) {
- //
- // If the Port is all 0xFF's, start to traverse the device list from the
- // beginning.
- //
- Node = GetFirstNode (&Private->DeviceList);
- if (!IsNull (&Private->DeviceList, Node)) {
- DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
- *Port = DeviceData->Port;
- goto Exit;
- }
- return EFI_NOT_FOUND;
- } else if (*Port == Private->PreviousPort) {
- Node = GetFirstNode (&Private->DeviceList);
- while (!IsNull (&Private->DeviceList, Node)) {
- DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
- if (DeviceData->Port > *Port){
- *Port = DeviceData->Port;
- goto Exit;
- }
- Node = GetNextNode (&Private->DeviceList, Node);
- }
- return EFI_NOT_FOUND;
- } else {
- //
- // Port is not equal to all 0xFF's and not equal to previous return value.
- //
- return EFI_INVALID_PARAMETER;
- }
- Exit:
- //
- // Update the PreviousPort.
- //
- Private->PreviousPort = *Port;
- return EFI_SUCCESS;
- }
- /**
- Used to retrieve the list of legal port multiplier port numbers for ATA devices
- on a port of an ATA controller. These can either be the list of port multiplier
- ports where ATA devices are actually present on port or the list of legal port
- multiplier ports on that port. Regardless, the caller of this function must probe
- the port number and port multiplier port number returned to see if an ATA device
- is actually present.
- The GetNextDevice() function retrieves the port multiplier port number of an ATA
- device present on a port of an ATA controller.
- If PortMultiplierPort points to a port multiplier port number value that was
- returned on a previous call to GetNextDevice(), then the port multiplier port
- number of the next ATA device on the port of the ATA controller is returned in
- PortMultiplierPort, and EFI_SUCCESS is returned.
- If PortMultiplierPort points to 0xFFFF, then the port multiplier port number
- of the first ATA device on port of the ATA controller is returned in PortMultiplierPort
- and EFI_SUCCESS is returned.
- If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort
- was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
- is returned.
- If PortMultiplierPort is the port multiplier port number of the last ATA device
- on the port of the ATA controller, then EFI_NOT_FOUND is returned.
- @param[in] This The PPI instance pointer.
- @param[in] Port The port number present on the ATA controller.
- @param[in,out] PortMultiplierPort On input, a pointer to the port multiplier
- port number of an ATA device present on the
- ATA controller. If on input a PortMultiplierPort
- of 0xFFFF is specified, then the port multiplier
- port number of the first ATA device is returned.
- On output, a pointer to the port multiplier port
- number of the next ATA device present on an ATA
- controller.
- @retval EFI_SUCCESS The port multiplier port number of the next ATA
- device on the port of the ATA controller was
- returned in PortMultiplierPort.
- @retval EFI_NOT_FOUND There are no more ATA devices on this port of
- the ATA controller.
- @retval EFI_INVALID_PARAMETER PortMultiplierPort is not 0xFFFF, and PortMultiplierPort
- was not returned on a previous call to GetNextDevice().
- **/
- EFI_STATUS
- EFIAPI
- AhciAtaPassThruGetNextDevice (
- IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
- IN UINT16 Port,
- IN OUT UINT16 *PortMultiplierPort
- )
- {
- PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
- PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
- LIST_ENTRY *Node;
- if (This == NULL || PortMultiplierPort == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
- if (Private->PreviousPortMultiplier == 0xFFFF) {
- //
- // If a device is directly attached on a port, previous call to this
- // function will return the value 0xFFFF for PortMultiplierPort. In
- // this case, there should be no more device on the port multiplier.
- //
- Private->PreviousPortMultiplier = 0;
- return EFI_NOT_FOUND;
- }
- if (*PortMultiplierPort == Private->PreviousPortMultiplier) {
- Node = GetFirstNode (&Private->DeviceList);
- while (!IsNull (&Private->DeviceList, Node)) {
- DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
- if ((DeviceData->Port == Port) &&
- (DeviceData->PortMultiplier > *PortMultiplierPort)){
- *PortMultiplierPort = DeviceData->PortMultiplier;
- goto Exit;
- }
- Node = GetNextNode (&Private->DeviceList, Node);
- }
- return EFI_NOT_FOUND;
- } else if (*PortMultiplierPort == 0xFFFF) {
- //
- // If the PortMultiplierPort is all 0xFF's, start to traverse the device list
- // from the beginning.
- //
- Node = GetFirstNode (&Private->DeviceList);
- while (!IsNull (&Private->DeviceList, Node)) {
- DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
- if (DeviceData->Port == Port){
- *PortMultiplierPort = DeviceData->PortMultiplier;
- goto Exit;
- }
- Node = GetNextNode (&Private->DeviceList, Node);
- }
- return EFI_NOT_FOUND;
- } else {
- //
- // PortMultiplierPort is not equal to all 0xFF's and not equal to previous
- // return value.
- //
- return EFI_INVALID_PARAMETER;
- }
- Exit:
- //
- // Update the PreviousPortMultiplier.
- //
- Private->PreviousPortMultiplier = *PortMultiplierPort;
- return EFI_SUCCESS;
- }
- /**
- Gets the device path information of the underlying ATA host controller.
- @param[in] This The PPI instance pointer.
- @param[out] DevicePathLength The length of the device path in bytes specified
- by DevicePath.
- @param[out] DevicePath The device path of the underlying ATA host controller.
- This field re-uses EFI Device Path Protocol as
- defined by Section 10.2 EFI Device Path Protocol
- of UEFI 2.7 Specification.
- @retval EFI_SUCCESS The device path of the ATA host controller has
- been successfully returned.
- @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
- @retval EFI_OUT_OF_RESOURCES Not enough resource to return the device path.
- **/
- EFI_STATUS
- EFIAPI
- AhciAtaPassThruGetDevicePath (
- IN EDKII_PEI_ATA_PASS_THRU_PPI *This,
- OUT UINTN *DevicePathLength,
- OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
- )
- {
- PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
- if (This == NULL || DevicePathLength == NULL || DevicePath == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_PASS_THRU (This);
- *DevicePathLength = Private->DevicePathLength;
- *DevicePath = AllocateCopyPool (Private->DevicePathLength, Private->DevicePath);
- if (*DevicePath == NULL) {
- *DevicePathLength = 0;
- return EFI_OUT_OF_RESOURCES;
- }
- return EFI_SUCCESS;
- }
|