From 490b5ea10bcdab3579d4c12056b177cea52d6f8e Mon Sep 17 00:00:00 2001 From: qianouyang Date: Tue, 3 May 2011 10:31:41 +0000 Subject: [PATCH] Add BlockIO2 Protocol. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11606 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Bus/Ata/AtaAtapiPassThru/AhciMode.c | 542 ++++++++------ .../Bus/Ata/AtaAtapiPassThru/AhciMode.h | 116 +-- .../Ata/AtaAtapiPassThru/AtaAtapiPassThru.c | 617 +++++++++++----- .../Ata/AtaAtapiPassThru/AtaAtapiPassThru.h | 303 +++++++- .../Bus/Ata/AtaAtapiPassThru/IdeMode.c | 666 +++++++++++------- .../Bus/Ata/AtaAtapiPassThru/IdeMode.h | 91 +-- MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c | 294 +++++++- MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h | 237 ++++++- MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf | 3 +- .../Bus/Ata/AtaBusDxe/AtaPassThruExecute.c | 321 ++++++++- .../Universal/Disk/PartitionDxe/ElTorito.c | 18 +- .../Universal/Disk/PartitionDxe/Gpt.c | 92 +-- .../Universal/Disk/PartitionDxe/Mbr.c | 59 +- .../Universal/Disk/PartitionDxe/Partition.c | 612 +++++++++++++--- .../Universal/Disk/PartitionDxe/Partition.h | 79 ++- .../Disk/PartitionDxe/PartitionDxe.inf | 3 +- MdePkg/MdePkg.dec | 3 + 17 files changed, 2880 insertions(+), 1176 deletions(-) diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c index 8ba0201563..7765bfc75c 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c @@ -184,9 +184,50 @@ AhciWaitMemSet ( return EFI_DEVICE_ERROR; } +/** + Check the memory status to the test value. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Offset The memory address to test. + @param[in] MaskValue The mask value of memory. + @param[in] TestValue The test value of memory. + @param[in, out] RetryTimes The retry times value for waitting memory set. + + @retval EFI_NOTREADY The memory is not set. + @retval EFI_TIMEOUT The memory setting retry times out. + @retval EFI_SUCCESS The memory is correct set. + +**/ +EFI_STATUS +EFIAPI +AhciCheckMemSet ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 Offset, + IN UINT32 MaskValue, + IN UINT32 TestValue, + IN UINTN *RetryTimes + ) +{ + UINT32 Value; + + (*RetryTimes) --; + + Value = AhciReadReg (PciIo, Offset) & MaskValue; + + if (Value == TestValue) { + return EFI_SUCCESS; + } + + if ((*RetryTimes) == 0) { + return EFI_TIMEOUT; + } else { + return EFI_NOT_READY; + } +} + /** Check if the device is still on port. It also checks if the AHCI controller - supports the address and data count will be transfered. + supports the address and data count will be transferred. @param PciIo The PCI IO protocol instance. @param Port The number of port. @@ -206,7 +247,7 @@ AhciCheckDeviceStatus ( IN UINT8 Port ) { - UINT32 Data; + UINT32 Data; UINT32 Offset; Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS; @@ -214,7 +255,7 @@ AhciCheckDeviceStatus ( Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK; if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) { - return EFI_SUCCESS; + return EFI_SUCCESS; } return EFI_NOT_READY; @@ -240,7 +281,7 @@ AhciClearPortStatus ( // // Clear any error status - // + // Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR; AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset)); @@ -310,8 +351,8 @@ AhciEnableFisReceive ( IN EFI_PCI_IO_PROTOCOL *PciIo, IN UINT8 Port, IN UINT64 Timeout - ) -{ + ) +{ UINT32 Offset; Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; @@ -370,12 +411,12 @@ AhciDisableFisReceive ( AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE)); return AhciWaitMemSet ( - PciIo, + PciIo, Offset, EFI_AHCI_PORT_CMD_FR, 0, Timeout - ); + ); } @@ -412,7 +453,7 @@ AhciBuildCommand ( IN UINT64 DataLength ) { - UINT64 BaseAddr; + UINT64 BaseAddr; UINT64 PrdtNumber; UINT64 PrdtIndex; UINTN RemainedData; @@ -436,7 +477,7 @@ AhciBuildCommand ( BaseAddr = Data64.Uint64; - ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS)); + ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS)); ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE)); @@ -466,7 +507,7 @@ AhciBuildCommand ( CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber; for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) { - if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) { + if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) { AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1; } else { AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1; @@ -475,7 +516,7 @@ AhciBuildCommand ( Data64.Uint64 = (UINT64)MemAddr; AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba = Data64.Uint32.Lower32; AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32; - RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT; + RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT; MemAddr += EFI_AHCI_MAX_DATA_PER_PRDT; } @@ -543,18 +584,21 @@ AhciBuildCommandFis ( /** Start a PIO data transfer on specific port. - @param PciIo The PCI IO protocol instance. - @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS. - @param Port The number of port. - @param PortMultiplier The timeout value of stop. - @param AtapiCommand The atapi command will be used for the transfer. - @param AtapiCommandLength The length of the atapi command. - @param Read The transfer direction. - @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. - @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. - @param MemoryAddr The pointer to the data buffer. - @param DataCount The data count to be transferred. - @param Timeout The timeout value of non data transfer. + @param[in] PciIo The PCI IO protocol instance. + @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS. + @param[in] Port The number of port. + @param[in] PortMultiplier The timeout value of stop. + @param[in] AtapiCommand The atapi command will be used for the + transfer. + @param[in] AtapiCommandLength The length of the atapi command. + @param[in] Read The transfer direction. + @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. + @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. + @param[in, out] MemoryAddr The pointer to the data buffer. + @param[in] DataCount The data count to be transferred. + @param[in] Timeout The timeout value of non data transfer. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs. @retval EFI_TIMEOUT The operation is time out. @@ -576,7 +620,8 @@ AhciPioTransfer ( IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, IN OUT VOID *MemoryAddr, IN UINT32 DataCount, - IN UINT64 Timeout + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task ) { EFI_STATUS Status; @@ -639,17 +684,17 @@ AhciPioTransfer ( ); Status = AhciStartCommand ( - PciIo, - Port, + PciIo, + Port, 0, Timeout ); if (EFI_ERROR (Status)) { goto Exit; } - + // - // Checking the status and wait the driver sending data + // Check the status and wait the driver sending data // FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS); // @@ -668,7 +713,7 @@ AhciPioTransfer ( // MicroSecondDelay(100); - Delay--; + Delay--; } while (Delay > 0); if (Delay == 0) { @@ -689,30 +734,30 @@ AhciPioTransfer ( ); if (EFI_ERROR (Status)) { - goto Exit; + goto Exit; } Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS; Status = AhciWaitMemSet ( PciIo, - Offset, + Offset, EFI_AHCI_PORT_IS_PSS, EFI_AHCI_PORT_IS_PSS, Timeout - ); + ); if (EFI_ERROR (Status)) { - goto Exit; + goto Exit; } -Exit: +Exit: AhciStopCommand ( - PciIo, + PciIo, Port, Timeout ); AhciDisableFisReceive ( - PciIo, + PciIo, Port, Timeout ); @@ -730,29 +775,32 @@ Exit: /** Start a DMA data transfer on specific port - @param PciIo The PCI IO protocol instance. - @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS. - @param Port The number of port. - @param PortMultiplier The timeout value of stop. - @param AtapiCommand The atapi command will be used for the transfer. - @param AtapiCommandLength The length of the atapi command. - @param Read The transfer direction. - @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. - @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. - @param MemoryAddr The pointer to the data buffer. - @param DataCount The data count to be transferred. - @param Timeout The timeout value of non data transfer. + @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance. + @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS. + @param[in] Port The number of port. + @param[in] PortMultiplier The timeout value of stop. + @param[in] AtapiCommand The atapi command will be used for the + transfer. + @param[in] AtapiCommandLength The length of the atapi command. + @param[in] Read The transfer direction. + @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. + @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. + @param[in, out] MemoryAddr The pointer to the data buffer. + @param[in] DataCount The data count to be transferred. + @param[in] Timeout The timeout value of non data transfer. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs. @retval EFI_TIMEOUT The operation is time out. @retval EFI_UNSUPPORTED The device is not ready for transfer. @retval EFI_SUCCESS The DMA data transfer executes successfully. - + **/ EFI_STATUS EFIAPI AhciDmaTransfer ( - IN EFI_PCI_IO_PROTOCOL *PciIo, + IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance, IN EFI_AHCI_REGISTERS *AhciRegisters, IN UINT8 Port, IN UINT8 PortMultiplier, @@ -763,7 +811,8 @@ AhciDmaTransfer ( IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, IN OUT VOID *MemoryAddr, IN UINTN DataCount, - IN UINT64 Timeout + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task ) { EFI_STATUS Status; @@ -775,141 +824,224 @@ AhciDmaTransfer ( EFI_AHCI_COMMAND_FIS CFis; EFI_AHCI_COMMAND_LIST CmdList; - if (Read) { - Flag = EfiPciIoOperationBusMasterWrite; - } else { - Flag = EfiPciIoOperationBusMasterRead; - } + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_TPL OldTpl; - // - // construct command list and command table with pci bus address - // - MapLength = DataCount; - Status = PciIo->Map ( - PciIo, - Flag, - MemoryAddr, - &MapLength, - &PhyAddr, - &Map - ); + Map = NULL; + PciIo = Instance->PciIo; - if (EFI_ERROR (Status) || (DataCount != MapLength)) { - return EFI_OUT_OF_RESOURCES; + if (PciIo == NULL) { + return EFI_INVALID_PARAMETER; } // - // Package read needed + // Before starting the Blocking BlockIO operation, push to finish all non-blocking + // BlockIO tasks. + // Delay 100us to simulate the blocking time out checking. // - AhciBuildCommandFis (&CFis, AtaCommandBlock); + while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + AsyncNonBlockingTransferRoutine (NULL, Instance); + gBS->RestoreTPL (OldTpl); + // + // Stall for 100us. + // + MicroSecondDelay (100); + } - ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST)); + if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) { + // + // Mark the Task to indicate that it has been started. + // + if (Task != NULL) { + Task->IsStart = TRUE; + Task->RetryTimes = (UINT32) (DivU64x32(Timeout, 1000) + 1); + } + if (Read) { + Flag = EfiPciIoOperationBusMasterWrite; + } else { + Flag = EfiPciIoOperationBusMasterRead; + } - CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4; - CmdList.AhciCmdW = Read ? 0 : 1; + // + // Construct command list and command table with pci bus address. + // + MapLength = DataCount; + Status = PciIo->Map ( + PciIo, + Flag, + MemoryAddr, + &MapLength, + &PhyAddr, + &Map + ); + + if (EFI_ERROR (Status) || (DataCount != MapLength)) { + return EFI_OUT_OF_RESOURCES; + } - AhciBuildCommand ( - PciIo, - AhciRegisters, - Port, - PortMultiplier, - &CFis, - &CmdList, - AtapiCommand, - AtapiCommandLength, - 0, - (VOID *)(UINTN)PhyAddr, - DataCount - ); - - Status = AhciStartCommand ( - PciIo, - Port, - 0, - Timeout - ); - if (EFI_ERROR (Status)) { - goto Exit; - } - - // - // Wait device PRD processed - // - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS; - Status = AhciWaitMemSet ( - PciIo, - Offset, - EFI_AHCI_PORT_IS_DPS, - EFI_AHCI_PORT_IS_DPS, - Timeout - ); - - if (EFI_ERROR (Status)) { - goto Exit; + if (Task != NULL) { + Task->Map = Map; + } + // + // Package read needed + // + AhciBuildCommandFis (&CFis, AtaCommandBlock); + + ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST)); + + CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4; + CmdList.AhciCmdW = Read ? 0 : 1; + + AhciBuildCommand ( + PciIo, + AhciRegisters, + Port, + PortMultiplier, + &CFis, + &CmdList, + AtapiCommand, + AtapiCommandLength, + 0, + (VOID *)(UINTN)PhyAddr, + DataCount + ); + + Status = AhciStartCommand ( + PciIo, + Port, + 0, + Timeout + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Wait device PRD processed + // + Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS; + Status = AhciWaitMemSet ( + PciIo, + Offset, + EFI_AHCI_PORT_IS_DPS, + EFI_AHCI_PORT_IS_DPS, + Timeout + ); + + if (EFI_ERROR (Status)) { + goto Exit; + } } // // Wait for command compelte // Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI; - Status = AhciWaitMemSet ( - PciIo, - Offset, - 0xFFFFFFFF, - 0, - Timeout - ); + if (Task != NULL) { + // + // For Non-blocking + // + Status = AhciCheckMemSet ( + PciIo, + Offset, + 0xFFFFFFFF, + 0, + (UINTN *) (&Task->RetryTimes) + ); + } else { + Status = AhciWaitMemSet ( + PciIo, + Offset, + 0xFFFFFFFF, + 0, + Timeout + ); + } + if (EFI_ERROR (Status)) { goto Exit; } Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS; - Status = AhciWaitMemSet ( - PciIo, - Offset, - EFI_AHCI_PORT_IS_DHRS, - EFI_AHCI_PORT_IS_DHRS, - Timeout - ); + + if (Task != NULL) { + // + // For Non-blocking + // + Status = AhciCheckMemSet ( + PciIo, + Offset, + EFI_AHCI_PORT_IS_DHRS, + EFI_AHCI_PORT_IS_DHRS, + (UINTN *) (&Task->RetryTimes) + ); + } else { + Status = AhciWaitMemSet ( + PciIo, + Offset, + EFI_AHCI_PORT_IS_DHRS, + EFI_AHCI_PORT_IS_DHRS, + Timeout + ); + } + if (EFI_ERROR (Status)) { goto Exit; } -Exit: - AhciStopCommand ( - PciIo, - Port, - Timeout - ); +Exit: + // + // For Blocking mode, the command should be stopped, the Fis should be disabled + // and the PciIo should be unmapped. + // For non-blocking mode, only when a error is happened (if the return status is + // EFI_NOT_READY that means the command doesn't finished, try again.), first do the + // context cleanup, then set the packet's Asb status. + // + if (Task == NULL || + ((Task != NULL) && (Status != EFI_NOT_READY)) + ) { + AhciStopCommand ( + PciIo, + Port, + Timeout + ); - AhciDisableFisReceive ( - PciIo, - Port, - Timeout - ); + AhciDisableFisReceive ( + PciIo, + Port, + Timeout + ); - PciIo->Unmap ( - PciIo, - Map - ); - - AhciDumpPortStatus (PciIo, Port, AtaStatusBlock); + PciIo->Unmap ( + PciIo, + (Task != NULL) ? Task->Map : Map + ); + if (Task != NULL) { + Task->Packet->Asb->AtaStatus = 0x01; + } + } + + AhciDumpPortStatus (PciIo, Port, AtaStatusBlock); return Status; } /** Start a non data transfer on specific port. - @param PciIo The PCI IO protocol instance. - @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS. - @param Port The number of port. - @param PortMultiplier The timeout value of stop. - @param AtapiCommand The atapi command will be used for the transfer. - @param AtapiCommandLength The length of the atapi command. - @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. - @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. - @param Timeout The timeout value of non data transfer. + @param[in] PciIo The PCI IO protocol instance. + @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS. + @param[in] Port The number of port. + @param[in] PortMultiplier The timeout value of stop. + @param[in] AtapiCommand The atapi command will be used for the + transfer. + @param[in] AtapiCommandLength The length of the atapi command. + @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. + @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. + @param[in] Timeout The timeout value of non data transfer. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs. @retval EFI_TIMEOUT The operation is time out. @@ -928,15 +1060,16 @@ AhciNonDataTransfer ( IN UINT8 AtapiCommandLength, IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN UINT64 Timeout - ) + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task + ) { - EFI_STATUS Status; + EFI_STATUS Status; UINTN FisBaseAddr; UINT32 Offset; UINT32 Value; UINT32 Delay; - + EFI_AHCI_COMMAND_FIS CFis; EFI_AHCI_COMMAND_LIST CmdList; @@ -961,18 +1094,18 @@ AhciNonDataTransfer ( 0, NULL, 0 - ); - + ); + Status = AhciStartCommand ( - PciIo, - Port, + PciIo, + Port, 0, Timeout ); if (EFI_ERROR (Status)) { goto Exit; } - + // // Wait device sends the Response Fis // @@ -993,7 +1126,7 @@ AhciNonDataTransfer ( // MicroSecondDelay(100); - Delay --; + Delay --; } while (Delay > 0); if (Delay == 0) { @@ -1009,17 +1142,17 @@ AhciNonDataTransfer ( 0xFFFFFFFF, 0, Timeout - ); - -Exit: + ); + +Exit: AhciStopCommand ( - PciIo, + PciIo, Port, Timeout ); AhciDisableFisReceive ( - PciIo, + PciIo, Port, Timeout ); @@ -1056,7 +1189,7 @@ AhciStopCommand ( Data = AhciReadReg (PciIo, Offset); if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) { - return EFI_SUCCESS; + return EFI_SUCCESS; } if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) { @@ -1064,22 +1197,22 @@ AhciStopCommand ( } return AhciWaitMemSet ( - PciIo, + PciIo, Offset, EFI_AHCI_PORT_CMD_CR, 0, Timeout - ); + ); } /** Start command for give slot on specific port. - + @param PciIo The PCI IO protocol instance. @param Port The number of port. - @param CommandSlot The number of CommandSlot. + @param CommandSlot The number of Command Slot. @param Timeout The timeout value of start. - + @retval EFI_DEVICE_ERROR The command start unsuccessfully. @retval EFI_TIMEOUT The operation is time out. @retval EFI_SUCCESS The command start successfully. @@ -1119,14 +1252,14 @@ AhciStartCommand ( Port, Timeout ); - + if (EFI_ERROR (Status)) { return Status; } Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; PortStatus = AhciReadReg (PciIo, Offset); - + StartCmd = 0; if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) { StartCmd = AhciReadReg (PciIo, Offset); @@ -1143,12 +1276,12 @@ AhciStartCommand ( AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL); AhciWaitMemSet ( - PciIo, + PciIo, Offset, EFI_AHCI_PORT_CMD_COL, 0, Timeout - ); + ); } } @@ -1190,8 +1323,8 @@ AhciPortReset ( ) { EFI_STATUS Status; - UINT32 Offset; - + UINT32 Offset; + AhciClearPortStatus (PciIo, Port); AhciStopCommand (PciIo, Port, Timeout); @@ -1205,14 +1338,14 @@ AhciPortReset ( AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT); // - // wait 5 milliseceond before de-assert DET + // wait 5 millisecond before de-assert DET // MicroSecondDelay (5000); AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK); // - // wait 5 milliseceond before de-assert DET + // wait 5 millisecond before de-assert DET // MicroSecondDelay (5000); @@ -1226,7 +1359,7 @@ AhciPortReset ( EFI_AHCI_PORT_SSTS_DET_MASK, EFI_AHCI_PORT_SSTS_DET_PCE, Timeout - ); + ); if (EFI_ERROR (Status)) { return Status; @@ -1240,11 +1373,10 @@ AhciPortReset ( /** Do AHCI HBA reset. - + @param PciIo The PCI IO protocol instance. @param Timeout The timeout value of reset. - - + @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset. @retval EFI_TIMEOUT The reset operation is time out. @retval EFI_SUCCESS AHCI controller is reset successfully. @@ -1340,7 +1472,8 @@ AhciAtaSmartReturnStatusCheck ( 0, &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); if (EFI_ERROR (Status)) { @@ -1390,7 +1523,7 @@ AhciAtaSmartSupport ( IN EFI_AHCI_REGISTERS *AhciRegisters, IN UINT8 Port, IN UINT8 PortMultiplier, - IN EFI_IDENTIFY_DATA *IdentifyData, + IN EFI_IDENTIFY_DATA *IdentifyData, IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock ) { @@ -1430,7 +1563,8 @@ AhciAtaSmartSupport ( 0, &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); @@ -1455,7 +1589,8 @@ AhciAtaSmartSupport ( 0, &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); if (!EFI_ERROR (Status)) { @@ -1469,7 +1604,7 @@ AhciAtaSmartSupport ( } } } - DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n", + DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n", Port, PortMultiplier)); } @@ -1511,7 +1646,7 @@ AhciIdentify ( ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK)); ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK)); - + AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE; AtaCommandBlock.AtaSectorCount = 1; @@ -1527,7 +1662,8 @@ AhciIdentify ( &AtaStatusBlock, Buffer, sizeof (EFI_IDENTIFY_DATA), - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); return Status; @@ -1565,7 +1701,7 @@ AhciIdentifyPacket ( if (PciIo == NULL || AhciRegisters == NULL) { return EFI_INVALID_PARAMETER; } - + ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK)); ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK)); @@ -1584,7 +1720,8 @@ AhciIdentifyPacket ( &AtaStatusBlock, Buffer, sizeof (EFI_IDENTIFY_DATA), - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); return Status; @@ -1623,7 +1760,7 @@ AhciDeviceSetFeature ( ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK)); ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK)); - + AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES; AtaCommandBlock.AtaFeatures = (UINT8) Feature; AtaCommandBlock.AtaFeaturesExp = (UINT8) (Feature >> 8); @@ -1641,7 +1778,8 @@ AhciDeviceSetFeature ( 0, &AtaCommandBlock, &AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); return Status; @@ -1708,7 +1846,7 @@ AhciPacketCommandExecute ( Read = FALSE; } - if (Length == 0) { + if (Length == 0) { Status = AhciNonDataTransfer ( PciIo, AhciRegisters, @@ -1718,7 +1856,8 @@ AhciPacketCommandExecute ( Packet->CdbLength, &AtaCommandBlock, &AtaStatusBlock, - Packet->Timeout + Packet->Timeout, + NULL ); } else { // @@ -1742,7 +1881,8 @@ AhciPacketCommandExecute ( &AtaStatusBlock, Buffer, Length, - Packet->Timeout + Packet->Timeout, + NULL ); if (!EFI_ERROR (Status)) { break; diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h index 1efe0ebe73..9c4a9397e9 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h @@ -1,7 +1,7 @@ /** @file Header file for AHCI mode of ATA host controller. - Copyright (c) 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2011, 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 @@ -154,7 +154,7 @@ typedef union { #define EFI_AHCI_PORT_SERR_BDE BIT19 #define EFI_AHCI_PORT_SERR_DE BIT20 #define EFI_AHCI_PORT_SERR_CRCE BIT21 -#define EFI_AHCI_PORT_SERR_HE BIT22 +#define EFI_AHCI_PORT_SERR_HE BIT22 #define EFI_AHCI_PORT_SERR_LSE BIT23 #define EFI_AHCI_PORT_SERR_TSTE BIT24 #define EFI_AHCI_PORT_SERR_UFT BIT25 @@ -348,117 +348,5 @@ AhciStopCommand ( IN UINT64 Timeout ); -/** - Start a non data transfer on specific port. - - @param PciIo The PCI IO protocol instance. - @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS. - @param Port The number of port. - @param PortMultiplier The timeout value of stop. - @param AtapiCommand The atapi command will be used for the transfer. - @param AtapiCommandLength The length of the atapi command. - @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. - @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. - @param Timeout The timeout value of non data transfer. - - @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs. - @retval EFI_TIMEOUT The operation is time out. - @retval EFI_UNSUPPORTED The device is not ready for transfer. - @retval EFI_SUCCESS The non data transfer executes successfully. - -**/ -EFI_STATUS -EFIAPI -AhciNonDataTransfer ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN EFI_AHCI_REGISTERS *AhciRegisters, - IN UINT8 Port, - IN UINT8 PortMultiplier, - IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL, - IN UINT8 AtapiCommandLength, - IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, - IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN UINT64 Timeout - ); - -/** - Start a DMA data transfer on specific port - - @param PciIo The PCI IO protocol instance. - @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS. - @param Port The number of port. - @param PortMultiplier The timeout value of stop. - @param AtapiCommand The atapi command will be used for the transfer. - @param AtapiCommandLength The length of the atapi command. - @param Read The transfer direction. - @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. - @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. - @param MemoryAddr The pointer to the data buffer. - @param DataCount The data count to be transferred. - @param Timeout The timeout value of non data transfer. - - @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs. - @retval EFI_TIMEOUT The operation is time out. - @retval EFI_UNSUPPORTED The device is not ready for transfer. - @retval EFI_SUCCESS The DMA data transfer executes successfully. - -**/ -EFI_STATUS -EFIAPI -AhciDmaTransfer ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN EFI_AHCI_REGISTERS *AhciRegisters, - IN UINT8 Port, - IN UINT8 PortMultiplier, - IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL, - IN UINT8 AtapiCommandLength, - IN BOOLEAN Read, - IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, - IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN OUT VOID *MemoryAddr, - IN UINTN DataCount, - IN UINT64 Timeout - ); - -/** - Start a PIO data transfer on specific port. - - @param PciIo The PCI IO protocol instance. - @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS. - @param Port The number of port. - @param PortMultiplier The timeout value of stop. - @param AtapiCommand The atapi command will be used for the transfer. - @param AtapiCommandLength The length of the atapi command. - @param Read The transfer direction. - @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. - @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. - @param MemoryAddr The pointer to the data buffer. - @param DataCount The data count to be transferred. - @param Timeout The timeout value of non data transfer. - - @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs. - @retval EFI_TIMEOUT The operation is time out. - @retval EFI_UNSUPPORTED The device is not ready for transfer. - @retval EFI_SUCCESS The PIO data transfer executes successfully. - -**/ -EFI_STATUS -EFIAPI -AhciPioTransfer ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN EFI_AHCI_REGISTERS *AhciRegisters, - IN UINT8 Port, - IN UINT8 PortMultiplier, - IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL, - IN UINT8 AtapiCommandLength, - IN BOOLEAN Read, - IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, - IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN OUT VOID *MemoryAddr, - IN UINT32 DataCount, - IN UINT64 Timeout - ); - - #endif diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c index ca64df7f6b..3e135d74ec 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c @@ -39,7 +39,7 @@ ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = { // bits. // Note that the driver doesn't support AtaPassThru non blocking I/O. // - EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL, + EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_NONBLOCKIO, // // IoAlign // @@ -98,7 +98,12 @@ ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = { 0, // PreviousPort 0, // PreviousPortMultiplier 0, // PreviousTargetId - 0 // PreviousLun + 0, // PreviousLun + NULL, // Timer event + { // NonBlocking TaskList + NULL, + NULL + } }; ATAPI_DEVICE_PATH mAtapiDevicePathTemplate = { @@ -132,12 +137,304 @@ UINT8 mScsiId[TARGET_MAX_BYTES] = { 0xFF, 0xFF, 0xFF, 0xFF }; +/** + Sends an ATA command to an ATA device that is attached to the ATA controller. This function + supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required, + and the non-blocking I/O functionality is optional. + + @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 0. + @param[in, out] Packet A pointer to the ATA command to send to the ATA device specified by Port + and PortMultiplierPort. + @param[in] Instance Pointer to the ATA_ATAPI_PASS_THRU_INSTANCE. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. + + @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 +EFIAPI +AtaPassThruPassThruExecute ( + IN UINT16 Port, + IN UINT16 PortMultiplierPort, + IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet, + IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance, + IN ATA_NONBLOCK_TASK *Task OPTIONAL + ) +{ + EFI_ATA_PASS_THRU_CMD_PROTOCOL Protocol; + EFI_ATA_HC_WORK_MODE Mode; + EFI_STATUS Status; + + Protocol = Packet->Protocol; + + Mode = Instance->Mode; + switch (Mode) { + case EfiAtaIdeMode: + // + // Reassign IDE mode io port registers' base addresses + // + Status = GetIdeRegisterIoAddr (Instance->PciIo, Instance->IdeRegisters); + + if (EFI_ERROR (Status)) { + return Status; + } + + switch (Protocol) { + case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA: + Status = AtaNonDataCommandIn ( + Instance->PciIo, + &Instance->IdeRegisters[Port], + Packet->Acb, + Packet->Asb, + Packet->Timeout, + Task + ); + break; + case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN: + Status = AtaPioDataInOut ( + Instance->PciIo, + &Instance->IdeRegisters[Port], + Packet->InDataBuffer, + Packet->InTransferLength, + TRUE, + Packet->Acb, + Packet->Asb, + Packet->Timeout, + Task + ); + break; + case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT: + Status = AtaPioDataInOut ( + Instance->PciIo, + &Instance->IdeRegisters[Port], + Packet->OutDataBuffer, + Packet->OutTransferLength, + FALSE, + Packet->Acb, + Packet->Asb, + Packet->Timeout, + Task + ); + break; + case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN: + Status = AtaUdmaInOut ( + Instance, + &Instance->IdeRegisters[Port], + TRUE, + Packet->InDataBuffer, + Packet->InTransferLength, + Packet->Acb, + Packet->Asb, + Packet->Timeout, + Task + ); + break; + case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT: + Status = AtaUdmaInOut ( + Instance, + &Instance->IdeRegisters[Port], + FALSE, + Packet->OutDataBuffer, + Packet->OutTransferLength, + Packet->Acb, + Packet->Asb, + Packet->Timeout, + Task + ); + break; + default : + return EFI_UNSUPPORTED; + } + break; + case EfiAtaAhciMode : + switch (Protocol) { + case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA: + Status = AhciNonDataTransfer ( + Instance->PciIo, + &Instance->AhciRegisters, + (UINT8)Port, + (UINT8)PortMultiplierPort, + NULL, + 0, + Packet->Acb, + Packet->Asb, + Packet->Timeout, + Task + ); + break; + case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN: + Status = AhciPioTransfer ( + Instance->PciIo, + &Instance->AhciRegisters, + (UINT8)Port, + (UINT8)PortMultiplierPort, + NULL, + 0, + TRUE, + Packet->Acb, + Packet->Asb, + Packet->InDataBuffer, + Packet->InTransferLength, + Packet->Timeout, + Task + ); + break; + case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT: + Status = AhciPioTransfer ( + Instance->PciIo, + &Instance->AhciRegisters, + (UINT8)Port, + (UINT8)PortMultiplierPort, + NULL, + 0, + FALSE, + Packet->Acb, + Packet->Asb, + Packet->OutDataBuffer, + Packet->OutTransferLength, + Packet->Timeout, + Task + ); + break; + case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN: + Status = AhciDmaTransfer ( + Instance, + &Instance->AhciRegisters, + (UINT8)Port, + (UINT8)PortMultiplierPort, + NULL, + 0, + TRUE, + Packet->Acb, + Packet->Asb, + Packet->InDataBuffer, + Packet->InTransferLength, + Packet->Timeout, + Task + ); + break; + case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT: + Status = AhciDmaTransfer ( + Instance, + &Instance->AhciRegisters, + (UINT8)Port, + (UINT8)PortMultiplierPort, + NULL, + 0, + FALSE, + Packet->Acb, + Packet->Asb, + Packet->OutDataBuffer, + Packet->OutTransferLength, + Packet->Timeout, + Task + ); + break; + default : + return EFI_UNSUPPORTED; + } + break; + + default: + Status = EFI_DEVICE_ERROR; + break; + } + + return Status; +} + +/** + Call back function when the timer event is signaled. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the + Event. + +**/ +VOID +EFIAPI +AsyncNonBlockingTransferRoutine ( + EFI_EVENT Event, + VOID* Context + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *EntryHeader; + ATA_NONBLOCK_TASK *Task; + EFI_STATUS Status; + ATA_ATAPI_PASS_THRU_INSTANCE *Instance; + + Instance = (ATA_ATAPI_PASS_THRU_INSTANCE *) Context; + EntryHeader = &Instance->NonBlockingTaskList; + // + // Get the Taks from the Taks List and execute it, until there is + // no task in the list or the device is busy with task (EFI_NOT_READY). + // + while (TRUE) { + if (!IsListEmpty (EntryHeader)) { + Entry = GetFirstNode (EntryHeader); + Task = ATA_NON_BLOCK_TASK_FROM_ENTRY (Entry); + } else { + return; + } + + Status = AtaPassThruPassThruExecute ( + Task->Port, + Task->PortMultiplier, + Task->Packet, + Instance, + Task + ); + + // + // If the data transfer meet a error which is not dumped into the status block + // set the Status block related bit. + // + if ((Status != EFI_NOT_READY) && (Status != EFI_SUCCESS)) { + Task->Packet->Asb->AtaStatus = 0x01; + } + // + // For Non blocking mode, the Status of EFI_NOT_READY means the operation + // is not finished yet. Other Status indicate the operation is either + // successful or failed. + // + if (Status != EFI_NOT_READY) { + RemoveEntryList (&Task->Link); + gBS->SignalEvent (Task->Event); + FreePool (Task); + } else { + break; + } + } +} + /** The Entry Point of module. - @param[in] ImageHandle The firmware allocated handle for the EFI image. + @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. @@ -266,7 +563,7 @@ AtaAtapiPassThruSupported ( // return Status; } - + // // Close the I/O Abstraction(s) used to perform the supported test // @@ -324,7 +621,7 @@ AtaAtapiPassThruSupported ( 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. + 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 @@ -333,7 +630,7 @@ AtaAtapiPassThruSupported ( @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. + 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 @@ -446,6 +743,28 @@ AtaAtapiPassThruStart ( Instance->AtaPassThru.Mode = &Instance->AtaPassThruMode; Instance->ExtScsiPassThru.Mode = &Instance->ExtScsiPassThruMode; InitializeListHead(&Instance->DeviceList); + InitializeListHead(&Instance->NonBlockingTaskList); + + Instance->TimerEvent = NULL; + + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + AsyncNonBlockingTransferRoutine, + Instance, + &Instance->TimerEvent + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Set 1ms timer. + // + Status = gBS->SetTimer (Instance->TimerEvent, TimerPeriodic, 10000); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } // // Enumerate all inserted ATA devices. @@ -475,6 +794,10 @@ ErrorExit: ); } + if (Instance->TimerEvent != NULL) { + gBS->CloseEvent (Instance->TimerEvent); + } + // // Remove all inserted ATA devices. // @@ -542,13 +865,22 @@ AtaAtapiPassThruStop ( if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } - - Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS(AtaPassThru); - PciIo = Instance->PciIo; + + Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (AtaPassThru); + + // + // Close Non-Blocking timer and free Task list. + // + if (Instance->TimerEvent != NULL) { + gBS->CloseEvent (Instance->TimerEvent); + Instance->TimerEvent = NULL; + } + DestroyAsynTaskList (Instance); // // Disable this ATA host controller. // + PciIo = Instance->PciIo; Status = PciIo->Attributes ( PciIo, EfiPciIoAttributeOperationSupported, @@ -672,7 +1004,7 @@ SearchDeviceInfoList ( } Node = GetNextNode (&Instance->DeviceList, Node); - } + } return NULL; } @@ -757,6 +1089,42 @@ DestroyDeviceInfoList ( } } +/** + Destroy all pending non blocking tasks. + + @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance. + +**/ +VOID +EFIAPI +DestroyAsynTaskList ( + IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *DelEntry; + ATA_NONBLOCK_TASK *Task; + EFI_TPL OldTpl; + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + if (!IsListEmpty (&Instance->NonBlockingTaskList)) { + // + // Free the Subtask list. + // + for (Entry = (&Instance->NonBlockingTaskList)->ForwardLink; + Entry != (&Instance->NonBlockingTaskList); + ) { + DelEntry = Entry; + Entry = Entry->ForwardLink; + Task = ATA_NON_BLOCK_TASK_FROM_ENTRY (DelEntry); + + RemoveEntryList (DelEntry); + FreePool (Task); + } + } + gBS->RestoreTPL (OldTpl); +} + /** Enumerate all attached ATA devices at IDE mode or AHCI mode separately. @@ -863,17 +1231,16 @@ AtaPassThruPassThru ( IN UINT16 PortMultiplierPort, IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet, IN EFI_EVENT Event OPTIONAL - ) + ) { - EFI_STATUS Status; ATA_ATAPI_PASS_THRU_INSTANCE *Instance; - EFI_ATA_PASS_THRU_CMD_PROTOCOL Protocol; - EFI_ATA_HC_WORK_MODE Mode; LIST_ENTRY *Node; EFI_ATA_DEVICE_INFO *DeviceInfo; EFI_IDENTIFY_DATA *IdentifyData; UINT64 Capacity; UINT32 MaxSectorCount; + ATA_NONBLOCK_TASK *Task; + EFI_TPL OldTpl; Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This); @@ -940,173 +1307,37 @@ AtaPassThruPassThru ( return EFI_BAD_BUFFER_SIZE; } - Status = EFI_UNSUPPORTED; - Protocol = Packet->Protocol; - - Mode = Instance->Mode; - switch (Mode) { - case EfiAtaIdeMode: - // - // Reassign IDE mode io port registers' base addresses - // - Status = GetIdeRegisterIoAddr (Instance->PciIo, Instance->IdeRegisters); - - if (EFI_ERROR (Status)) { - return Status; - } - - switch (Protocol) { - case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA: - Status = AtaNonDataCommandIn( - Instance->PciIo, - &Instance->IdeRegisters[Port], - Packet->Acb, - Packet->Asb, - Packet->Timeout - ); - break; - case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN: - Status = AtaPioDataInOut( - Instance->PciIo, - &Instance->IdeRegisters[Port], - Packet->InDataBuffer, - Packet->InTransferLength, - TRUE, - Packet->Acb, - Packet->Asb, - Packet->Timeout - ); - break; - case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT: - Status = AtaPioDataInOut( - Instance->PciIo, - &Instance->IdeRegisters[Port], - Packet->OutDataBuffer, - Packet->OutTransferLength, - FALSE, - Packet->Acb, - Packet->Asb, - Packet->Timeout - ); - break; - case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN: - Status = AtaUdmaInOut( - Instance->PciIo, - &Instance->IdeRegisters[Port], - TRUE, - Packet->InDataBuffer, - Packet->InTransferLength, - Packet->Acb, - Packet->Asb, - Packet->Timeout - ); - break; - case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT: - Status = AtaUdmaInOut( - Instance->PciIo, - &Instance->IdeRegisters[Port], - FALSE, - Packet->OutDataBuffer, - Packet->OutTransferLength, - Packet->Acb, - Packet->Asb, - Packet->Timeout - ); - break; - default : - return EFI_UNSUPPORTED; - } - break; - case EfiAtaAhciMode : - switch (Protocol) { - case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA: - Status = AhciNonDataTransfer( - Instance->PciIo, - &Instance->AhciRegisters, - (UINT8)Port, - (UINT8)PortMultiplierPort, - NULL, - 0, - Packet->Acb, - Packet->Asb, - Packet->Timeout - ); - break; - case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN: - Status = AhciPioTransfer( - Instance->PciIo, - &Instance->AhciRegisters, - (UINT8)Port, - (UINT8)PortMultiplierPort, - NULL, - 0, - TRUE, - Packet->Acb, - Packet->Asb, - Packet->InDataBuffer, - Packet->InTransferLength, - Packet->Timeout - ); - break; - case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT: - Status = AhciPioTransfer( - Instance->PciIo, - &Instance->AhciRegisters, - (UINT8)Port, - (UINT8)PortMultiplierPort, - NULL, - 0, - FALSE, - Packet->Acb, - Packet->Asb, - Packet->OutDataBuffer, - Packet->OutTransferLength, - Packet->Timeout - ); - break; - case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN: - Status = AhciDmaTransfer( - Instance->PciIo, - &Instance->AhciRegisters, - (UINT8)Port, - (UINT8)PortMultiplierPort, - NULL, - 0, - TRUE, - Packet->Acb, - Packet->Asb, - Packet->InDataBuffer, - Packet->InTransferLength, - Packet->Timeout - ); - break; - case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT: - Status = AhciDmaTransfer( - Instance->PciIo, - &Instance->AhciRegisters, - (UINT8)Port, - (UINT8)PortMultiplierPort, - NULL, - 0, - FALSE, - Packet->Acb, - Packet->Asb, - Packet->OutDataBuffer, - Packet->OutTransferLength, - Packet->Timeout - ); - break; - default : - return EFI_UNSUPPORTED; - } - break; + // + // For non-blocking mode, queue the Task into the list. + // + if (Event != NULL) { + Task = AllocateZeroPool (sizeof (ATA_NONBLOCK_TASK)); + if (Task == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Task->Signature = ATA_NONBLOCKING_TASK_SIGNATURE; + Task->Port = Port; + Task->PortMultiplier = PortMultiplierPort; + Task->Packet = Packet; + Task->Event = Event; + Task->IsStart = FALSE; + Task->RetryTimes = 0; + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Instance->NonBlockingTaskList, &Task->Link); + gBS->RestoreTPL (OldTpl); - default: - Status = EFI_DEVICE_ERROR; - break; + return EFI_SUCCESS; + } else { + return AtaPassThruPassThruExecute ( + Port, + PortMultiplierPort, + Packet, + Instance, + NULL + ); } - - return Status; } /** @@ -1197,7 +1428,7 @@ AtaPassThruGetNextPort ( // return EFI_INVALID_PARAMETER; } - + Exit: // // Update the PreviousPort and PreviousPortMultiplier. @@ -1216,20 +1447,20 @@ Exit: 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. @@ -1309,7 +1540,7 @@ AtaPassThruGetNextDevice ( // return EFI_INVALID_PARAMETER; } - + Exit: // // Update the PreviousPort and PreviousPortMultiplier. @@ -1377,7 +1608,7 @@ AtaPassThruBuildDevicePath ( if (Node == NULL) { return EFI_NOT_FOUND; } - + if (Instance->Mode == EfiAtaIdeMode) { DevicePathNode = AllocateCopyPool (sizeof (ATAPI_DEVICE_PATH), &mAtapiDevicePathTemplate); if (DevicePathNode == NULL) { @@ -1719,7 +1950,7 @@ ExtScsiPassThruPassThru ( can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI - channel. + channel. @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance. @param Target On input, a pointer to the Target ID (an array of size @@ -1840,7 +2071,7 @@ Exit: Instance->PreviousLun = *Lun; return EFI_SUCCESS; -} +} /** Used to allocate and build a device path node for a SCSI device on a SCSI channel. @@ -2031,8 +2262,8 @@ ExtScsiPassThruResetChannel ( ) { return EFI_UNSUPPORTED; -} - +} + /** Resets a SCSI logical unit that is connected to a SCSI channel. @@ -2061,7 +2292,7 @@ ExtScsiPassThruResetTargetLun ( ) { return EFI_UNSUPPORTED; -} +} /** Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either @@ -2176,5 +2407,5 @@ Exit: Instance->PreviousTargetId = *Target16; return EFI_SUCCESS; -} +} diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h index e1401867bb..0987478564 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h @@ -1,7 +1,7 @@ /** @file Header file for ATA/ATAPI PASS THRU driver. - Copyright (c) 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2011, 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 @@ -47,6 +47,9 @@ extern EFI_COMPONENT_NAME2_PROTOCOL gAtaAtapiPassThruComponentName2; #define ATA_ATAPI_PASS_THRU_SIGNATURE SIGNATURE_32 ('a', 'a', 'p', 't') #define ATA_ATAPI_DEVICE_SIGNATURE SIGNATURE_32 ('a', 'd', 'e', 'v') +#define ATA_NONBLOCKING_TASK_SIGNATURE SIGNATURE_32 ('a', 't', 's', 'k') + +typedef struct _ATA_NONBLOCK_TASK ATA_NONBLOCK_TASK; typedef enum { EfiAtaIdeMode, @@ -111,9 +114,33 @@ typedef struct { // UINT16 PreviousTargetId; UINT64 PreviousLun; - + + // + // For Non-blocking. + // + EFI_EVENT TimerEvent; + LIST_ENTRY NonBlockingTaskList; } ATA_ATAPI_PASS_THRU_INSTANCE; +// +// Task for Non-blocking mode. +// +struct _ATA_NONBLOCK_TASK { + UINT32 Signature; + LIST_ENTRY Link; + + UINT16 Port; + UINT16 PortMultiplier; + EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet; + BOOLEAN IsStart; + EFI_EVENT Event; + UINT64 RetryTimes; + VOID *Map; // Pointer to map. + VOID *TableMap;// Pointer to PRD table map. + EFI_ATA_DMA_PRD *MapBaseAddress; // Pointer to range Base address for Map. + UINTN PageCount; // The page numbers used by PCIO freebuffer. +}; + // // Timeout value which uses 100ns as a unit. // It means 3 second span. @@ -142,6 +169,14 @@ typedef struct { Link, \ ATA_ATAPI_DEVICE_SIGNATURE \ ); + +#define ATA_NON_BLOCK_TASK_FROM_ENTRY(a) \ + CR (a, \ + ATA_NONBLOCK_TASK, \ + Link, \ + ATA_NONBLOCKING_TASK_SIGNATURE \ + ); + /** Retrieves a Unicode string that is the user readable name of the driver. @@ -453,6 +488,18 @@ DestroyDeviceInfoList ( IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance ); +/** + Destroy all pending non blocking tasks. + + @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance. + +**/ +VOID +EFIAPI +DestroyAsynTaskList ( + IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance + ); + /** Enumerate all attached ATA devices at IDE mode or AHCI mode separately. @@ -470,6 +517,21 @@ EnumerateAttachedDevice ( IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance ); +/** + Call back funtion when the timer event is signaled. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the + Event. + +**/ +VOID +EFIAPI +AsyncNonBlockingTransferRoutine ( + EFI_EVENT Event, + VOID* Context + ); + /** Sends an ATA command to an ATA device that is attached to the ATA controller. This function supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required, @@ -556,16 +618,16 @@ AtaPassThruGetNextPort ( 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. @@ -673,6 +735,7 @@ AtaPassThruBuildDevicePath ( @retval EFI_UNSUPPORTED This driver does not support the device path node type in DevicePath. @retval EFI_NOT_FOUND A valid translation from DevicePath to a port number and port multiplier port number does not exist. + **/ EFI_STATUS EFIAPI @@ -809,7 +872,7 @@ ExtScsiPassThruPassThru ( can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI - channel. + channel. @param This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance. @param Target On input, a pointer to the Target ID (an array of size @@ -918,7 +981,7 @@ EFIAPI ExtScsiPassThruResetChannel ( IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This ); - + /** Resets a SCSI logical unit that is connected to a SCSI channel. @@ -1003,5 +1066,231 @@ AhciModeInitialization ( IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance ); +/** + Start a non data transfer on specific port. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS. + @param[in] Port The number of port. + @param[in] PortMultiplier The timeout value of stop. + @param[in] AtapiCommand The atapi command will be used for the + transfer. + @param[in] AtapiCommandLength The length of the atapi command. + @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. + @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. + @param[in] Timeout The timeout value of non data transfer. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. + + @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs. + @retval EFI_TIMEOUT The operation is time out. + @retval EFI_UNSUPPORTED The device is not ready for transfer. + @retval EFI_SUCCESS The non data transfer executes successfully. + +**/ +EFI_STATUS +EFIAPI +AhciNonDataTransfer ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_AHCI_REGISTERS *AhciRegisters, + IN UINT8 Port, + IN UINT8 PortMultiplier, + IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL, + IN UINT8 AtapiCommandLength, + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, + IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task + ); + +/** + Start a DMA data transfer on specific port + + @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance. + @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS. + @param[in] Port The number of port. + @param[in] PortMultiplier The timeout value of stop. + @param[in] AtapiCommand The atapi command will be used for the + transfer. + @param[in] AtapiCommandLength The length of the atapi command. + @param[in] Read The transfer direction. + @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. + @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. + @param[in, out] MemoryAddr The pointer to the data buffer. + @param[in] DataCount The data count to be transferred. + @param[in] Timeout The timeout value of non data transfer. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. + + @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs. + @retval EFI_TIMEOUT The operation is time out. + @retval EFI_UNSUPPORTED The device is not ready for transfer. + @retval EFI_SUCCESS The DMA data transfer executes successfully. + +**/ +EFI_STATUS +EFIAPI +AhciDmaTransfer ( + IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance, + IN EFI_AHCI_REGISTERS *AhciRegisters, + IN UINT8 Port, + IN UINT8 PortMultiplier, + IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL, + IN UINT8 AtapiCommandLength, + IN BOOLEAN Read, + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, + IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, + IN OUT VOID *MemoryAddr, + IN UINTN DataCount, + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task + ); + +/** + Start a PIO data transfer on specific port. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS. + @param[in] Port The number of port. + @param[in] PortMultiplier The timeout value of stop. + @param[in] AtapiCommand The atapi command will be used for the + transfer. + @param[in] AtapiCommandLength The length of the atapi command. + @param[in] Read The transfer direction. + @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. + @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. + @param[in, out] MemoryAddr The pointer to the data buffer. + @param[in] DataCount The data count to be transferred. + @param[in] Timeout The timeout value of non data transfer. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. + + @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs. + @retval EFI_TIMEOUT The operation is time out. + @retval EFI_UNSUPPORTED The device is not ready for transfer. + @retval EFI_SUCCESS The PIO data transfer executes successfully. + +**/ +EFI_STATUS +EFIAPI +AhciPioTransfer ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_AHCI_REGISTERS *AhciRegisters, + IN UINT8 Port, + IN UINT8 PortMultiplier, + IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL, + IN UINT8 AtapiCommandLength, + IN BOOLEAN Read, + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, + IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, + IN OUT VOID *MemoryAddr, + IN UINT32 DataCount, + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task + ); + +/** + Send ATA command into device with NON_DATA protocol + + @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE + data structure. + @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. + @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data + structure. + @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. + @param[in] Timeout The time to complete the command. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. + + @retval EFI_SUCCESS Reading succeed + @retval EFI_ABORTED Command failed + @retval EFI_DEVICE_ERROR Device status error. + +**/ +EFI_STATUS +EFIAPI +AtaNonDataCommandIn ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_IDE_REGISTERS *IdeRegisters, + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, + IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task + ); + +/** + Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt). + + @param[in] Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data + structure. + @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. + @param[in] Read Flag used to determine the data transfer + direction. Read equals 1, means data transferred + from device to host;Read equals 0, means data + transferred from host to device. + @param[in] DataBuffer A pointer to the source buffer for the data. + @param[in] DataLength The length of the data. + @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. + @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. + @param[in] Timeout The time to complete the command. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. + + @retval EFI_SUCCESS the operation is successful. + @retval EFI_OUT_OF_RESOURCES Build PRD table failed + @retval EFI_UNSUPPORTED Unknown channel or operations command + @retval EFI_DEVICE_ERROR Ata command execute failed + +**/ +EFI_STATUS +EFIAPI +AtaUdmaInOut ( + IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance, + IN EFI_IDE_REGISTERS *IdeRegisters, + IN BOOLEAN Read, + IN VOID *DataBuffer, + IN UINT64 DataLength, + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, + IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task + ); + +/** + This function is used to send out ATA commands conforms to the PIO Data In Protocol. + + @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data + structure. + @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. + @param[in, out] Buffer A pointer to the source buffer for the data. + @param[in] ByteCount The length of the data. + @param[in] Read Flag used to determine the data transfer direction. + Read equals 1, means data transferred from device + to host;Read equals 0, means data transferred + from host to device. + @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. + @param[in] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. + @param[in] Timeout The time to complete the command. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. + + @retval EFI_SUCCESS send out the ATA command and device send required data successfully. + @retval EFI_DEVICE_ERROR command sent failed. + +**/ +EFI_STATUS +EFIAPI +AtaPioDataInOut ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_IDE_REGISTERS *IdeRegisters, + IN OUT VOID *Buffer, + IN UINT64 ByteCount, + IN BOOLEAN Read, + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, + IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task + ); + #endif diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c index 50b95a6713..915e4bb296 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c @@ -1,7 +1,7 @@ /** @file Header file for AHCI mode of ATA host controller. - Copyright (c) 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2011, 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 @@ -1123,16 +1123,20 @@ AtaIssueCommand ( /** This function is used to send out ATA commands conforms to the PIO Data In Protocol. - @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure. - @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. - @param Buffer A pointer to the source buffer for the data. - @param ByteCount The length of the data. - @param Read Flag used to determine the data transfer direction. - Read equals 1, means data transferred from device to host; - Read equals 0, means data transferred from host to device. - @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. - @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. - @param Timeout The time to complete the command. + @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data + structure. + @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. + @param[in, out] Buffer A pointer to the source buffer for the data. + @param[in] ByteCount The length of the data. + @param[in] Read Flag used to determine the data transfer direction. + Read equals 1, means data transferred from device + to host;Read equals 0, means data transferred + from host to device. + @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. + @param[in] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. + @param[in] Timeout The time to complete the command. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. @retval EFI_SUCCESS send out the ATA command and device send required data successfully. @retval EFI_DEVICE_ERROR command sent failed. @@ -1148,7 +1152,8 @@ AtaPioDataInOut ( IN BOOLEAN Read, IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN UINT64 Timeout + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task ) { UINTN WordCount; @@ -1248,17 +1253,24 @@ Exit: // DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock); + // + // Not support the Non-blocking now,just do the blocking process. + // return Status; } /** Send ATA command into device with NON_DATA protocol - @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure. - @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. - @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. - @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. - @param Timeout The time to complete the command. + @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE + data structure. + @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. + @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data + structure. + @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. + @param[in] Timeout The time to complete the command. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. @retval EFI_SUCCESS Reading succeed @retval EFI_ABORTED Command failed @@ -1272,7 +1284,8 @@ AtaNonDataCommandIn ( IN EFI_IDE_REGISTERS *IdeRegisters, IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN UINT64 Timeout + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task ) { EFI_STATUS Status; @@ -1310,24 +1323,123 @@ Exit: // Dump All Ide registers to ATA_STATUS_BLOCK // DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock); + + // + // Not support the Non-blocking now,just do the blocking process. + // + return Status; +} + +/** + Wait for memory to be set. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] PortNum The IDE Port number. + + @retval EFI_DEVICE_ERROR The memory is not set. + @retval EFI_TIMEOUT The memory setting is time out. + @retval EFI_SUCCESS The memory is correct set. + +**/ +EFI_STATUS +AtaUdmStatusWait ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT16 PortNum + ) +{ + UINT8 RegisterValue; + EFI_STATUS Status; + UINT64 Timeout; + + Timeout = 2000; + + while (TRUE) { + RegisterValue = IdeReadPortB (PciIo, PortNum); + + if (((RegisterValue & BMIS_ERROR) != 0) || (Timeout == 0)) { + DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n")); + Status = EFI_DEVICE_ERROR; + break; + } + + if ((RegisterValue & BMIS_INTERRUPT) != 0) { + Status = EFI_SUCCESS; + DEBUG ((DEBUG_INFO, "Task->RetryTimes = %x\n", Timeout)); + break; + } + // + // Stall for 1 milliseconds. + // + MicroSecondDelay (1000); + Timeout--; + } return Status; } +/** + Check if the memory to be set. + + @param[in] PciIo The PCI IO protocol instance. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. + @param[in] PortForBit The bit to be checked. + + @retval EFI_DEVICE_ERROR The memory setting met a issue. + @retval EFI_NOT_READY The memory is not set. + @retval EFI_TIMEOUT The memory setting is time out. + @retval EFI_SUCCESS The memory is correct set. + +**/ +EFI_STATUS +AtaUdmStatusCheck ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN ATA_NONBLOCK_TASK *Task, + IN UINT16 PortForBit + ) +{ + UINT8 RegisterValue; + + Task->RetryTimes--; + RegisterValue = IdeReadPortB(PciIo, PortForBit); + + if ((RegisterValue & BMIS_ERROR) != 0) { + DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n")); + return EFI_DEVICE_ERROR; + } + + if ((RegisterValue & BMIS_INTERRUPT) != 0) { + DEBUG ((DEBUG_INFO, "Task->RetryTimes = %x\n", Task->RetryTimes)); + return EFI_SUCCESS; + } + + if (Task->RetryTimes == 0) { + return EFI_TIMEOUT; + } else { + // + // The memory is not set. + // + return EFI_NOT_READY; + } +} /** Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt). - @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure. - @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. - @param Read Flag used to determine the data transfer direction. - Read equals 1, means data transferred from device to host; - Read equals 0, means data transferred from host to device. - @param DataBuffer A pointer to the source buffer for the data. - @param DataLength The length of the data. - @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. - @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. - @param Timeout The time to complete the command. + @param[in] Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data + structure. + @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. + @param[in] Read Flag used to determine the data transfer + direction. Read equals 1, means data transferred + from device to host;Read equals 0, means data + transferred from host to device. + @param[in] DataBuffer A pointer to the source buffer for the data. + @param[in] DataLength The length of the data. + @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. + @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. + @param[in] Timeout The time to complete the command. + @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK + used by non-blocking mode. @retval EFI_SUCCESS the operation is successful. @retval EFI_OUT_OF_RESOURCES Build PRD table failed @@ -1338,14 +1450,15 @@ Exit: EFI_STATUS EFIAPI AtaUdmaInOut ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN EFI_IDE_REGISTERS *IdeRegisters, - IN BOOLEAN Read, - IN VOID *DataBuffer, - IN UINT64 DataLength, - IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, - IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN UINT64 Timeout + IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance, + IN EFI_IDE_REGISTERS *IdeRegisters, + IN BOOLEAN Read, + IN VOID *DataBuffer, + IN UINT64 DataLength, + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, + IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, + IN UINT64 Timeout, + IN ATA_NONBLOCK_TASK *Task ) { EFI_STATUS Status; @@ -1353,18 +1466,16 @@ AtaUdmaInOut ( UINT16 IoPortForBmis; UINT16 IoPortForBmid; - UINT8 RegisterValue; - - EFI_ATA_DMA_PRD *PrdBaseAddr; - UINTN PrdTableNum; UINTN PrdTableSize; EFI_PHYSICAL_ADDRESS PrdTableMapAddr; VOID *PrdTableMap; + EFI_ATA_DMA_PRD *PrdBaseAddr; + UINTN PrdTableNum; + UINT8 RegisterValue; UINTN PageCount; UINTN ByteCount; UINTN ByteRemaining; - UINT8 DeviceControl; VOID *BufferMap; @@ -1373,14 +1484,36 @@ AtaUdmaInOut ( UINT8 DeviceHead; UINT8 AtaCommand; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_TPL OldTpl; - Status = EFI_SUCCESS; - PrdBaseAddr = NULL; + + Status = EFI_SUCCESS; + PrdBaseAddr = NULL; + PrdTableMap = NULL; + BufferMap = NULL; + PageCount = 0; + PciIo = Instance->PciIo; if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) { return EFI_INVALID_PARAMETER; } + // + // Before starting the Blocking BlockIO operation, push to finish all non-blocking + // BlockIO tasks. + // Delay 1ms to simulate the blocking time out checking. + // + while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + AsyncNonBlockingTransferRoutine (NULL, Instance); + gBS->RestoreTPL (OldTpl); + // + // Stall for 1 milliseconds. + // + MicroSecondDelay (1000); + } + // // The data buffer should be even alignment // @@ -1389,234 +1522,260 @@ AtaUdmaInOut ( } // - // Calculate the number of PRD entry. - // Every entry in PRD table can specify a 64K memory region. + // Set relevant IO Port address. // - PrdTableNum = (UINTN)(RShiftU64(DataLength, 16) + 1); + IoPortForBmic = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET); + IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET); + IoPortForBmid = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMID_OFFSET); // - // Make sure that the memory region of PRD table is not cross 64K boundary - // - PrdTableSize = PrdTableNum * sizeof (EFI_ATA_DMA_PRD); - if (PrdTableSize > 0x10000) { - return EFI_INVALID_PARAMETER; - } + // For Blocking mode, start the command. + // For non-blocking mode, when the command is not started, start it, otherwise + // go to check the status. + // + if (((Task != NULL) && (!Task->IsStart)) || (Task == NULL)) { + // + // Calculate the number of PRD entry. + // Every entry in PRD table can specify a 64K memory region. + // + PrdTableNum = (UINTN)(RShiftU64(DataLength, 16) + 1); - // - // Allocate buffer for PRD table initialization. - // - PageCount = EFI_SIZE_TO_PAGES (PrdTableSize); - Status = PciIo->AllocateBuffer ( - PciIo, - AllocateAnyPages, - EfiBootServicesData, - PageCount, - (VOID **)&PrdBaseAddr, - 0 - ); - if (EFI_ERROR (Status)) { - return EFI_OUT_OF_RESOURCES; - } + // + // Make sure that the memory region of PRD table is not cross 64K boundary + // + PrdTableSize = PrdTableNum * sizeof (EFI_ATA_DMA_PRD); + if (PrdTableSize > 0x10000) { + return EFI_INVALID_PARAMETER; + } - ByteCount = EFI_PAGES_TO_SIZE (PageCount); - Status = PciIo->Map ( - PciIo, - EfiPciIoOperationBusMasterCommonBuffer, - PrdBaseAddr, - &ByteCount, - &PrdTableMapAddr, - &PrdTableMap - ); - if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) { - // - // If the data length actually mapped is not equal to the requested amount, - // it means the DMA operation may be broken into several discontinuous smaller chunks. - // Can't handle this case. - // - PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr); - return EFI_OUT_OF_RESOURCES; - } + // + // Allocate buffer for PRD table initialization. + // + PageCount = EFI_SIZE_TO_PAGES (PrdTableSize); + Status = PciIo->AllocateBuffer ( + PciIo, + AllocateAnyPages, + EfiBootServicesData, + PageCount, + (VOID **)&PrdBaseAddr, + 0 + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } - ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount); + ByteCount = EFI_PAGES_TO_SIZE (PageCount); + Status = PciIo->Map ( + PciIo, + EfiPciIoOperationBusMasterCommonBuffer, + PrdBaseAddr, + &ByteCount, + &PrdTableMapAddr, + &PrdTableMap + ); + if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) { + // + // If the data length actually mapped is not equal to the requested amount, + // it means the DMA operation may be broken into several discontinuous smaller chunks. + // Can't handle this case. + // + PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr); + return EFI_OUT_OF_RESOURCES; + } - // - // Map the host address of DataBuffer to DMA master address. - // - if (Read) { - PciIoOperation = EfiPciIoOperationBusMasterWrite; - } else { - PciIoOperation = EfiPciIoOperationBusMasterRead; - } + ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount); - ByteCount = (UINTN)DataLength; - Status = PciIo->Map ( - PciIo, - PciIoOperation, - DataBuffer, - &ByteCount, - &BufferMapAddress, - &BufferMap - ); - if (EFI_ERROR (Status) || (ByteCount != DataLength)) { - PciIo->Unmap (PciIo, PrdTableMap); - PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr); - return EFI_OUT_OF_RESOURCES; - } + // + // Map the host address of DataBuffer to DMA master address. + // + if (Read) { + PciIoOperation = EfiPciIoOperationBusMasterWrite; + } else { + PciIoOperation = EfiPciIoOperationBusMasterRead; + } - // - // According to Ata spec, it requires the buffer address and size to be even. - // - ASSERT ((BufferMapAddress & 0x1) == 0); - ASSERT ((ByteCount & 0x1) == 0); + ByteCount = (UINTN)DataLength; + Status = PciIo->Map ( + PciIo, + PciIoOperation, + DataBuffer, + &ByteCount, + &BufferMapAddress, + &BufferMap + ); + if (EFI_ERROR (Status) || (ByteCount != DataLength)) { + PciIo->Unmap (PciIo, PrdTableMap); + PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr); + return EFI_OUT_OF_RESOURCES; + } + + // + // According to Ata spec, it requires the buffer address and size to be even. + // + ASSERT ((BufferMapAddress & 0x1) == 0); + ASSERT ((ByteCount & 0x1) == 0); + + // + // Fill the PRD table with appropriate bus master address of data buffer and data length. + // + ByteRemaining = ByteCount; + while (ByteRemaining != 0) { + if (ByteRemaining <= 0x10000) { + PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress); + PrdBaseAddr->ByteCount = (UINT16) ByteRemaining; + PrdBaseAddr->EndOfTable = 0x8000; + break; + } - // - // Fill the PRD table with appropriate bus master address of data buffer and data length. - // - ByteRemaining = ByteCount; - while (ByteRemaining != 0) { - if (ByteRemaining <= 0x10000) { PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress); - PrdBaseAddr->ByteCount = (UINT16) ByteRemaining; - PrdBaseAddr->EndOfTable = 0x8000; - break; - } + PrdBaseAddr->ByteCount = (UINT16) 0x0; - PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress); - PrdBaseAddr->ByteCount = (UINT16) 0x0; + ByteRemaining -= 0x10000; + BufferMapAddress += 0x10000; + PrdBaseAddr++; + } - ByteRemaining -= 0x10000; - BufferMapAddress += 0x10000; - PrdBaseAddr++; - } + // + // Start to enable the DMA operation + // + DeviceHead = AtaCommandBlock->AtaDeviceHead; + AtaCommand = AtaCommandBlock->AtaCommand; - // - // Start to enable the DMA operation - // - DeviceHead = AtaCommandBlock->AtaDeviceHead; - AtaCommand = AtaCommandBlock->AtaCommand; + IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead)); - IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead)); + // + // Enable interrupt to support UDMA + // + DeviceControl = 0; + IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl); - // - // Enable interrupt to support UDMA - // - DeviceControl = 0; - IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl); + // + // Read BMIS register and clear ERROR and INTR bit + // + RegisterValue = IdeReadPortB(PciIo, IoPortForBmis); + RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); + IdeWritePortB(PciIo, IoPortForBmis, RegisterValue); - IoPortForBmic = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET); - IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET); - IoPortForBmid = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMID_OFFSET); + // + // Set the base address to BMID register + // + IdeWritePortDW (PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr); - // - // Read BMIS register and clear ERROR and INTR bit - // - RegisterValue = IdeReadPortB(PciIo, IoPortForBmis); - RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); - IdeWritePortB(PciIo, IoPortForBmis, RegisterValue); + // + // Set BMIC register to identify the operation direction + // + RegisterValue = IdeReadPortB(PciIo, IoPortForBmic); + if (Read) { + RegisterValue |= BMIC_NREAD; + } else { + RegisterValue &= ~((UINT8) BMIC_NREAD); + } + IdeWritePortB (PciIo, IoPortForBmic, RegisterValue); - // - // Set the base address to BMID register - // - IdeWritePortDW(PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr); + // + // Issue ATA command + // + Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout); - // - // Set BMIC register to identify the operation direction - // - RegisterValue = IdeReadPortB(PciIo, IoPortForBmic); - if (Read) { - RegisterValue |= BMIC_NREAD; - } else { - RegisterValue &= ~((UINT8) BMIC_NREAD); - } - IdeWritePortB(PciIo, IoPortForBmic, RegisterValue); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } - // - // Issue ATA command - // - Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout); + // + // Set START bit of BMIC register + // + RegisterValue = IdeReadPortB(PciIo, IoPortForBmic); + RegisterValue |= BMIC_START; + IdeWritePortB(PciIo, IoPortForBmic, RegisterValue); - if (EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - goto Exit; + if (Task != NULL) { + // + // Max transfer number of sectors for one command is 65536(32Mbyte), + // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps). + // So set the variable Count to 2000, for about 2 second Timeout time. + // + Task->RetryTimes = 2000; + Task->Map = BufferMap; + Task->TableMap = PrdTableMap; + Task->MapBaseAddress = PrdBaseAddr; + Task->PageCount = PageCount; + Task->IsStart = TRUE; + } } - // - // Set START bit of BMIC register - // - RegisterValue = IdeReadPortB(PciIo, IoPortForBmic); - RegisterValue |= BMIC_START; - IdeWritePortB(PciIo, IoPortForBmic, RegisterValue); - // // Check the INTERRUPT and ERROR bit of BMIS // Max transfer number of sectors for one command is 65536(32Mbyte), // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps). // So set the variable Count to 2000, for about 2 second Timeout time. // - Timeout = 2000; - while (TRUE) { - RegisterValue = IdeReadPortB(PciIo, IoPortForBmis); - - if (((RegisterValue & BMIS_ERROR) != 0) || (Timeout == 0)) { - DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n")); - Status = EFI_DEVICE_ERROR; - break; - } - - if ((RegisterValue & BMIS_INTERRUPT) != 0) { - Status = EFI_SUCCESS; - break; - } - // - // Stall for 1 milliseconds. - // - MicroSecondDelay (1000); - Timeout--; + if (Task != NULL) { + Status = AtaUdmStatusCheck (PciIo, Task, IoPortForBmis); + } else { + Status = AtaUdmStatusWait (PciIo, IoPortForBmis); } // - // Read BMIS register and clear ERROR and INTR bit + // For blocking mode, clear registers and free buffers. + // For non blocking mode, when the related registers have been set or time + // out, or a error has been happened, it needs to clear the register and free + // buffer. // - RegisterValue = IdeReadPortB(PciIo, IoPortForBmis); - RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); - IdeWritePortB(PciIo, IoPortForBmis, RegisterValue); + if ((Task == NULL) || Status != EFI_NOT_READY) { + // + // Read BMIS register and clear ERROR and INTR bit + // + RegisterValue = IdeReadPortB (PciIo, IoPortForBmis); + RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); + IdeWritePortB (PciIo, IoPortForBmis, RegisterValue); - // - // Read Status Register of IDE device to clear interrupt - // - RegisterValue = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus); + // + // Read Status Register of IDE device to clear interrupt + // + RegisterValue = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus); - // - // Clear START bit of BMIC register - // - RegisterValue = IdeReadPortB(PciIo, IoPortForBmic); - RegisterValue &= ~((UINT8) BMIC_START); - IdeWritePortB(PciIo, IoPortForBmic, RegisterValue); + // + // Clear START bit of BMIC register + // + RegisterValue = IdeReadPortB(PciIo, IoPortForBmic); + RegisterValue &= ~((UINT8) BMIC_START); + IdeWritePortB (PciIo, IoPortForBmic, RegisterValue); - // - // Disable interrupt of Select device - // - DeviceControl = IdeReadPortB (PciIo, IdeRegisters->AltOrDev); - DeviceControl |= ATA_CTLREG_IEN_L; - IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl); - // - // Stall for 10 milliseconds. - // - MicroSecondDelay (10000); + // + // Disable interrupt of Select device + // + DeviceControl = IdeReadPortB (PciIo, IdeRegisters->AltOrDev); + DeviceControl |= ATA_CTLREG_IEN_L; + IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl); + // + // Stall for 10 milliseconds. + // + MicroSecondDelay (10000); + + } Exit: // // Free all allocated resource // - PciIo->Unmap (PciIo, PrdTableMap); - PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr); - PciIo->Unmap (PciIo, BufferMap); - - // - // Dump All Ide registers to ATA_STATUS_BLOCK - // - DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock); + if ((Task == NULL) || Status != EFI_NOT_READY) { + if (Task != NULL) { + PciIo->Unmap (PciIo, Task->TableMap); + PciIo->FreeBuffer (PciIo, Task->PageCount, Task->MapBaseAddress); + PciIo->Unmap (PciIo, Task->Map); + } else { + PciIo->Unmap (PciIo, PrdTableMap); + PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr); + PciIo->Unmap (PciIo, BufferMap); + } + // + // Dump All Ide registers to ATA_STATUS_BLOCK + // + DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock); + } + return Status; } @@ -2021,7 +2180,8 @@ SetDeviceTransferMode ( &Instance->IdeRegisters[Channel], &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); return Status; @@ -2069,7 +2229,8 @@ SetDriveParameters ( &Instance->IdeRegisters[Channel], &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); // @@ -2084,7 +2245,8 @@ SetDriveParameters ( &Instance->IdeRegisters[Channel], &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); return Status; @@ -2132,7 +2294,8 @@ IdeAtaSmartReturnStatusCheck ( &Instance->IdeRegisters[Channel], &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); if (EFI_ERROR (Status)) { @@ -2212,7 +2375,8 @@ IdeAtaSmartSupport ( &Instance->IdeRegisters[Channel], &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); if (!EFI_ERROR (Status)) { @@ -2233,7 +2397,8 @@ IdeAtaSmartSupport ( &Instance->IdeRegisters[Channel], &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); if (!EFI_ERROR (Status)) { Status = IdeAtaSmartReturnStatusCheck ( @@ -2254,6 +2419,7 @@ IdeAtaSmartSupport ( return ; } + /** Sends out an ATA Identify Command to the specified device. @@ -2274,6 +2440,7 @@ IdeAtaSmartSupport ( @retval EFI_SUCCESS Identify ATA device successfully. @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device. @retval EFI_OUT_OF_RESOURCES Allocate memory failed. + **/ EFI_STATUS EFIAPI @@ -2286,10 +2453,10 @@ AtaIdentify ( ) { EFI_STATUS Status; - EFI_ATA_COMMAND_BLOCK AtaCommandBlock; + EFI_ATA_COMMAND_BLOCK AtaCommandBlock; ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK)); - + AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE; AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4); @@ -2301,7 +2468,8 @@ AtaIdentify ( TRUE, &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); return Status; @@ -2368,7 +2536,8 @@ AtaIdentifyPacket ( TRUE, &AtaCommandBlock, AtaStatusBlock, - ATA_ATAPI_TIMEOUT + ATA_ATAPI_TIMEOUT, + NULL ); return Status; @@ -2425,7 +2594,7 @@ DetectAndConfigIdeDevice ( IdeInit = Instance->IdeControllerInit; PciIo = Instance->PciIo; - for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) { + for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) { // // Send ATA Device Execut Diagnostic command. // This command should work no matter DRDY is ready or not @@ -2483,7 +2652,7 @@ DetectAndConfigIdeDevice ( if (EFI_ERROR (Status)) { DeviceType = EfiIdeHarddisk; Status = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL); - } + } } if (EFI_ERROR (Status)) { @@ -2491,12 +2660,11 @@ DetectAndConfigIdeDevice ( // No device is found at this port // continue; - } - + } + DEBUG ((EFI_D_INFO, "[%a] channel [%a] [%a] device\n", (IdeChannel == 1) ? "secondary" : "primary ", (IdeDevice == 1) ? "slave " : "master", DeviceType == EfiIdeCdrom ? "cdrom " : "harddisk")); - // // If the device is a hard disk, then try to enable S.M.A.R.T feature // @@ -2548,7 +2716,7 @@ DetectAndConfigIdeDevice ( continue; } } - + // // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't // be set together. Only one DMA mode can be set to a device. If setting @@ -2559,7 +2727,7 @@ DetectAndConfigIdeDevice ( TransferMode.ModeCategory = EFI_ATA_MODE_UDMA; TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode); Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL); - + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status)); continue; @@ -2568,13 +2736,13 @@ DetectAndConfigIdeDevice ( TransferMode.ModeCategory = EFI_ATA_MODE_MDMA; TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode; Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL); - + if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status)); continue; } } - + // // Set Parameters for the device: // 1) Init @@ -2587,10 +2755,10 @@ DetectAndConfigIdeDevice ( DriveParameters.Sector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->sectors_per_track; DriveParameters.Heads = (UINT8) (((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->heads - 1); DriveParameters.MultipleSector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->multi_sector_cmd_max_sct_cnt; - + Status = SetDriveParameters (Instance, IdeChannel, IdeDevice, &DriveParameters, NULL); } - + // // Set IDE controller Timing Blocks in the PCI Configuration Space // diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h index b9c58c6341..67fff64658 100644 --- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h +++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h @@ -1,7 +1,7 @@ /** @file Header file for IDE mode of ATA host controller. - Copyright (c) 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2010 - 2011, 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 @@ -200,94 +200,5 @@ AtaPacketCommandExecute ( IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet ); -/** - Send ATA command into device with NON_DATA protocol - - @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure. - @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. - @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. - @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. - @param Timeout The time to complete the command. - - @retval EFI_SUCCESS Reading succeed - @retval EFI_ABORTED Command failed - @retval EFI_DEVICE_ERROR Device status error. - -**/ -EFI_STATUS -EFIAPI -AtaNonDataCommandIn ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN EFI_IDE_REGISTERS *IdeRegisters, - IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, - IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN UINT64 Timeout - ); - -/** - Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt). - - @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure. - @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. - @param Read Flag used to determine the data transfer direction. - Read equals 1, means data transferred from device to host; - Read equals 0, means data transferred from host to device. - @param DataBuffer A pointer to the source buffer for the data. - @param DataLength The length of the data. - @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. - @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. - @param Timeout The time to complete the command. - - @retval EFI_SUCCESS the operation is successful. - @retval EFI_OUT_OF_RESOURCES Build PRD table failed - @retval EFI_UNSUPPORTED Unknown channel or operations command - @retval EFI_DEVICE_ERROR Ata command execute failed - -**/ -EFI_STATUS -EFIAPI -AtaUdmaInOut ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN EFI_IDE_REGISTERS *IdeRegisters, - IN BOOLEAN Read, - IN VOID *DataBuffer, - IN UINT64 DataLength, - IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, - IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN UINT64 Timeout - ); - -/** - This function is used to send out ATA commands conforms to the PIO Data In Protocol. - - @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure. - @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. - @param Buffer A pointer to the source buffer for the data. - @param ByteCount The length of the data. - @param Read Flag used to determine the data transfer direction. - Read equals 1, means data transferred from device to host; - Read equals 0, means data transferred from host to device. - @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. - @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. - @param Timeout The time to complete the command. - - @retval EFI_SUCCESS send out the ATA command and device send required data successfully. - @retval EFI_DEVICE_ERROR command sent failed. - -**/ -EFI_STATUS -EFIAPI -AtaPioDataInOut ( - IN EFI_PCI_IO_PROTOCOL *PciIo, - IN EFI_IDE_REGISTERS *IdeRegisters, - IN OUT VOID *Buffer, - IN UINT64 ByteCount, - IN BOOLEAN Read, - IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, - IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN UINT64 Timeout - ); - - #endif diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c index a3c0670c98..437eca725c 100644 --- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c +++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c @@ -44,6 +44,13 @@ ATA_DEVICE gAtaDeviceTemplate = { AtaBlockIoWriteBlocks, AtaBlockIoFlushBlocks }, + { // BlockIo2 + NULL, + AtaBlockIoResetEx, + AtaBlockIoReadBlocksEx, + AtaBlockIoWriteBlocksEx, + AtaBlockIoFlushBlocksEx + }, { // BlockMedia 0, // MediaId FALSE, // RemovableMedia @@ -75,7 +82,8 @@ ATA_DEVICE gAtaDeviceTemplate = { FALSE, // Lba48Bit NULL, // IdentifyData NULL, // ControllerNameTable - {L'\0', } // ModelName + {L'\0', }, // ModelName + {NULL, NULL} // AtaTaskList }; /** @@ -135,12 +143,34 @@ ReleaseAtaResources ( IN ATA_DEVICE *AtaDevice ) { + ATA_BUS_ASYN_TASK *Task; + LIST_ENTRY *Entry; + LIST_ENTRY *DelEntry; + EFI_TPL OldTpl; + FreeUnicodeStringTable (AtaDevice->ControllerNameTable); FreeAlignedBuffer (AtaDevice->Asb, sizeof (*AtaDevice->Asb)); FreeAlignedBuffer (AtaDevice->IdentifyData, sizeof (*AtaDevice->IdentifyData)); if (AtaDevice->DevicePath != NULL) { FreePool (AtaDevice->DevicePath); } + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + if (!IsListEmpty (&AtaDevice->AtaTaskList)) { + // + // Free the Subtask list. + // + for(Entry = (&AtaDevice->AtaTaskList)->ForwardLink; + Entry != (&AtaDevice->AtaTaskList); + ) { + DelEntry = Entry; + Entry = Entry->ForwardLink; + Task = ATA_AYNS_TASK_FROM_ENTRY (DelEntry); + + RemoveEntryList (DelEntry); + FreeAtaSubTask (Task); + } + } + gBS->RestoreTPL (OldTpl); FreePool (AtaDevice); } @@ -218,10 +248,11 @@ RegisterAtaDevice ( // // Initializes ATA device structures and allocates the required buffer. // - AtaDevice->BlockIo.Media = &AtaDevice->BlockMedia; - AtaDevice->AtaBusDriverData = AtaBusDriverData; - AtaDevice->DevicePath = DevicePath; - AtaDevice->Port = Port; + AtaDevice->BlockIo.Media = &AtaDevice->BlockMedia; + AtaDevice->BlockIo2.Media = &AtaDevice->BlockMedia; + AtaDevice->AtaBusDriverData = AtaBusDriverData; + AtaDevice->DevicePath = DevicePath; + AtaDevice->Port = Port; AtaDevice->PortMultiplierPort = PortMultiplierPort; AtaDevice->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->Asb)); if (AtaDevice->Asb == NULL) { @@ -234,6 +265,11 @@ RegisterAtaDevice ( goto Done; } + // + // Initial Ata Task List + // + InitializeListHead (&AtaDevice->AtaTaskList); + // // Try to identify the ATA device via the ATA pass through command. // @@ -241,7 +277,7 @@ RegisterAtaDevice ( if (EFI_ERROR (Status)) { goto Done; } - + // // Build controller name for Component Name (2) protocol. // @@ -281,6 +317,8 @@ RegisterAtaDevice ( AtaDevice->DevicePath, &gEfiBlockIoProtocolGuid, &AtaDevice->BlockIo, + &gEfiBlockIo2ProtocolGuid, + &AtaDevice->BlockIo2, &gEfiDiskInfoProtocolGuid, &AtaDevice->DiskInfo, NULL @@ -334,8 +372,11 @@ UnregisterAtaDevice ( { EFI_STATUS Status; EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_BLOCK_IO2_PROTOCOL *BlockIo2; ATA_DEVICE *AtaDevice; EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; + BlockIo2 = NULL; + BlockIo = NULL; Status = gBS->OpenProtocol ( Handle, @@ -346,10 +387,30 @@ UnregisterAtaDevice ( EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { - return Status; + // + // Locate BlockIo2 protocol + // + Status = gBS->OpenProtocol ( + Handle, + &gEfiBlockIo2ProtocolGuid, + (VOID **) &BlockIo2, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } } - AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (BlockIo); + // + // Get AtaDevice data. + // + if (BlockIo != NULL) { + AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (BlockIo); + } else { + AtaDevice = ATA_DEVICE_FROM_BLOCK_IO2 (BlockIo2); + } // // Close the child handle @@ -361,12 +422,18 @@ UnregisterAtaDevice ( Handle ); + // + // The Ata Bus driver installs the BlockIo and BlockIo2 in the DriverBindingStart(). + // Here should uninstall both of them. + // Status = gBS->UninstallMultipleProtocolInterfaces ( Handle, &gEfiDevicePathProtocolGuid, AtaDevice->DevicePath, &gEfiBlockIoProtocolGuid, &AtaDevice->BlockIo, + &gEfiBlockIo2ProtocolGuid, + &AtaDevice->BlockIo2, &gEfiDiskInfoProtocolGuid, &AtaDevice->DiskInfo, NULL @@ -385,7 +452,6 @@ UnregisterAtaDevice ( } ReleaseAtaResources (AtaDevice); - return Status; } @@ -446,7 +512,7 @@ AtaBusDriverBindingSupported ( EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; UINT16 Port; UINT16 PortMultiplierPort; - + // // Test EFI_ATA_PASS_THRU_PROTOCOL on controller handle. // @@ -522,7 +588,7 @@ AtaBusDriverBindingSupported ( @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. + 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 @@ -589,7 +655,7 @@ AtaBusDriverBindingStart ( } AtaBusDriverData->AtaPassThru = AtaPassThru; - AtaBusDriverData->Controller = Controller; + AtaBusDriverData->Controller = Controller; AtaBusDriverData->ParentDevicePath = ParentDevicePath; AtaBusDriverData->DriverBindingHandle = This->DriverBindingHandle; @@ -628,7 +694,7 @@ AtaBusDriverBindingStart ( // break; } - + PortMultiplierPort = 0xFFFF; while (TRUE) { Status = AtaPassThru->GetNextDevice (AtaPassThru, Port, &PortMultiplierPort); @@ -649,7 +715,7 @@ AtaBusDriverBindingStart ( Status = RegisterAtaDevice (AtaBusDriverData,Port, PortMultiplierPort); } } - + return Status; ErrorExit: @@ -789,7 +855,7 @@ AtaBlockIoReset ( AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This); - Status = ResetAtaDevice (AtaDevice); + Status = ResetAtaDevice (AtaDevice); if (EFI_ERROR (Status)) { Status = EFI_DEVICE_ERROR; @@ -803,13 +869,18 @@ AtaBlockIoReset ( /** 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. - @param IsWrite Indicates whether it is a write operation. + @param[in] This Indicates a pointer to the calling context. Either be + block I/O or block I/O2. + @param[in] MediaId The media ID that the read/write request is for. + @param[in] Lba The starting logical block address to be read/written. + The caller is responsible for reading/writing to only + legitimate locations. + @param[in, out] Token A pointer to the token associated with the transaction. + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[out] Buffer A pointer to the destination/source buffer for the data. + @param[in] IsBlockIo2 Indicate the calling is from BlockIO or BlockIO2. TURE is + from BlockIO2, FALSE is for BlockIO. + @param[in] IsWrite Indicates whether it is a write operation. @retval EFI_SUCCESS The data was read/written correctly to the device. @retval EFI_WRITE_PROTECTED The device can not be read/written to. @@ -823,12 +894,14 @@ AtaBlockIoReset ( **/ 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 + IN VOID *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + OUT VOID *Buffer, + IN BOOLEAN IsBlockIo2, + IN BOOLEAN IsWrite ) { ATA_DEVICE *AtaDevice; @@ -839,21 +912,28 @@ BlockIoReadWrite ( UINTN NumberOfBlocks; UINTN IoAlign; - // - // Check parameters. - // - Media = This->Media; + if (IsBlockIo2) { + Media = ((EFI_BLOCK_IO2_PROTOCOL *) This)->Media; + AtaDevice = ATA_DEVICE_FROM_BLOCK_IO2 (This); + } else { + Media = ((EFI_BLOCK_IO_PROTOCOL *) This)->Media; + AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This); + } + if (MediaId != Media->MediaId) { return EFI_MEDIA_CHANGED; } + // + // Check parameters. + // if (Buffer == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize == 0) { return EFI_SUCCESS; - } + } BlockSize = Media->BlockSize; if ((BufferSize % BlockSize) != 0) { @@ -871,13 +951,11 @@ BlockIoReadWrite ( } 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); + Status = AccessAtaDevice (AtaDevice, Buffer, Lba, NumberOfBlocks, IsWrite, Token); gBS->RestoreTPL (OldTpl); @@ -914,7 +992,7 @@ AtaBlockIoReadBlocks ( OUT VOID *Buffer ) { - return BlockIoReadWrite (This, MediaId, Lba, BufferSize, Buffer, FALSE); + return BlockIoReadWrite ((VOID *) This, MediaId, Lba, NULL, BufferSize, Buffer, FALSE, FALSE); } @@ -948,7 +1026,7 @@ AtaBlockIoWriteBlocks ( IN VOID *Buffer ) { - return BlockIoReadWrite (This, MediaId, Lba, BufferSize, Buffer, TRUE); + return BlockIoReadWrite ((VOID *) This, MediaId, Lba, NULL, BufferSize, Buffer, FALSE, TRUE); } @@ -974,7 +1052,147 @@ AtaBlockIoFlushBlocks ( return EFI_SUCCESS; } +/** + Reset the Block Device. + + @param[in] This Indicates a pointer to the calling context. + @param[in] 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 +AtaBlockIoResetEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_STATUS Status; + ATA_DEVICE *AtaDevice; + EFI_TPL OldTpl; + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + AtaDevice = ATA_DEVICE_FROM_BLOCK_IO2 (This); + + Status = ResetAtaDevice (AtaDevice); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + } + + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Read BufferSize bytes from Lba into Buffer. + + @param[in] This Indicates a pointer to the calling context. + @param[in] MediaId Id of the media, changes every time the media is replaced. + @param[in] Lba The starting Logical Block Address to read from. + @param[in, out] Token A pointer to the token associated with the transaction. + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[out] Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The read request was queued if Event is not NULL. + The data was read correctly from the device if + the Event is NULL. + @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 is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack + of resources. + +**/ +EFI_STATUS +EFIAPI +AtaBlockIoReadBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + return BlockIoReadWrite ((VOID *) This, MediaId, Lba, Token, BufferSize, Buffer, TRUE, FALSE); +} + + +/** + Write BufferSize bytes from Lba into Buffer. + + @param[in] This Indicates a pointer to the calling context. + @param[in] MediaId The media ID that the write request is for. + @param[in] Lba The starting logical block address to be written. The + caller is responsible for writing to only legitimate + locations. + @param[in, out] Token A pointer to the token associated with the transaction. + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[in] 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 +AtaBlockIoWriteBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + return BlockIoReadWrite ((VOID *) This, MediaId, Lba, Token, BufferSize, Buffer, TRUE, TRUE); +} + + +/** + Flush the Block Device. + + @param[in] This Indicates a pointer to the calling context. + @param[in, out] Token A pointer to the token associated with the transaction. + + @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 +AtaBlockIoFlushBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN OUT EFI_BLOCK_IO2_TOKEN *Token + ) +{ + // + // Signla event and return directly. + // + if (Token != NULL && Token->Event != NULL) { + Token->TransactionStatus = EFI_SUCCESS; + gBS->SignalEvent (Token->Event); + } + return EFI_SUCCESS; +} /** Provides inquiry information for the controller type. diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h index 4cda0e5cc4..4d036836e9 100644 --- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h +++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -59,13 +60,37 @@ // // The maximum ATA transaction sector count in 48 bit addressing mode. // -#define MAX_48BIT_TRANSFER_BLOCK_NUM 0x10000 +//#define MAX_48BIT_TRANSFER_BLOCK_NUM 0x10000 + +// +// BugBug: if the TransferLength is equal with 0x10000 (the 48bit max length), +// there is a bug that even the register interrupt bit has been sit, the buffer +// seems not ready. Change the Maximum Sector Numbers to 0xFFFF to work round +// this issue. +// +#define MAX_48BIT_TRANSFER_BLOCK_NUM 0xFFFF // // The maximum model name in ATA identify data // #define MAX_MODEL_NAME_LEN 40 +#define ATA_TASK_SIGNATURE SIGNATURE_32 ('A', 'T', 'S', 'K') +#define ATA_DEVICE_SIGNATURE SIGNATURE_32 ('A', 'B', 'I', 'D') + +#define IS_ALIGNED(addr, size) (((UINTN) (addr) & (size - 1)) == 0) + +// +// Task for the non blocking I/O +// +typedef struct { + UINT32 Signature; + EFI_BLOCK_IO2_TOKEN *Token; + UINTN *UnsignalledEventCount; + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; + BOOLEAN *IsError;// Indicate whether meeting error during source allocation for new task. + LIST_ENTRY TaskEntry; +} ATA_BUS_ASYN_TASK; // // ATA bus data structure for ATA controller @@ -77,46 +102,48 @@ typedef struct { 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; + 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; + EFI_HANDLE Handle; + EFI_BLOCK_IO_PROTOCOL BlockIo; + EFI_BLOCK_IO2_PROTOCOL BlockIo2; + EFI_BLOCK_IO_MEDIA BlockMedia; + EFI_DISK_INFO_PROTOCOL DiskInfo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; - ATA_BUS_DRIVER_DATA *AtaBusDriverData; - UINT16 Port; - UINT16 PortMultiplierPort; + 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; + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; + EFI_ATA_COMMAND_BLOCK Acb; + EFI_ATA_STATUS_BLOCK *Asb; - BOOLEAN UdmaValid; - BOOLEAN Lba48Bit; + BOOLEAN UdmaValid; + BOOLEAN Lba48Bit; // // Cached data for ATA identify data // - ATA_IDENTIFY_DATA *IdentifyData; + ATA_IDENTIFY_DATA *IdentifyData; - EFI_UNICODE_STRING_TABLE *ControllerNameTable; - CHAR16 ModelName[MAX_MODEL_NAME_LEN + 1]; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + CHAR16 ModelName[MAX_MODEL_NAME_LEN + 1]; + LIST_ENTRY AtaTaskList; } 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) +#define ATA_DEVICE_FROM_BLOCK_IO(a) CR (a, ATA_DEVICE, BlockIo, ATA_DEVICE_SIGNATURE) +#define ATA_DEVICE_FROM_BLOCK_IO2(a) CR (a, ATA_DEVICE, BlockIo2, ATA_DEVICE_SIGNATURE) +#define ATA_DEVICE_FROM_DISK_INFO(a) CR (a, ATA_DEVICE, DiskInfo, ATA_DEVICE_SIGNATURE) +#define ATA_AYNS_TASK_FROM_ENTRY(a) CR (a, ATA_BUS_ASYN_TASK, TaskEntry, ATA_TASK_SIGNATURE) // // Global Variables @@ -125,6 +152,52 @@ extern EFI_DRIVER_BINDING_PROTOCOL gAtaBusDriverBinding; extern EFI_COMPONENT_NAME_PROTOCOL gAtaBusComponentName; extern EFI_COMPONENT_NAME2_PROTOCOL gAtaBusComponentName2; +/** + 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 + ); + +/** + Frees an aligned buffer for ATA device. + + This function frees an aligned buffer for the ATA device to perform + ATA pass through operations. + + @param Buffer The aligned buffer to be freed. + @param BufferSize The request buffer size. + +**/ +VOID +FreeAlignedBuffer ( + IN VOID *Buffer, + IN UINTN BufferSize + ); + +/** + Free SubTask. + + @param[in, out] Task Pointer to task to be freed. + +**/ +VOID +EFIAPI +FreeAtaSubTask ( + IN ATA_BUS_ASYN_TASK *Task + ); /** Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.ResetDevice(). @@ -162,7 +235,6 @@ DiscoverAtaDevice ( IN OUT ATA_DEVICE *AtaDevice ); - /** Read or write a number of blocks from ATA device. @@ -170,11 +242,12 @@ DiscoverAtaDevice ( 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. + @param[in, out] AtaDevice The ATA child device involved for the operation. + @param[in, out] Buffer The pointer to the current transaction buffer. + @param[in] StartLba The starting logical block address to be accessed. + @param[in] NumberOfBlocks The block number or sector count of the transfer. + @param[in] IsWrite Indicates whether it is a write operation. + @param[in, out] Token A pointer to the token associated with the transaction. @retval EFI_SUCCESS The data transfer is complete successfully. @return others Some error occurs when transferring data. @@ -186,7 +259,8 @@ AccessAtaDevice( IN OUT UINT8 *Buffer, IN EFI_LBA StartLba, IN UINTN NumberOfBlocks, - IN BOOLEAN IsWrite + IN BOOLEAN IsWrite, + IN OUT EFI_BLOCK_IO2_TOKEN *Token ); // @@ -544,6 +618,111 @@ AtaBlockIoFlushBlocks ( IN EFI_BLOCK_IO_PROTOCOL *This ); +/** + Reset the Block Device throught Block I/O2 protocol. + + @param[in] This Indicates a pointer to the calling context. + @param[in] 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 +AtaBlockIoResetEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Read BufferSize bytes from Lba into Buffer. + + @param[in] This Indicates a pointer to the calling context. + @param[in] MediaId Id of the media, changes every time the media is replaced. + @param[in] Lba The starting Logical Block Address to read from. + @param[in, out] Token A pointer to the token associated with the transaction. + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[out] Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The read request was queued if Event is not NULL. + The data was read correctly from the device if + the Event is NULL. + @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 is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack + of resources. + +**/ +EFI_STATUS +EFIAPI +AtaBlockIoReadBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Write BufferSize bytes from Lba into Buffer. + + @param[in] This Indicates a pointer to the calling context. + @param[in] MediaId The media ID that the write request is for. + @param[in] Lba The starting logical block address to be written. The + caller is responsible for writing to only legitimate + locations. + @param[in, out] Token A pointer to the token associated with the transaction. + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[in] 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 +AtaBlockIoWriteBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/** + Flush the Block Device. + + @param[in] This Indicates a pointer to the calling context. + @param[in, out] Token A pointer to the token associated with the transaction. + + @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 +AtaBlockIoFlushBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN OUT EFI_BLOCK_IO2_TOKEN *Token + ); /** Provides inquiry information for the controller type. diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf index 9ca1b4bbb4..18ed39d429 100644 --- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf +++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf @@ -5,7 +5,7 @@ # 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 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2009 - 2011, 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 @@ -63,6 +63,7 @@ [Protocols] gEfiDiskInfoProtocolGuid # BY_START gEfiBlockIoProtocolGuid # BY_START + gEfiBlockIo2ProtocolGuid # BY_START gEfiAtaPassThruProtocolGuid # TO_START gEfiDevicePathProtocolGuid # TO_START diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c index acfbd74394..1f204193fd 100644 --- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c +++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c @@ -5,7 +5,7 @@ It transforms the high level identity, read/write, reset command to ATA pass through command and protocol. - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2011, 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 @@ -75,14 +75,25 @@ UINTN mMaxTransferBlockNumber[] = { 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. + @param[in, out] AtaDevice The ATA child device involved for the operation. + @param[in, out] TaskPacket Pointer to a Pass Thru Command Packet. Optional, + if it is NULL, blocking mode, and use the packet + in AtaDevice. If it is not NULL, non blocking mode, + and pass down this Packet. + @param[in] Event If Event is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking I/O is + supported,then non-blocking I/O is performed, + and Event will be signaled when the write + request is completed. @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru(). **/ EFI_STATUS AtaDevicePassThru ( - IN OUT ATA_DEVICE *AtaDevice + IN OUT ATA_DEVICE *AtaDevice, + IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL + IN OUT EFI_EVENT Event OPTIONAL ) { EFI_STATUS Status; @@ -90,12 +101,19 @@ AtaDevicePassThru ( EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet; // - // Assemble packet + // Assemble packet. If it is non blocking mode, the Ata driver should keep each + // subtask and clean them when the event is signaled. // - Packet = &AtaDevice->Packet; - Packet->Asb = AtaDevice->Asb; - Packet->Acb = &AtaDevice->Acb; - Packet->Timeout = ATA_TIMEOUT; + if (TaskPacket != NULL) { + Packet = TaskPacket; + Packet->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->Asb)); + CopyMem (Packet->Asb, AtaDevice->Asb, sizeof (*AtaDevice->Asb)); + Packet->Acb = AllocateCopyPool(sizeof (EFI_ATA_COMMAND_BLOCK), &AtaDevice->Acb); + } else { + Packet = &AtaDevice->Packet; + Packet->Asb = AtaDevice->Asb; + Packet->Acb = &AtaDevice->Acb; + } AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru; @@ -104,7 +122,7 @@ AtaDevicePassThru ( AtaDevice->Port, AtaDevice->PortMultiplierPort, Packet, - NULL + Event ); // // Ensure ATA pass through caller and callee have the same @@ -257,6 +275,8 @@ IdentifyAtaDevice ( return EFI_UNSUPPORTED; } + DEBUG ((EFI_D_INFO, "AtaBus - Identify Device (%x %x)\n", (UINTN)AtaDevice->Port, (UINTN)AtaDevice->PortMultiplierPort)); + // // Check whether the WORD 88 (supported UltraDMA by drive) is valid // @@ -319,7 +339,7 @@ IdentifyAtaDevice ( // // Get ATA model name from identify data structure. // - PrintAtaModelName (AtaDevice); + PrintAtaModelName (AtaDevice); return EFI_SUCCESS; } @@ -354,7 +374,7 @@ DiscoverAtaDevice ( // Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb)); Acb->AtaCommand = ATA_CMD_IDENTIFY_DRIVE; - Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4)); + Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4)); // // Prepare for ATA pass through packet. @@ -363,11 +383,12 @@ DiscoverAtaDevice ( 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; + Packet->Length = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT; + Packet->Timeout = ATA_TIMEOUT; Retry = MAX_RETRY_TIMES; do { - Status = AtaDevicePassThru (AtaDevice); + Status = AtaDevicePassThru (AtaDevice, NULL, NULL); if (!EFI_ERROR (Status)) { // // The command is issued successfully @@ -389,11 +410,20 @@ DiscoverAtaDevice ( 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. + @param[in, out] AtaDevice The ATA child device involved for the operation. + @param[in, out] TaskPacket Pointer to a Pass Thru Command Packet. Optional, + if it is NULL, blocking mode, and use the packet + in AtaDevice. If it is not NULL, non blocking mode, + and pass down this Packet. + @param[in, out] Buffer The pointer to the current transaction buffer. + @param[in] StartLba The starting logical block address to be accessed. + @param[in] TransferLength The block number or sector count of the transfer. + @param[in] IsWrite Indicates whether it is a write operation. + @param[in] Event If Event is NULL, then blocking I/O is performed. + If Event is not NULL and non-blocking I/O is + supported,then non-blocking I/O is performed, + and Event will be signaled when the write + request is completed. @retval EFI_SUCCESS The data transfer is complete successfully. @return others Some error occurs when transferring data. @@ -401,11 +431,13 @@ DiscoverAtaDevice ( **/ EFI_STATUS TransferAtaDevice ( - IN OUT ATA_DEVICE *AtaDevice, - IN OUT VOID *Buffer, - IN EFI_LBA StartLba, - IN UINT32 TransferLength, - IN BOOLEAN IsWrite + IN OUT ATA_DEVICE *AtaDevice, + IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL + IN OUT VOID *Buffer, + IN EFI_LBA StartLba, + IN UINT32 TransferLength, + IN BOOLEAN IsWrite, + IN EFI_EVENT Event OPTIONAL ) { EFI_ATA_COMMAND_BLOCK *Acb; @@ -425,7 +457,7 @@ TransferAtaDevice ( 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)); + Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4)); Acb->AtaSectorCount = (UINT8) TransferLength; if (AtaDevice->Lba48Bit) { Acb->AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24); @@ -439,7 +471,12 @@ TransferAtaDevice ( // // Prepare for ATA pass through packet. // - Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet)); + if (TaskPacket != NULL) { + Packet = ZeroMem (TaskPacket, sizeof (*Packet)); + } else { + Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet)); + } + if (IsWrite) { Packet->OutDataBuffer = Buffer; Packet->OutTransferLength = TransferLength; @@ -447,10 +484,109 @@ TransferAtaDevice ( Packet->InDataBuffer = Buffer; Packet->InTransferLength = TransferLength; } + Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsWrite]; Packet->Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT; + Packet->Timeout = ATA_TIMEOUT; + + return AtaDevicePassThru (AtaDevice, TaskPacket, Event); +} + +/** + Free SubTask. + + @param[in, out] Task Pointer to task to be freed. + +**/ +VOID +EFIAPI +FreeAtaSubTask ( + IN ATA_BUS_ASYN_TASK *Task + ) +{ + if (Task->Packet.Asb != NULL) { + FreeAlignedBuffer (Task->Packet.Asb, sizeof (Task->Packet.Asb)); + } + if (Task->Packet.Acb != NULL) { + FreePool (Task->Packet.Acb); + } + + FreePool (Task); +} + +/** + Call back funtion when the event is signaled. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registerd to the + Event. + +**/ +VOID +EFIAPI +AtaNonBlockingCallBack ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + ATA_BUS_ASYN_TASK *Task; + + Task = (ATA_BUS_ASYN_TASK *) Context; + gBS->CloseEvent (Event); + + // + // Check the command status. + // If there is error during the sub task source allocation, the error status + // should be returned to the caller directly, so here the Task->Token may already + // be deleted by the caller and no need to update the status. + // + if ((!(*Task->IsError)) && (Task->Packet.Asb->AtaStatus & 0x01) == 0x01) { + Task->Token->TransactionStatus = EFI_DEVICE_ERROR; + } + DEBUG (( + DEBUG_INFO, + "NON-BLOCKING EVENT FINISHED!- STATUS = %r\n", + Task->Token->TransactionStatus + )); + + // + // Reduce the SubEventCount, till it comes to zero. + // + (*Task->UnsignalledEventCount) --; + DEBUG ((DEBUG_INFO, "UnsignalledEventCount = %x\n", *Task->UnsignalledEventCount)); + + // + // Remove the SubTask from the Task list. + // + RemoveEntryList (&Task->TaskEntry); + if ((*Task->UnsignalledEventCount) == 0) { + // + // All Sub tasks are done, then signal the upper layyer event. + // Except there is error during the sub task source allocation. + // + if (!(*Task->IsError)) { + gBS->SignalEvent (Task->Token->Event); + DEBUG ((DEBUG_INFO, "Signal Up Level Event UnsignalledEventCount = %x!\n", *Task->UnsignalledEventCount)); + } + + FreePool (Task->UnsignalledEventCount); + FreePool (Task->IsError); + } - return AtaDevicePassThru (AtaDevice); + DEBUG (( + DEBUG_INFO, + "PACKET INFO: Write=%s, Lenght=%x, LowCylinder=%x, HighCylinder=%x,SectionNumber=%x", + Task->Packet.OutDataBuffer != NULL ? L"YES" : L"NO", + Task->Packet.OutDataBuffer != NULL ? Task->Packet.OutTransferLength : Task->Packet.InTransferLength, + Task->Packet.Acb->AtaCylinderLow, + Task->Packet.Acb->AtaCylinderHigh, + Task->Packet.Acb->AtaSectorCount + )); + + // + // Free the buffer of SubTask. + // + FreeAtaSubTask (Task); } /** @@ -460,11 +596,12 @@ TransferAtaDevice ( 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. + @param[in, out] AtaDevice The ATA child device involved for the operation. + @param[in, out] Buffer The pointer to the current transaction buffer. + @param[in] StartLba The starting logical block address to be accessed. + @param[in] NumberOfBlocks The block number or sector count of the transfer. + @param[in] IsWrite Indicates whether it is a write operation. + @param[in, out] Token A pointer to the token associated with the transaction. @retval EFI_SUCCESS The data transfer is complete successfully. @return others Some error occurs when transferring data. @@ -476,36 +613,146 @@ AccessAtaDevice( IN OUT UINT8 *Buffer, IN EFI_LBA StartLba, IN UINTN NumberOfBlocks, - IN BOOLEAN IsWrite + IN BOOLEAN IsWrite, + IN OUT EFI_BLOCK_IO2_TOKEN *Token ) { EFI_STATUS Status; UINTN MaxTransferBlockNumber; UINTN TransferBlockNumber; UINTN BlockSize; - + UINTN *EventCount; + UINTN TempCount; + ATA_BUS_ASYN_TASK *Task; + EFI_EVENT SubEvent; + UINTN Index; + BOOLEAN *IsError; + EFI_TPL OldTpl; + + SubEvent = NULL; + TempCount = 0; + Status = EFI_SUCCESS; + + EventCount = AllocateZeroPool (sizeof (UINTN)); + if (EventCount == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + IsError = AllocateZeroPool (sizeof (BOOLEAN)); + if (IsError == NULL) { + goto EXIT; + } + *IsError = FALSE; + + // + // Initial the return status for Non Blocking. + // + if (Token != NULL && Token->Event != NULL) { + Token->TransactionStatus = EFI_SUCCESS; + } // // Ensure AtaDevice->Lba48Bit is a valid boolean value // ASSERT ((UINTN) AtaDevice->Lba48Bit < 2); MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit]; - BlockSize = AtaDevice->BlockMedia.BlockSize; + BlockSize = AtaDevice->BlockMedia.BlockSize; + + TempCount = (NumberOfBlocks + MaxTransferBlockNumber - 1) / MaxTransferBlockNumber; + *EventCount = TempCount; + Index = 0; + do { if (NumberOfBlocks > MaxTransferBlockNumber) { TransferBlockNumber = MaxTransferBlockNumber; - NumberOfBlocks -= MaxTransferBlockNumber; + NumberOfBlocks -= MaxTransferBlockNumber; } else { TransferBlockNumber = NumberOfBlocks; NumberOfBlocks = 0; } - Status = TransferAtaDevice (AtaDevice, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite); + // + // Create sub event for the sub Ata task. Non-Blocking Mode. + // + if (Token != NULL && Token->Event != NULL) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + Task = AllocateZeroPool (sizeof (ATA_BUS_ASYN_TASK)); + if (Task == NULL) { + // + // If resource allocation fail, reduce the total sub event counts. + // + *EventCount = (*EventCount) - (TempCount - Index); + *IsError = TRUE; + Token->TransactionStatus = EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + + gBS->RestoreTPL (OldTpl); + goto EXIT; + } + + Task->UnsignalledEventCount = EventCount; + Task->Token = Token; + Task->IsError = IsError; + + InsertTailList (&AtaDevice->AtaTaskList, &Task->TaskEntry); + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + AtaNonBlockingCallBack, + Task, + &SubEvent + ); + // + // If resource allocation fail, the un-signalled event count should equal to + // the original one minus the unassigned subtasks number. + // + if (EFI_ERROR (Status)) { + *EventCount = (*EventCount) - (TempCount - Index); + *IsError = TRUE; + gBS->RestoreTPL (OldTpl); + goto EXIT; + } + Index++; + gBS->RestoreTPL (OldTpl); + + DEBUG ((EFI_D_INFO, "NON-BLOCKING SET EVENT START: WRITE = %d\n", IsWrite)); + Status = TransferAtaDevice (AtaDevice, &Task->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent); + DEBUG (( + EFI_D_INFO, + "NON-BLOCKING SET EVENT END:StartLba=%x, TransferBlockNumbers=%x, Status=%r\n", + StartLba, + TransferBlockNumber, + Status + )); + }else { + // + // Blocking Mode. + // + DEBUG ((EFI_D_INFO, "BLOCKING BLOCK I/O START: WRITE = %d\n", IsWrite)); + Status = TransferAtaDevice (AtaDevice, NULL, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, NULL); + DEBUG (( + EFI_D_INFO, + "BLOCKING BLOCK I/O FINISHE - StartLba = %x; TransferBlockNumbers = %x, status = %r\n", + StartLba, + TransferBlockNumber, + Status + )); + } + if (EFI_ERROR (Status)) { - return Status; + goto EXIT; } + StartLba += TransferBlockNumber; Buffer += TransferBlockNumber * BlockSize; } while (NumberOfBlocks > 0); +EXIT: + + if (*EventCount == 0) { + FreePool (EventCount); + FreePool (IsError); + } + return Status; } diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c b/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c index 98e46e9d76..13b94c307f 100644 --- a/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c +++ b/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c @@ -1,7 +1,7 @@ /** @file Decode an El Torito formatted CD-ROM -Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2011, 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 @@ -20,15 +20,16 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Install child handles if the Handle supports El Torito format. @param[in] This Calling context. - @param[in] Handle Parent Handle - @param[in] DiskIo Parent DiskIo interface - @param[in] BlockIo Parent BlockIo interface + @param[in] Handle Parent Handle. + @param[in] DiskIo Parent DiskIo interface. + @param[in] BlockIo Parent BlockIo interface. + @param[in] BlockIo2 Parent BlockIo2 interface. @param[in] DevicePath Parent Device Path - @retval EFI_SUCCESS Child handle(s) was added - @retval EFI_MEDIA_CHANGED Media changed Detected - @retval other no child handle was added + @retval EFI_SUCCESS Child handle(s) was added. + @retval EFI_MEDIA_CHANGED Media changed Detected. + @retval other no child handle was added. **/ EFI_STATUS @@ -37,6 +38,7 @@ PartitionInstallElToritoChildHandles ( IN EFI_HANDLE Handle, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { @@ -59,6 +61,7 @@ PartitionInstallElToritoChildHandles ( Found = EFI_NOT_FOUND; Media = BlockIo->Media; + VolSpaceSize = 0; // @@ -256,6 +259,7 @@ PartitionInstallElToritoChildHandles ( Handle, DiskIo, BlockIo, + BlockIo2, DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &CdDev, Catalog->Boot.Lba, diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c index 19eb6f12c2..682e8b41b5 100644 --- a/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c +++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c @@ -2,7 +2,7 @@ Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0 specification. -Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2011, 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 @@ -16,11 +16,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "Partition.h" - /** Install child handles if the Handle supports GPT partition structure. - @param[in] BlockIo Parent BlockIo interface + @param[in] BlockIo Parent BlockIo interface. @param[in] DiskIo Disk Io protocol. @param[in] Lba The starting Lba of the Partition Table @param[out] PartHeader Stores the partition table that is read @@ -37,7 +36,6 @@ PartitionValidGptTable ( OUT EFI_PARTITION_TABLE_HEADER *PartHeader ); - /** Check if the CRC field in the Partition table header is valid for Partition entry array. @@ -60,11 +58,11 @@ PartitionCheckGptEntryArrayCRC ( /** Restore Partition Table to its alternate place - (Primary -> Backup or Backup -> Primary) + (Primary -> Backup or Backup -> Primary). - @param[in] BlockIo Parent BlockIo interface + @param[in] BlockIo Parent BlockIo interface. @param[in] DiskIo Disk Io Protocol. - @param[in] PartHeader Partition table header structure + @param[in] PartHeader Partition table header structure. @retval TRUE Restoring succeeds @retval FALSE Restoring failed @@ -160,15 +158,16 @@ PartitionSetCrc ( /** Install child handles if the Handle supports GPT partition structure. - @param[in] This - Calling context. - @param[in] Handle - Parent Handle - @param[in] DiskIo - Parent DiskIo interface - @param[in] BlockIo - Parent BlockIo interface - @param[in] DevicePath - Parent Device Path + @param[in] This Calling context. + @param[in] Handle Parent Handle. + @param[in] DiskIo Parent DiskIo interface. + @param[in] BlockIo Parent BlockIo interface. + @param[in] BlockIo2 Parent BlockIo2 interface. + @param[in] DevicePath Parent Device Path. - @retval EFI_SUCCESS Valid GPT disk - @retval EFI_MEDIA_CHANGED Media changed Detected - @retval other Not a valid GPT disk + @retval EFI_SUCCESS Valid GPT disk. + @retval EFI_MEDIA_CHANGED Media changed Detected. + @retval other Not a valid GPT disk. **/ EFI_STATUS @@ -177,6 +176,7 @@ PartitionInstallGptChildHandles ( IN EFI_HANDLE Handle, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { @@ -191,6 +191,7 @@ PartitionInstallGptChildHandles ( UINTN Index; EFI_STATUS GptValidStatus; HARDDRIVE_DEVICE_PATH HdDev; + UINT32 MediaId; ProtectiveMbr = NULL; PrimaryHeader = NULL; @@ -200,6 +201,7 @@ PartitionInstallGptChildHandles ( BlockSize = BlockIo->Media->BlockSize; LastBlock = BlockIo->Media->LastBlock; + MediaId = BlockIo->Media->MediaId; DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize)); DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock)); @@ -219,15 +221,16 @@ PartitionInstallGptChildHandles ( // Status = DiskIo->ReadDisk ( DiskIo, - BlockIo->Media->MediaId, + MediaId, 0, - BlockIo->Media->BlockSize, + BlockSize, ProtectiveMbr ); if (EFI_ERROR (Status)) { GptValidStatus = Status; goto Done; } + // // Verify that the Protective MBR is valid // @@ -302,7 +305,7 @@ PartitionInstallGptChildHandles ( Status = DiskIo->ReadDisk ( DiskIo, - BlockIo->Media->MediaId, + MediaId, MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize), PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry), PartEntry @@ -369,17 +372,18 @@ PartitionInstallGptChildHandles ( DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (PartEntry[Index].EndingLBA, BlockSize))); Status = PartitionInstallChildHandle ( - This, - Handle, - DiskIo, - BlockIo, - DevicePath, - (EFI_DEVICE_PATH_PROTOCOL *) &HdDev, - PartEntry[Index].StartingLBA, - PartEntry[Index].EndingLBA, - BlockSize, - CompareGuid(&PartEntry[Index].PartitionTypeGUID, &gEfiPartTypeSystemPartGuid) - ); + This, + Handle, + DiskIo, + BlockIo, + BlockIo2, + DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &HdDev, + PartEntry[Index].StartingLBA, + PartEntry[Index].EndingLBA, + BlockSize, + CompareGuid(&PartEntry[Index].PartitionTypeGUID, &gEfiPartTypeSystemPartGuid) + ); } DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n")); @@ -404,11 +408,10 @@ Done: return GptValidStatus; } - /** Install child handles if the Handle supports GPT partition structure. - @param[in] BlockIo Parent BlockIo interface + @param[in] BlockIo Parent BlockIo interface. @param[in] DiskIo Disk Io protocol. @param[in] Lba The starting Lba of the Partition Table @param[out] PartHeader Stores the partition table that is read @@ -428,9 +431,10 @@ PartitionValidGptTable ( EFI_STATUS Status; UINT32 BlockSize; EFI_PARTITION_TABLE_HEADER *PartHdr; + UINT32 MediaId; BlockSize = BlockIo->Media->BlockSize; - + MediaId = BlockIo->Media->MediaId; PartHdr = AllocateZeroPool (BlockSize); if (PartHdr == NULL) { @@ -442,7 +446,7 @@ PartitionValidGptTable ( // Status = DiskIo->ReadDisk ( DiskIo, - BlockIo->Media->MediaId, + MediaId, MultU64x32 (Lba, BlockSize), BlockSize, PartHdr @@ -472,12 +476,12 @@ PartitionValidGptTable ( return TRUE; } - /** Check if the CRC field in the Partition table header is valid for Partition entry array. @param[in] BlockIo Parent BlockIo interface + @param[in] BlockIo2 Parent BlockIo2 interface. @param[in] DiskIo Disk Io Protocol. @param[in] PartHeader Partition table header structure @@ -535,11 +539,11 @@ PartitionCheckGptEntryArrayCRC ( /** Restore Partition Table to its alternate place - (Primary -> Backup or Backup -> Primary) + (Primary -> Backup or Backup -> Primary). - @param[in] BlockIo Parent BlockIo interface + @param[in] BlockIo Parent BlockIo interface. @param[in] DiskIo Disk Io Protocol. - @param[in] PartHeader Partition table header structure + @param[in] PartHeader Partition table header structure. @retval TRUE Restoring succeeds @retval FALSE Restoring failed @@ -557,11 +561,13 @@ PartitionRestoreGptTable ( EFI_PARTITION_TABLE_HEADER *PartHdr; EFI_LBA PEntryLBA; UINT8 *Ptr; + UINT32 MediaId; PartHdr = NULL; Ptr = NULL; BlockSize = BlockIo->Media->BlockSize; + MediaId = BlockIo->Media->MediaId; PartHdr = AllocateZeroPool (BlockSize); @@ -583,8 +589,8 @@ PartitionRestoreGptTable ( Status = DiskIo->WriteDisk ( DiskIo, - BlockIo->Media->MediaId, - MultU64x32 (PartHdr->MyLBA, BlockIo->Media->BlockSize), + MediaId, + MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize), BlockSize, PartHdr ); @@ -601,8 +607,8 @@ PartitionRestoreGptTable ( Status = DiskIo->ReadDisk ( DiskIo, - BlockIo->Media->MediaId, - MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), + MediaId, + MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize), PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry, Ptr ); @@ -612,8 +618,8 @@ PartitionRestoreGptTable ( Status = DiskIo->WriteDisk ( DiskIo, - BlockIo->Media->MediaId, - MultU64x32(PEntryLBA, BlockIo->Media->BlockSize), + MediaId, + MultU64x32(PEntryLBA, (UINT32) BlockSize), PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry, Ptr ); diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c index 8aef497ad3..4c64663746 100644 --- a/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c +++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c @@ -11,7 +11,7 @@ always on the first sector of a media. The first sector also contains the legacy boot strap code. -Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2011, 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 @@ -101,11 +101,12 @@ PartitionValidMbr ( /** Install child handles if the Handle supports MBR format. - @param This Calling context. - @param Handle Parent Handle. - @param DiskIo Parent DiskIo interface. - @param BlockIo Parent BlockIo interface. - @param DevicePath Parent Device Path. + @param[in] This Calling context. + @param[in] Handle Parent Handle. + @param[in] DiskIo Parent DiskIo interface. + @param[in] BlockIo Parent BlockIo interface. + @param[in] BlockIo2 Parent BlockIo2 interface. + @param[in] DevicePath Parent Device Path. @retval EFI_SUCCESS A child handle was added. @retval EFI_MEDIA_CHANGED Media change was detected. @@ -118,6 +119,7 @@ PartitionInstallMbrChildHandles ( IN EFI_HANDLE Handle, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { @@ -131,26 +133,33 @@ PartitionInstallMbrChildHandles ( UINT32 PartitionNumber; EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode; + UINT32 BlockSize; + UINT32 MediaId; + EFI_LBA LastBlock; Found = EFI_NOT_FOUND; - Mbr = AllocatePool (BlockIo->Media->BlockSize); + BlockSize = BlockIo->Media->BlockSize; + MediaId = BlockIo->Media->MediaId; + LastBlock = BlockIo->Media->LastBlock; + + Mbr = AllocatePool (BlockSize); if (Mbr == NULL) { return Found; } Status = DiskIo->ReadDisk ( DiskIo, - BlockIo->Media->MediaId, + MediaId, 0, - BlockIo->Media->BlockSize, + BlockSize, Mbr ); if (EFI_ERROR (Status)) { Found = Status; goto Done; } - if (!PartitionValidMbr (Mbr, BlockIo->Media->LastBlock)) { + if (!PartitionValidMbr (Mbr, LastBlock)) { goto Done; } // @@ -218,6 +227,7 @@ PartitionInstallMbrChildHandles ( Handle, DiskIo, BlockIo, + BlockIo2, DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &HdDev, HdDev.PartitionStart, @@ -241,9 +251,9 @@ PartitionInstallMbrChildHandles ( Status = DiskIo->ReadDisk ( DiskIo, - BlockIo->Media->MediaId, - MultU64x32 (ExtMbrStartingLba, BlockIo->Media->BlockSize), - BlockIo->Media->BlockSize, + MediaId, + MultU64x32 (ExtMbrStartingLba, BlockSize), + BlockSize, Mbr ); if (EFI_ERROR (Status)) { @@ -274,17 +284,18 @@ PartitionInstallMbrChildHandles ( *((UINT32 *) &HdDev.Signature[0]) = 0; Status = PartitionInstallChildHandle ( - This, - Handle, - DiskIo, - BlockIo, - DevicePath, - (EFI_DEVICE_PATH_PROTOCOL *) &HdDev, - HdDev.PartitionStart - ParentHdDev.PartitionStart, - HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1, - MBR_SIZE, - (BOOLEAN) (Mbr->Partition[0].OSIndicator == EFI_PARTITION) - ); + This, + Handle, + DiskIo, + BlockIo, + BlockIo2, + DevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &HdDev, + HdDev.PartitionStart - ParentHdDev.PartitionStart, + HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1, + MBR_SIZE, + (BOOLEAN) (Mbr->Partition[0].OSIndicator == EFI_PARTITION) + ); if (!EFI_ERROR (Status)) { Found = EFI_SUCCESS; } diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c index 3596a3bfc1..7d194daaea 100644 --- a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c +++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c @@ -40,16 +40,15 @@ PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = { NULL }; - - /** Test to see if this driver supports ControllerHandle. Any ControllerHandle - than contains a BlockIo and DiskIo protocol can be supported. + than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be + supported. - @param This Protocol instance pointer. - @param ControllerHandle Handle of device to test - @param RemainingDevicePath Optional parameter use to pick a specific child - device to start. + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to test. + @param[in] RemainingDevicePath Optional parameter use to pick a specific child + device to start. @retval EFI_SUCCESS This driver supports this device @retval EFI_ALREADY_STARTED This driver is already running on this device @@ -86,7 +85,7 @@ PartitionDriverBindingSupported ( if (Node->DevPath.Type != MEDIA_DEVICE_PATH || Node->DevPath.SubType != MEDIA_HARDDRIVE_DP || DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) { - return EFI_UNSUPPORTED; + return EFI_UNSUPPORTED; } } } @@ -105,7 +104,6 @@ PartitionDriverBindingSupported ( if (Status == EFI_ALREADY_STARTED) { return EFI_SUCCESS; } - if (EFI_ERROR (Status)) { return Status; } @@ -159,20 +157,39 @@ PartitionDriverBindingSupported ( ControllerHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL ); - - return Status; + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIo2ProtocolGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (EFI_ERROR (Status)) { + // + // According to UEFI Spec 2.3.1, if a driver is written for a disk device, + // then the EFI_BLOCK_IO_PROTOCOL and EFI_BLOCK_IO2_PROTOCOAL must be implemented. + // Currently, SCSI disk driver only produce the EFI_BLOCK_IO_PROTOCOL, it will + // not be updated until the non blocking SCSI Pass Thru Protocol is provided. + // If there is no EFI_BLOCK_IO2_PROTOCOL, skip here. + // + } + return EFI_SUCCESS; } - /** - Start this driver on ControllerHandle by opening a Block IO and Disk IO - protocol, reading Device Path, and creating a child handle with a - Disk IO and device path protocol. + Start this driver on ControllerHandle by opening a Block IO or a Block IO2 + or both, and Disk IO protocol, reading Device Path, and creating a child + handle with a Disk IO and device path protocol. - @param This Protocol instance pointer. - @param ControllerHandle Handle of device to bind driver to - @param RemainingDevicePath Optional parameter use to pick a specific child - device to start. + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to bind driver to + @param[in] RemainingDevicePath Optional parameter use to pick a specific child + device to start. @retval EFI_SUCCESS This driver is added to ControllerHandle @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle @@ -190,6 +207,7 @@ PartitionDriverBindingStart ( EFI_STATUS Status; EFI_STATUS OpenStatus; EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_BLOCK_IO2_PROTOCOL *BlockIo2; EFI_DISK_IO_PROTOCOL *DiskIo; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; PARTITION_DETECT_ROUTINE *Routine; @@ -211,6 +229,10 @@ PartitionDriverBindingStart ( } } + // + // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue, + // otherwise, return error. + // Status = gBS->OpenProtocol ( ControllerHandle, &gEfiBlockIoProtocolGuid, @@ -222,8 +244,27 @@ PartitionDriverBindingStart ( if (EFI_ERROR (Status)) { goto Exit; } + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIo2ProtocolGuid, + (VOID **) &BlockIo2, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + // + // According to UEFI Spec 2.3.1, if a driver is written for a disk device, + // then the EFI_BLOCK_IO_PROTOCOL and EFI_BLOCK_IO2_PROTOCOAL must be implemented. + // Currently, SCSI disk driver only produce the EFI_BLOCK_IO_PROTOCOL, it will + // not be updated until the non blocking SCSI Pass Thru Protocol is provided. + // If there is no EFI_BLOCK_IO2_PROTOCOL, skip here. + // + } + // - // Get the Device Path Protocol on ControllerHandle's handle + // Get the Device Path Protocol on ControllerHandle's handle. // Status = gBS->OpenProtocol ( ControllerHandle, @@ -276,6 +317,7 @@ PartitionDriverBindingStart ( ControllerHandle, DiskIo, BlockIo, + BlockIo2, ParentDevicePath ); if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) { @@ -306,6 +348,15 @@ PartitionDriverBindingStart ( This->DriverBindingHandle, ControllerHandle ); + // + // Close Parent BlockIO2 if has. + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiBlockIo2ProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); gBS->CloseProtocol ( ControllerHandle, @@ -320,7 +371,6 @@ Exit: return Status; } - /** Stop this driver on ControllerHandle. Support stopping any child handles created by this driver. @@ -347,10 +397,15 @@ PartitionDriverBindingStop ( EFI_STATUS Status; UINTN Index; EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_BLOCK_IO2_PROTOCOL *BlockIo2; BOOLEAN AllChildrenStopped; PARTITION_PRIVATE_DATA *Private; EFI_DISK_IO_PROTOCOL *DiskIo; + BlockIo = NULL; + BlockIo2 = NULL; + Private = NULL; + if (NumberOfChildren == 0) { // // Close the bus driver @@ -361,6 +416,15 @@ PartitionDriverBindingStop ( This->DriverBindingHandle, ControllerHandle ); + // + // Close Parent BlockIO2 if has. + // + gBS->CloseProtocol ( + ControllerHandle, + &gEfiBlockIo2ProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); gBS->CloseProtocol ( ControllerHandle, @@ -368,60 +432,91 @@ PartitionDriverBindingStop ( This->DriverBindingHandle, ControllerHandle ); - return EFI_SUCCESS; } AllChildrenStopped = TRUE; for (Index = 0; Index < NumberOfChildren; Index++) { - Status = gBS->OpenProtocol ( - ChildHandleBuffer[Index], - &gEfiBlockIoProtocolGuid, - (VOID **) &BlockIo, - This->DriverBindingHandle, - ControllerHandle, - EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); - if (!EFI_ERROR (Status)) { - + gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + // + // Try to locate BlockIo2. + // + gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiBlockIo2ProtocolGuid, + (VOID **) &BlockIo2, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (BlockIo != NULL) { Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo); + } else if (BlockIo2 != NULL) { + Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (BlockIo2); + } else { + ASSERT (FALSE); + } - // - // All Software protocols have be freed from the handle so remove it. - // + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index] + ); + // + // All Software protocols have be freed from the handle so remove it. + // Remove the BlockIo Protocol if has. + // Remove the BlockIo2 Protocol if has. + // + if (BlockIo2 != NULL) { BlockIo->FlushBlocks (BlockIo); - - Status = gBS->CloseProtocol ( - ControllerHandle, - &gEfiDiskIoProtocolGuid, - This->DriverBindingHandle, - ChildHandleBuffer[Index] - ); - + BlockIo2->FlushBlocksEx (BlockIo2, NULL); Status = gBS->UninstallMultipleProtocolInterfaces ( - ChildHandleBuffer[Index], - &gEfiDevicePathProtocolGuid, - Private->DevicePath, - &gEfiBlockIoProtocolGuid, - &Private->BlockIo, - Private->EspGuid, - NULL, - NULL - ); - if (EFI_ERROR (Status)) { - gBS->OpenProtocol ( - ControllerHandle, - &gEfiDiskIoProtocolGuid, - (VOID **) &DiskIo, - This->DriverBindingHandle, - ChildHandleBuffer[Index], - EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER - ); - } else { - FreePool (Private->DevicePath); - FreePool (Private); - } + ChildHandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + Private->DevicePath, + &gEfiBlockIoProtocolGuid, + &Private->BlockIo, + &gEfiBlockIo2ProtocolGuid, + &Private->BlockIo2, + Private->EspGuid, + NULL, + NULL + ); + } else { + BlockIo->FlushBlocks (BlockIo); + Status = gBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + Private->DevicePath, + &gEfiBlockIoProtocolGuid, + &Private->BlockIo, + Private->EspGuid, + NULL, + NULL + ); + } + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + (VOID **) &DiskIo, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + } else { + FreePool (Private->DevicePath); + FreePool (Private); } if (EFI_ERROR (Status)) { @@ -551,11 +646,11 @@ PartitionReadBlocks ( Write by using the Disk IO protocol on the parent device. Lba addresses must be converted to byte offsets. - @param This Protocol instance pointer. - @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 Buffer containing read data + @param[in] This Protocol instance pointer. + @param[in] MediaId Id of the media, changes every time the media is replaced. + @param[in] Lba The starting Logical Block Address to read from + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[in] Buffer Buffer containing data to be written to device. @retval EFI_SUCCESS The data was written correctly to the device. @retval EFI_WRITE_PROTECTED The device can not be written to. @@ -574,7 +669,7 @@ PartitionWriteBlocks ( IN UINT32 MediaId, IN EFI_LBA Lba, IN UINTN BufferSize, - OUT VOID *Buffer + IN VOID *Buffer ) { PARTITION_PRIVATE_DATA *Private; @@ -622,25 +717,261 @@ PartitionFlushBlocks ( return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo); } +/** + Reset the Block Device throught Block I/O2 protocol. + + @param This Protocol instance pointer. + @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 +PartitionResetEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + PARTITION_PRIVATE_DATA *Private; + + Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This); + + return Private->ParentBlockIo2->Reset ( + Private->ParentBlockIo2, + ExtendedVerification + ); +} + +/** + Read BufferSize bytes from Lba into Buffer. + + This function reads the requested number of blocks from the device. All the + blocks are read, or an error is returned. + If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and + non-blocking I/O is being used, the Event associated with this request will + not be signaled. + + @param[in] This Indicates a pointer to the calling context. + @param[in] MediaId Id of the media, changes every time the media is + replaced. + @param[in] Lba The starting Logical Block Address to read from. + @param[in, out] Token A pointer to the token associated with the transaction. + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[out] Buffer A pointer to the destination buffer for the data. The + caller is responsible for either having implicit or + explicit ownership of the buffer. + + @retval EFI_SUCCESS The read request was queued if Token->Event is + not NULL.The data was read correctly from the + device if the Token->Event is NULL. + @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 is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the + intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack + of resources. +**/ +EFI_STATUS +EFIAPI +PartitionReadBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + PARTITION_PRIVATE_DATA *Private; + UINT64 Offset; + UINT32 UnderRun; + + if (Token == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This); + if (BufferSize % Private->BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; + if (Offset + BufferSize > Private->End) { + return EFI_INVALID_PARAMETER; + } + + // + // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must + // be multiple of BlockSize. If the Spec will be updated the DiskIO to support + // BlockIO2, this limitation will be removed and call DiskIO here. + // + Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun); + if (UnderRun != 0) { + return EFI_UNSUPPORTED; + } + + // + // Because some partitions have different block size from their parent + // device, in that case the Block I/O2 couldn't be called. + // + if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) { + return EFI_UNSUPPORTED; + } + + return Private->ParentBlockIo2->ReadBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer); +} + +/** + Write BufferSize bytes from Lba into Buffer. + + This function writes the requested number of blocks to the device. All blocks + are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA, + EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is + being used, the Event associated with this request will not be signaled. + + @param[in] This Indicates a pointer to the calling context. + @param[in] MediaId The media ID that the write request is for. + @param[in] Lba The starting logical block address to be written. The + caller is responsible for writing to only legitimate + locations. + @param[in, out] Token A pointer to the token associated with the transaction. + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[in] Buffer A pointer to the source buffer for the data. + + @retval EFI_SUCCESS The write request was queued if Event is not NULL. + The data was written correctly to the device if + the Event is NULL. + @retval EFI_WRITE_PROTECTED The device can not be written to. + @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_DEVICE_ERROR The device reported an error while performing the write. + @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. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack + of resources. + +**/ +EFI_STATUS +EFIAPI +PartitionWriteBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT EFI_BLOCK_IO2_TOKEN *Token, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + PARTITION_PRIVATE_DATA *Private; + UINT64 Offset; + UINT32 UnderRun; + + if (Token == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This); + if (BufferSize % Private->BlockSize != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start; + if (Offset + BufferSize > Private->End) { + return EFI_INVALID_PARAMETER; + } + + // + // Since the BlockIO2 call Parent BlockIO2 directly, so here the offset must + // be multiple of BlockSize. If the Spec will be updated the DiskIO to support + // BlockIO2, this limitation will be removed and call DiskIO here. + // + Lba = DivU64x32Remainder (Offset, Private->BlockSize, &UnderRun); + if (UnderRun != 0) { + return EFI_UNSUPPORTED; + } + + // + // Because some kinds of partition have different block size from their parent, + // in that case it couldn't call parent Block I/O2. + // + if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) { + return EFI_UNSUPPORTED; + } + + return Private->ParentBlockIo2->WriteBlocksEx (Private->ParentBlockIo2, MediaId, Lba, Token, BufferSize, Buffer); +} + +/** + Flush the Block Device. + + If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED + is returned and non-blocking I/O is being used, the Event associated with + this request will not be signaled. + + @param[in] This Indicates a pointer to the calling context. + @param[in,out] Token A pointer to the token associated with the transaction + + @retval EFI_SUCCESS The flush request was queued if Event is not NULL. + All outstanding data was written correctly to the + device if the Event is NULL. + @retval EFI_DEVICE_ERROR The device reported an error while writting back + the data. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack + of resources. + +**/ +EFI_STATUS +EFIAPI +PartitionFlushBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN OUT EFI_BLOCK_IO2_TOKEN *Token + ) +{ + PARTITION_PRIVATE_DATA *Private; + + Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This); + + // + // Because some kinds of partition have different block size from their parent, + // in that case it couldn't call parent Block I/O2. + // + if (Private->BlockSize != Private->ParentBlockIo->Media->BlockSize) { + return EFI_UNSUPPORTED; + } + + return Private->ParentBlockIo2->FlushBlocksEx (Private->ParentBlockIo2, Token); +} /** Create a child handle for a logical block device that represents the bytes Start to End of the Parent Block IO device. - @param[in] This Protocol instance pointer - @param[in] ParentHandle Parent Handle for new child - @param[in] ParentDiskIo Parent DiskIo interface - @param[in] ParentBlockIo Parent BlockIo interface - @param[in] ParentDevicePath Parent Device Path - @param[in] DevicePathNode Child Device Path node - @param[in] Start Start Block - @param[in] End End Block - @param[in] BlockSize Child block size - @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle - - @retval EFI_SUCCESS A child handle was added - @retval other A child handle was not added + @param[in] This Protocol instance pointer. + @param[in] ParentHandle Parent Handle for new child. + @param[in] ParentDiskIo Parent DiskIo interface. + @param[in] ParentBlockIo Parent BlockIo interface. + @param[in] ParentBlockIo2 Parent BlockIo2 interface. + @param[in] ParentDevicePath Parent Device Path. + @param[in] DevicePathNode Child Device Path node. + @param[in] Start Start Block. + @param[in] End End Block. + @param[in] BlockSize Child block size. + @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle. + + @retval EFI_SUCCESS A child handle was added. + @retval other A child handle was not added. **/ EFI_STATUS @@ -649,6 +980,7 @@ PartitionInstallChildHandle ( IN EFI_HANDLE ParentHandle, IN EFI_DISK_IO_PROTOCOL *ParentDiskIo, IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo, + IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN EFI_LBA Start, @@ -660,6 +992,7 @@ PartitionInstallChildHandle ( EFI_STATUS Status; PARTITION_PRIVATE_DATA *Private; + Status = EFI_SUCCESS; Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA)); if (Private == NULL) { return EFI_OUT_OF_RESOURCES; @@ -672,28 +1005,51 @@ PartitionInstallChildHandle ( Private->BlockSize = BlockSize; Private->ParentBlockIo = ParentBlockIo; + Private->ParentBlockIo2 = ParentBlockIo2; Private->DiskIo = ParentDiskIo; - Private->BlockIo.Revision = ParentBlockIo->Revision; + if (Private->ParentBlockIo != NULL) { + Private->BlockIo.Revision = ParentBlockIo->Revision; - Private->BlockIo.Media = &Private->Media; - CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA)); - Private->Media.LogicalPartition = TRUE; + Private->BlockIo.Media = &Private->Media; + CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA)); + + + Private->BlockIo.Reset = PartitionReset; + Private->BlockIo.ReadBlocks = PartitionReadBlocks; + Private->BlockIo.WriteBlocks = PartitionWriteBlocks; + Private->BlockIo.FlushBlocks = PartitionFlushBlocks; + } + + if (Private->ParentBlockIo2 != NULL) { + Private->BlockIo2.Media = &Private->Media2; + CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA)); + + Private->BlockIo2.Reset = PartitionResetEx; + Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx; + Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx; + Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx; + } - // - // Logical BlockIo instance doesn't have IoAlign restriction because it implements block io operation based on DiskIo - // Private->Media.IoAlign = 0; + Private->Media.LogicalPartition = TRUE; Private->Media.LastBlock = DivU64x32 ( MultU64x32 ( End - Start + 1, - ParentBlockIo->Media->BlockSize + (ParentBlockIo != NULL) ? ParentBlockIo->Media->BlockSize : ParentBlockIo2->Media->BlockSize ), - BlockSize + BlockSize ) - 1; Private->Media.BlockSize = (UINT32) BlockSize; + // + // For BlockIO2, it should keep the same alignment with the parent BlockIO2's. + // + Private->Media2.LogicalPartition = TRUE; + Private->Media2.LastBlock = Private->Media.LastBlock; + Private->Media2.BlockSize = (UINT32) BlockSize; + // // Per UEFI Spec, LowestAlignedLba and LogicalBlocksPerPhysicalBlock must be 0 // for logical partitions. @@ -703,12 +1059,7 @@ PartitionInstallChildHandle ( Private->BlockIo.Media->LogicalBlocksPerPhysicalBlock = 0; } - Private->BlockIo.Reset = PartitionReset; - Private->BlockIo.ReadBlocks = PartitionReadBlocks; - Private->BlockIo.WriteBlocks = PartitionWriteBlocks; - Private->BlockIo.FlushBlocks = PartitionFlushBlocks; - - Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode); + Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode); if (Private->DevicePath == NULL) { FreePool (Private); @@ -723,20 +1074,61 @@ PartitionInstallChildHandle ( // Private->EspGuid = NULL; } + // - // Create the new handle + // Create the new handle. + // BlockIO2 will be installed on the condition that the blocksize of parent BlockIO + // is same with the child BlockIO's. Instead of calling the DiskIO, the child BlockIO2 + // directly call the parent BlockIO and doesn't handle the different block size issue. + // If SPEC will update the DiskIO to support the Non-Blocking model, the BlockIO2 will call + // DiskIO to handle the blocksize unequal issue and the limitation will be remove from + // here. // Private->Handle = NULL; - Status = gBS->InstallMultipleProtocolInterfaces ( - &Private->Handle, - &gEfiDevicePathProtocolGuid, - Private->DevicePath, - &gEfiBlockIoProtocolGuid, - &Private->BlockIo, - Private->EspGuid, - NULL, - NULL - ); + if ((Private->ParentBlockIo != NULL) && + (Private->ParentBlockIo2 != NULL) && + (Private->ParentBlockIo2->Media->BlockSize == BlockSize) + ) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiDevicePathProtocolGuid, + Private->DevicePath, + &gEfiBlockIoProtocolGuid, + &Private->BlockIo, + &gEfiBlockIo2ProtocolGuid, + &Private->BlockIo2, + Private->EspGuid, + NULL, + NULL + ); + } else { + if (Private->ParentBlockIo != NULL) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiDevicePathProtocolGuid, + Private->DevicePath, + &gEfiBlockIoProtocolGuid, + &Private->BlockIo, + Private->EspGuid, + NULL, + NULL + ); + } + if (Private->ParentBlockIo2 != NULL && + Private->ParentBlockIo2->Media->BlockSize == BlockSize + ) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiDevicePathProtocolGuid, + Private->DevicePath, + &gEfiBlockIo2ProtocolGuid, + &Private->BlockIo2, + Private->EspGuid, + NULL, + NULL + ); + } + } if (!EFI_ERROR (Status)) { // diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h index 9fca9f360e..7a4ca8a319 100644 --- a/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h +++ b/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h @@ -4,7 +4,7 @@ of the raw block devices media. Currently "El Torito CD-ROM", Legacy MBR, and GPT partition schemes are supported. -Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2011, 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 @@ -20,6 +20,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include +#include #include #include #include @@ -48,10 +49,13 @@ typedef struct { EFI_HANDLE Handle; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_BLOCK_IO_PROTOCOL BlockIo; + EFI_BLOCK_IO2_PROTOCOL BlockIo2; EFI_BLOCK_IO_MEDIA Media; + EFI_BLOCK_IO_MEDIA Media2;//For BlockIO2 EFI_DISK_IO_PROTOCOL *DiskIo; EFI_BLOCK_IO_PROTOCOL *ParentBlockIo; + EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2; UINT64 Start; UINT64 End; UINT32 BlockSize; @@ -61,6 +65,7 @@ typedef struct { } PARTITION_PRIVATE_DATA; #define PARTITION_DEVICE_FROM_BLOCK_IO_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo, PARTITION_PRIVATE_DATA_SIGNATURE) +#define PARTITION_DEVICE_FROM_BLOCK_IO2_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo2, PARTITION_PRIVATE_DATA_SIGNATURE) // // Global Variables @@ -300,19 +305,20 @@ PartitionComponentNameGetControllerName ( Create a child handle for a logical block device that represents the bytes Start to End of the Parent Block IO device. - @param[in] This Protocol instance pointer - @param[in] ParentHandle Parent Handle for new child - @param[in] ParentDiskIo Parent DiskIo interface - @param[in] ParentBlockIo Parent BlockIo interface - @param[in] ParentDevicePath Parent Device Path - @param[in] DevicePathNode Child Device Path node - @param[in] Start Start Block - @param[in] End End Block - @param[in] BlockSize Child block size - @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle + @param[in] This Protocol instance pointer. + @param[in] ParentHandle Parent Handle for new child. + @param[in] ParentDiskIo Parent DiskIo interface. + @param[in] ParentBlockIo Parent BlockIo interface. + @param[in] ParentBlockIo2 Parent BlockIo2 interface. + @param[in] ParentDevicePath Parent Device Path. + @param[in] DevicePathNode Child Device Path node. + @param[in] Start Start Block. + @param[in] End End Block. + @param[in] BlockSize Child block size. + @param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle. - @retval EFI_SUCCESS A child handle was added - @retval other A child handle was not added + @retval EFI_SUCCESS A child handle was added. + @retval other A child handle was not added. **/ EFI_STATUS @@ -321,6 +327,7 @@ PartitionInstallChildHandle ( IN EFI_HANDLE ParentHandle, IN EFI_DISK_IO_PROTOCOL *ParentDiskIo, IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo, + IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN EFI_LBA Start, @@ -332,15 +339,17 @@ PartitionInstallChildHandle ( /** Install child handles if the Handle supports GPT partition structure. - @param[in] This - Calling context. - @param[in] Handle - Parent Handle - @param[in] DiskIo - Parent DiskIo interface - @param[in] BlockIo - Parent BlockIo interface - @param[in] DevicePath - Parent Device Path + @param[in] This Calling context. + @param[in] Handle Parent Handle. + @param[in] DiskIo Parent DiskIo interface. + @param[in] BlockIo Parent BlockIo interface. + @param[in] BlockIo2 Parent BlockIo2 interface. + @param[in] DevicePath Parent Device Path. - @retval EFI_SUCCESS Valid GPT disk - @retval EFI_MEDIA_CHANGED Media changed Detected - @retval other Not a valid GPT disk + @retval EFI_SUCCESS Valid GPT disk. + @retval EFI_MEDIA_CHANGED Media changed Detected. + @retval EFI_INVALID_PARAMETER If both BlockIo and BlockIo2 are NULL; + @retval other Not a valid GPT disk. **/ EFI_STATUS @@ -349,6 +358,7 @@ PartitionInstallGptChildHandles ( IN EFI_HANDLE Handle, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ); @@ -356,15 +366,16 @@ PartitionInstallGptChildHandles ( Install child handles if the Handle supports El Torito format. @param[in] This Calling context. - @param[in] Handle Parent Handle - @param[in] DiskIo Parent DiskIo interface - @param[in] BlockIo Parent BlockIo interface + @param[in] Handle Parent Handle. + @param[in] DiskIo Parent DiskIo interface. + @param[in] BlockIo Parent BlockIo interface. + @param[in] BlockIo2 Parent BlockIo2 interface. @param[in] DevicePath Parent Device Path - @retval EFI_SUCCESS Child handle(s) was added - @retval EFI_MEDIA_CHANGED Media changed Detected - @retval other no child handle was added + @retval EFI_SUCCESS Child handle(s) was added. + @retval EFI_MEDIA_CHANGED Media changed Detected. + @retval other no child handle was added. **/ EFI_STATUS @@ -373,17 +384,19 @@ PartitionInstallElToritoChildHandles ( IN EFI_HANDLE Handle, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ); /** Install child handles if the Handle supports MBR format. - @param This Calling context. - @param Handle Parent Handle. - @param DiskIo Parent DiskIo interface. - @param BlockIo Parent BlockIo interface. - @param DevicePath Parent Device Path. + @param[in] This Calling context. + @param[in] Handle Parent Handle. + @param[in] DiskIo Parent DiskIo interface. + @param[in] BlockIo Parent BlockIo interface. + @param[in] BlockIo2 Parent BlockIo2 interface. + @param[in] DevicePath Parent Device Path. @retval EFI_SUCCESS A child handle was added. @retval EFI_MEDIA_CHANGED Media change was detected. @@ -396,6 +409,7 @@ PartitionInstallMbrChildHandles ( IN EFI_HANDLE Handle, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ); @@ -406,6 +420,7 @@ EFI_STATUS IN EFI_HANDLE Handle, IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ); diff --git a/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf b/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf index 45a0e0d73b..cf5090fb7c 100644 --- a/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf +++ b/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf @@ -7,7 +7,7 @@ # The partition of physical BlockIo device supported is one of legacy MBR, GPT, # and "El Torito" partitions. # -# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2011, 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 @@ -70,5 +70,6 @@ gEfiDevicePathProtocolGuid ## BY_START gEfiDiskIoProtocolGuid ## BY_START gEfiBlockIoProtocolGuid ## TO_START + gEfiBlockIo2ProtocolGuid ## TO_START gEfiDevicePathProtocolGuid ## TO_START gEfiDiskIoProtocolGuid ## TO_START diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index c6c6e67a13..231fd1af95 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -894,6 +894,9 @@ ## Include/Protocol/BlockIo.h gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }} + ## Include/Protocol/BlockIo2.h + gEfiBlockIo2ProtocolGuid = { 0xa77b2472, 0xe282, 0x4e9f, {0xa2, 0x45, 0xc2, 0xc0, 0xe2, 0x7b, 0xbc, 0xc1 }} + ## Include/Protocol/UnicodeCollation.h gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }} -- 2.39.2