Add BlockIO2 Protocol.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11606 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
qianouyang 2011-05-03 10:31:41 +00:00
parent c89ea31f52
commit 490b5ea10b
17 changed files with 2892 additions and 1188 deletions

View File

@ -184,9 +184,50 @@ AhciWaitMemSet (
return EFI_DEVICE_ERROR; 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 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 PciIo The PCI IO protocol instance.
@param Port The number of port. @param Port The number of port.
@ -206,7 +247,7 @@ AhciCheckDeviceStatus (
IN UINT8 Port IN UINT8 Port
) )
{ {
UINT32 Data; UINT32 Data;
UINT32 Offset; UINT32 Offset;
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS; 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; Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;
if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) { if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {
return EFI_SUCCESS; return EFI_SUCCESS;
} }
return EFI_NOT_READY; return EFI_NOT_READY;
@ -240,7 +281,7 @@ AhciClearPortStatus (
// //
// Clear any error status // Clear any error status
// //
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR; Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset)); AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));
@ -310,8 +351,8 @@ AhciEnableFisReceive (
IN EFI_PCI_IO_PROTOCOL *PciIo, IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Port, IN UINT8 Port,
IN UINT64 Timeout IN UINT64 Timeout
) )
{ {
UINT32 Offset; UINT32 Offset;
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; 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)); AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));
return AhciWaitMemSet ( return AhciWaitMemSet (
PciIo, PciIo,
Offset, Offset,
EFI_AHCI_PORT_CMD_FR, EFI_AHCI_PORT_CMD_FR,
0, 0,
Timeout Timeout
); );
} }
@ -412,7 +453,7 @@ AhciBuildCommand (
IN UINT64 DataLength IN UINT64 DataLength
) )
{ {
UINT64 BaseAddr; UINT64 BaseAddr;
UINT64 PrdtNumber; UINT64 PrdtNumber;
UINT64 PrdtIndex; UINT64 PrdtIndex;
UINTN RemainedData; UINTN RemainedData;
@ -436,7 +477,7 @@ AhciBuildCommand (
BaseAddr = Data64.Uint64; 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)); ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));
@ -466,7 +507,7 @@ AhciBuildCommand (
CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber; CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;
for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) { 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; AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;
} else { } else {
AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1; AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;
@ -475,7 +516,7 @@ AhciBuildCommand (
Data64.Uint64 = (UINT64)MemAddr; Data64.Uint64 = (UINT64)MemAddr;
AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba = Data64.Uint32.Lower32; AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba = Data64.Uint32.Lower32;
AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32; 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; MemAddr += EFI_AHCI_MAX_DATA_PER_PRDT;
} }
@ -543,18 +584,21 @@ AhciBuildCommandFis (
/** /**
Start a PIO data transfer on specific port. Start a PIO data transfer on specific port.
@param PciIo The PCI IO protocol instance. @param[in] PciIo The PCI IO protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS. @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
@param Port The number of port. @param[in] Port The number of port.
@param PortMultiplier The timeout value of stop. @param[in] PortMultiplier The timeout value of stop.
@param AtapiCommand The atapi command will be used for the transfer. @param[in] AtapiCommand The atapi command will be used for the
@param AtapiCommandLength The length of the atapi command. transfer.
@param Read The transfer direction. @param[in] AtapiCommandLength The length of the atapi command.
@param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. @param[in] Read The transfer direction.
@param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
@param MemoryAddr The pointer to the data buffer. @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
@param DataCount The data count to be transferred. @param[in, out] MemoryAddr The pointer to the data buffer.
@param Timeout The timeout value of non data transfer. @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_DEVICE_ERROR The PIO data transfer abort with error occurs.
@retval EFI_TIMEOUT The operation is time out. @retval EFI_TIMEOUT The operation is time out.
@ -576,7 +620,8 @@ AhciPioTransfer (
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
IN OUT VOID *MemoryAddr, IN OUT VOID *MemoryAddr,
IN UINT32 DataCount, IN UINT32 DataCount,
IN UINT64 Timeout IN UINT64 Timeout,
IN ATA_NONBLOCK_TASK *Task
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
@ -639,17 +684,17 @@ AhciPioTransfer (
); );
Status = AhciStartCommand ( Status = AhciStartCommand (
PciIo, PciIo,
Port, Port,
0, 0,
Timeout Timeout
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Exit; 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); FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);
// //
@ -668,7 +713,7 @@ AhciPioTransfer (
// //
MicroSecondDelay(100); MicroSecondDelay(100);
Delay--; Delay--;
} while (Delay > 0); } while (Delay > 0);
if (Delay == 0) { if (Delay == 0) {
@ -689,30 +734,30 @@ AhciPioTransfer (
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Exit; goto Exit;
} }
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS; Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
Status = AhciWaitMemSet ( Status = AhciWaitMemSet (
PciIo, PciIo,
Offset, Offset,
EFI_AHCI_PORT_IS_PSS, EFI_AHCI_PORT_IS_PSS,
EFI_AHCI_PORT_IS_PSS, EFI_AHCI_PORT_IS_PSS,
Timeout Timeout
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Exit; goto Exit;
} }
Exit: Exit:
AhciStopCommand ( AhciStopCommand (
PciIo, PciIo,
Port, Port,
Timeout Timeout
); );
AhciDisableFisReceive ( AhciDisableFisReceive (
PciIo, PciIo,
Port, Port,
Timeout Timeout
); );
@ -730,29 +775,32 @@ Exit:
/** /**
Start a DMA data transfer on specific port Start a DMA data transfer on specific port
@param PciIo The PCI IO protocol instance. @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS. @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
@param Port The number of port. @param[in] Port The number of port.
@param PortMultiplier The timeout value of stop. @param[in] PortMultiplier The timeout value of stop.
@param AtapiCommand The atapi command will be used for the transfer. @param[in] AtapiCommand The atapi command will be used for the
@param AtapiCommandLength The length of the atapi command. transfer.
@param Read The transfer direction. @param[in] AtapiCommandLength The length of the atapi command.
@param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. @param[in] Read The transfer direction.
@param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
@param MemoryAddr The pointer to the data buffer. @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.
@param DataCount The data count to be transferred. @param[in, out] MemoryAddr The pointer to the data buffer.
@param Timeout The timeout value of non data transfer. @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_DEVICE_ERROR The DMA data transfer abort with error occurs.
@retval EFI_TIMEOUT The operation is time out. @retval EFI_TIMEOUT The operation is time out.
@retval EFI_UNSUPPORTED The device is not ready for transfer. @retval EFI_UNSUPPORTED The device is not ready for transfer.
@retval EFI_SUCCESS The DMA data transfer executes successfully. @retval EFI_SUCCESS The DMA data transfer executes successfully.
**/ **/
EFI_STATUS EFI_STATUS
EFIAPI EFIAPI
AhciDmaTransfer ( AhciDmaTransfer (
IN EFI_PCI_IO_PROTOCOL *PciIo, IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
IN EFI_AHCI_REGISTERS *AhciRegisters, IN EFI_AHCI_REGISTERS *AhciRegisters,
IN UINT8 Port, IN UINT8 Port,
IN UINT8 PortMultiplier, IN UINT8 PortMultiplier,
@ -763,7 +811,8 @@ AhciDmaTransfer (
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
IN OUT VOID *MemoryAddr, IN OUT VOID *MemoryAddr,
IN UINTN DataCount, IN UINTN DataCount,
IN UINT64 Timeout IN UINT64 Timeout,
IN ATA_NONBLOCK_TASK *Task
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
@ -775,141 +824,224 @@ AhciDmaTransfer (
EFI_AHCI_COMMAND_FIS CFis; EFI_AHCI_COMMAND_FIS CFis;
EFI_AHCI_COMMAND_LIST CmdList; EFI_AHCI_COMMAND_LIST CmdList;
if (Read) { EFI_PCI_IO_PROTOCOL *PciIo;
Flag = EfiPciIoOperationBusMasterWrite; EFI_TPL OldTpl;
} else {
Flag = EfiPciIoOperationBusMasterRead; Map = NULL;
PciIo = Instance->PciIo;
if (PciIo == NULL) {
return EFI_INVALID_PARAMETER;
} }
// //
// construct command list and command table with pci bus address // Before starting the Blocking BlockIO operation, push to finish all non-blocking
// BlockIO tasks.
// Delay 100us to simulate the blocking time out checking.
// //
MapLength = DataCount; while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {
Status = PciIo->Map ( OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
PciIo, AsyncNonBlockingTransferRoutine (NULL, Instance);
Flag, gBS->RestoreTPL (OldTpl);
MemoryAddr, //
&MapLength, // Stall for 100us.
&PhyAddr, //
&Map MicroSecondDelay (100);
);
if (EFI_ERROR (Status) || (DataCount != MapLength)) {
return EFI_OUT_OF_RESOURCES;
} }
// if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {
// Package read needed //
// // Mark the Task to indicate that it has been started.
AhciBuildCommandFis (&CFis, AtaCommandBlock); //
if (Task != NULL) {
Task->IsStart = TRUE;
Task->RetryTimes = (UINT32) (DivU64x32(Timeout, 1000) + 1);
}
if (Read) {
Flag = EfiPciIoOperationBusMasterWrite;
} else {
Flag = EfiPciIoOperationBusMasterRead;
}
ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST)); //
// Construct command list and command table with pci bus address.
//
MapLength = DataCount;
Status = PciIo->Map (
PciIo,
Flag,
MemoryAddr,
&MapLength,
&PhyAddr,
&Map
);
CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4; if (EFI_ERROR (Status) || (DataCount != MapLength)) {
CmdList.AhciCmdW = Read ? 0 : 1; return EFI_OUT_OF_RESOURCES;
}
AhciBuildCommand ( if (Task != NULL) {
PciIo, Task->Map = Map;
AhciRegisters, }
Port, //
PortMultiplier, // Package read needed
&CFis, //
&CmdList, AhciBuildCommandFis (&CFis, AtaCommandBlock);
AtapiCommand,
AtapiCommandLength, ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
0,
(VOID *)(UINTN)PhyAddr, CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
DataCount CmdList.AhciCmdW = Read ? 0 : 1;
);
AhciBuildCommand (
Status = AhciStartCommand ( PciIo,
PciIo, AhciRegisters,
Port, Port,
0, PortMultiplier,
Timeout &CFis,
); &CmdList,
if (EFI_ERROR (Status)) { AtapiCommand,
goto Exit; AtapiCommandLength,
} 0,
(VOID *)(UINTN)PhyAddr,
// DataCount
// Wait device PRD processed );
//
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS; Status = AhciStartCommand (
Status = AhciWaitMemSet ( PciIo,
PciIo, Port,
Offset, 0,
EFI_AHCI_PORT_IS_DPS, Timeout
EFI_AHCI_PORT_IS_DPS, );
Timeout if (EFI_ERROR (Status)) {
); goto Exit;
}
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 // Wait for command compelte
// //
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI; Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
Status = AhciWaitMemSet ( if (Task != NULL) {
PciIo, //
Offset, // For Non-blocking
0xFFFFFFFF, //
0, Status = AhciCheckMemSet (
Timeout PciIo,
); Offset,
0xFFFFFFFF,
0,
(UINTN *) (&Task->RetryTimes)
);
} else {
Status = AhciWaitMemSet (
PciIo,
Offset,
0xFFFFFFFF,
0,
Timeout
);
}
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Exit; goto Exit;
} }
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS; Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
Status = AhciWaitMemSet (
PciIo, if (Task != NULL) {
Offset, //
EFI_AHCI_PORT_IS_DHRS, // For Non-blocking
EFI_AHCI_PORT_IS_DHRS, //
Timeout 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)) { if (EFI_ERROR (Status)) {
goto Exit; goto Exit;
} }
Exit: Exit:
AhciStopCommand ( //
PciIo, // For Blocking mode, the command should be stopped, the Fis should be disabled
Port, // and the PciIo should be unmapped.
Timeout // 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 ( AhciDisableFisReceive (
PciIo, PciIo,
Port, Port,
Timeout Timeout
); );
PciIo->Unmap (
PciIo,
(Task != NULL) ? Task->Map : Map
);
if (Task != NULL) {
Task->Packet->Asb->AtaStatus = 0x01;
}
}
PciIo->Unmap (
PciIo,
Map
);
AhciDumpPortStatus (PciIo, Port, AtaStatusBlock); AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);
return Status; return Status;
} }
/** /**
Start a non data transfer on specific port. Start a non data transfer on specific port.
@param PciIo The PCI IO protocol instance. @param[in] PciIo The PCI IO protocol instance.
@param AhciRegisters The pointer to the EFI_AHCI_REGISTERS. @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
@param Port The number of port. @param[in] Port The number of port.
@param PortMultiplier The timeout value of stop. @param[in] PortMultiplier The timeout value of stop.
@param AtapiCommand The atapi command will be used for the transfer. @param[in] AtapiCommand The atapi command will be used for the
@param AtapiCommandLength The length of the atapi command. transfer.
@param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data. @param[in] AtapiCommandLength The length of the atapi command.
@param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data. @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.
@param Timeout The timeout value of non data transfer. @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_DEVICE_ERROR The non data transfer abort with error occurs.
@retval EFI_TIMEOUT The operation is time out. @retval EFI_TIMEOUT The operation is time out.
@ -928,15 +1060,16 @@ AhciNonDataTransfer (
IN UINT8 AtapiCommandLength, IN UINT8 AtapiCommandLength,
IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, 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; UINTN FisBaseAddr;
UINT32 Offset; UINT32 Offset;
UINT32 Value; UINT32 Value;
UINT32 Delay; UINT32 Delay;
EFI_AHCI_COMMAND_FIS CFis; EFI_AHCI_COMMAND_FIS CFis;
EFI_AHCI_COMMAND_LIST CmdList; EFI_AHCI_COMMAND_LIST CmdList;
@ -961,18 +1094,18 @@ AhciNonDataTransfer (
0, 0,
NULL, NULL,
0 0
); );
Status = AhciStartCommand ( Status = AhciStartCommand (
PciIo, PciIo,
Port, Port,
0, 0,
Timeout Timeout
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Exit; goto Exit;
} }
// //
// Wait device sends the Response Fis // Wait device sends the Response Fis
// //
@ -993,7 +1126,7 @@ AhciNonDataTransfer (
// //
MicroSecondDelay(100); MicroSecondDelay(100);
Delay --; Delay --;
} while (Delay > 0); } while (Delay > 0);
if (Delay == 0) { if (Delay == 0) {
@ -1009,17 +1142,17 @@ AhciNonDataTransfer (
0xFFFFFFFF, 0xFFFFFFFF,
0, 0,
Timeout Timeout
); );
Exit: Exit:
AhciStopCommand ( AhciStopCommand (
PciIo, PciIo,
Port, Port,
Timeout Timeout
); );
AhciDisableFisReceive ( AhciDisableFisReceive (
PciIo, PciIo,
Port, Port,
Timeout Timeout
); );
@ -1056,7 +1189,7 @@ AhciStopCommand (
Data = AhciReadReg (PciIo, Offset); Data = AhciReadReg (PciIo, Offset);
if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) { 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) { if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {
@ -1064,22 +1197,22 @@ AhciStopCommand (
} }
return AhciWaitMemSet ( return AhciWaitMemSet (
PciIo, PciIo,
Offset, Offset,
EFI_AHCI_PORT_CMD_CR, EFI_AHCI_PORT_CMD_CR,
0, 0,
Timeout Timeout
); );
} }
/** /**
Start command for give slot on specific port. Start command for give slot on specific port.
@param PciIo The PCI IO protocol instance. @param PciIo The PCI IO protocol instance.
@param Port The number of port. @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. @param Timeout The timeout value of start.
@retval EFI_DEVICE_ERROR The command start unsuccessfully. @retval EFI_DEVICE_ERROR The command start unsuccessfully.
@retval EFI_TIMEOUT The operation is time out. @retval EFI_TIMEOUT The operation is time out.
@retval EFI_SUCCESS The command start successfully. @retval EFI_SUCCESS The command start successfully.
@ -1119,14 +1252,14 @@ AhciStartCommand (
Port, Port,
Timeout Timeout
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return Status; return Status;
} }
Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
PortStatus = AhciReadReg (PciIo, Offset); PortStatus = AhciReadReg (PciIo, Offset);
StartCmd = 0; StartCmd = 0;
if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) { if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {
StartCmd = AhciReadReg (PciIo, Offset); StartCmd = AhciReadReg (PciIo, Offset);
@ -1143,12 +1276,12 @@ AhciStartCommand (
AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL); AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL);
AhciWaitMemSet ( AhciWaitMemSet (
PciIo, PciIo,
Offset, Offset,
EFI_AHCI_PORT_CMD_COL, EFI_AHCI_PORT_CMD_COL,
0, 0,
Timeout Timeout
); );
} }
} }
@ -1190,8 +1323,8 @@ AhciPortReset (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
UINT32 Offset; UINT32 Offset;
AhciClearPortStatus (PciIo, Port); AhciClearPortStatus (PciIo, Port);
AhciStopCommand (PciIo, Port, Timeout); AhciStopCommand (PciIo, Port, Timeout);
@ -1205,14 +1338,14 @@ AhciPortReset (
AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT); 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); MicroSecondDelay (5000);
AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK); 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); MicroSecondDelay (5000);
@ -1226,7 +1359,7 @@ AhciPortReset (
EFI_AHCI_PORT_SSTS_DET_MASK, EFI_AHCI_PORT_SSTS_DET_MASK,
EFI_AHCI_PORT_SSTS_DET_PCE, EFI_AHCI_PORT_SSTS_DET_PCE,
Timeout Timeout
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return Status; return Status;
@ -1240,11 +1373,10 @@ AhciPortReset (
/** /**
Do AHCI HBA reset. Do AHCI HBA reset.
@param PciIo The PCI IO protocol instance. @param PciIo The PCI IO protocol instance.
@param Timeout The timeout value of reset. @param Timeout The timeout value of reset.
@retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset. @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
@retval EFI_TIMEOUT The reset operation is time out. @retval EFI_TIMEOUT The reset operation is time out.
@retval EFI_SUCCESS AHCI controller is reset successfully. @retval EFI_SUCCESS AHCI controller is reset successfully.
@ -1340,7 +1472,8 @@ AhciAtaSmartReturnStatusCheck (
0, 0,
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
@ -1390,7 +1523,7 @@ AhciAtaSmartSupport (
IN EFI_AHCI_REGISTERS *AhciRegisters, IN EFI_AHCI_REGISTERS *AhciRegisters,
IN UINT8 Port, IN UINT8 Port,
IN UINT8 PortMultiplier, IN UINT8 PortMultiplier,
IN EFI_IDENTIFY_DATA *IdentifyData, IN EFI_IDENTIFY_DATA *IdentifyData,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock
) )
{ {
@ -1430,7 +1563,8 @@ AhciAtaSmartSupport (
0, 0,
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
@ -1455,7 +1589,8 @@ AhciAtaSmartSupport (
0, 0,
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
if (!EFI_ERROR (Status)) { 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)); Port, PortMultiplier));
} }
@ -1511,7 +1646,7 @@ AhciIdentify (
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK)); ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK)); ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE; AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
AtaCommandBlock.AtaSectorCount = 1; AtaCommandBlock.AtaSectorCount = 1;
@ -1527,7 +1662,8 @@ AhciIdentify (
&AtaStatusBlock, &AtaStatusBlock,
Buffer, Buffer,
sizeof (EFI_IDENTIFY_DATA), sizeof (EFI_IDENTIFY_DATA),
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
return Status; return Status;
@ -1565,7 +1701,7 @@ AhciIdentifyPacket (
if (PciIo == NULL || AhciRegisters == NULL) { if (PciIo == NULL || AhciRegisters == NULL) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK)); ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK)); ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
@ -1584,7 +1720,8 @@ AhciIdentifyPacket (
&AtaStatusBlock, &AtaStatusBlock,
Buffer, Buffer,
sizeof (EFI_IDENTIFY_DATA), sizeof (EFI_IDENTIFY_DATA),
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
return Status; return Status;
@ -1623,7 +1760,7 @@ AhciDeviceSetFeature (
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK)); ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK)); ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));
AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES; AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;
AtaCommandBlock.AtaFeatures = (UINT8) Feature; AtaCommandBlock.AtaFeatures = (UINT8) Feature;
AtaCommandBlock.AtaFeaturesExp = (UINT8) (Feature >> 8); AtaCommandBlock.AtaFeaturesExp = (UINT8) (Feature >> 8);
@ -1641,7 +1778,8 @@ AhciDeviceSetFeature (
0, 0,
&AtaCommandBlock, &AtaCommandBlock,
&AtaStatusBlock, &AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
return Status; return Status;
@ -1708,7 +1846,7 @@ AhciPacketCommandExecute (
Read = FALSE; Read = FALSE;
} }
if (Length == 0) { if (Length == 0) {
Status = AhciNonDataTransfer ( Status = AhciNonDataTransfer (
PciIo, PciIo,
AhciRegisters, AhciRegisters,
@ -1718,7 +1856,8 @@ AhciPacketCommandExecute (
Packet->CdbLength, Packet->CdbLength,
&AtaCommandBlock, &AtaCommandBlock,
&AtaStatusBlock, &AtaStatusBlock,
Packet->Timeout Packet->Timeout,
NULL
); );
} else { } else {
// //
@ -1742,7 +1881,8 @@ AhciPacketCommandExecute (
&AtaStatusBlock, &AtaStatusBlock,
Buffer, Buffer,
Length, Length,
Packet->Timeout Packet->Timeout,
NULL
); );
if (!EFI_ERROR (Status)) { if (!EFI_ERROR (Status)) {
break; break;

View File

@ -1,7 +1,7 @@
/** @file /** @file
Header file for AHCI mode of ATA host controller. Header file for AHCI mode of ATA host controller.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 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_BDE BIT19
#define EFI_AHCI_PORT_SERR_DE BIT20 #define EFI_AHCI_PORT_SERR_DE BIT20
#define EFI_AHCI_PORT_SERR_CRCE BIT21 #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_LSE BIT23
#define EFI_AHCI_PORT_SERR_TSTE BIT24 #define EFI_AHCI_PORT_SERR_TSTE BIT24
#define EFI_AHCI_PORT_SERR_UFT BIT25 #define EFI_AHCI_PORT_SERR_UFT BIT25
@ -348,117 +348,5 @@ AhciStopCommand (
IN UINT64 Timeout 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 #endif

View File

@ -39,7 +39,7 @@ ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = {
// bits. // bits.
// Note that the driver doesn't support AtaPassThru non blocking I/O. // 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 // IoAlign
// //
@ -98,7 +98,12 @@ ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = {
0, // PreviousPort 0, // PreviousPort
0, // PreviousPortMultiplier 0, // PreviousPortMultiplier
0, // PreviousTargetId 0, // PreviousTargetId
0 // PreviousLun 0, // PreviousLun
NULL, // Timer event
{ // NonBlocking TaskList
NULL,
NULL
}
}; };
ATAPI_DEVICE_PATH mAtapiDevicePathTemplate = { ATAPI_DEVICE_PATH mAtapiDevicePathTemplate = {
@ -132,12 +137,304 @@ UINT8 mScsiId[TARGET_MAX_BYTES] = {
0xFF, 0xFF, 0xFF, 0xFF 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. 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. @param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully. @retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some error occurs when executing this entry point. @retval other Some error occurs when executing this entry point.
@ -266,7 +563,7 @@ AtaAtapiPassThruSupported (
// //
return Status; return Status;
} }
// //
// Close the I/O Abstraction(s) used to perform the supported test // 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 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
EFI_DEVICE_PATH_PROTOCOL. EFI_DEVICE_PATH_PROTOCOL.
3. Prior to calling Start(), the Supported() function for the driver specified by This must 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] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param[in] ControllerHandle The handle of the controller to start. This handle @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 @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 parameter is ignored by device drivers, and is optional for bus
drivers. For a bus driver, if this parameter is NULL, then handles 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 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 not the End of Device Path Node, then only the handle for the
child device specified by the first Device Path Node of child device specified by the first Device Path Node of
@ -446,6 +743,28 @@ AtaAtapiPassThruStart (
Instance->AtaPassThru.Mode = &Instance->AtaPassThruMode; Instance->AtaPassThru.Mode = &Instance->AtaPassThruMode;
Instance->ExtScsiPassThru.Mode = &Instance->ExtScsiPassThruMode; Instance->ExtScsiPassThru.Mode = &Instance->ExtScsiPassThruMode;
InitializeListHead(&Instance->DeviceList); 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. // Enumerate all inserted ATA devices.
@ -475,6 +794,10 @@ ErrorExit:
); );
} }
if (Instance->TimerEvent != NULL) {
gBS->CloseEvent (Instance->TimerEvent);
}
// //
// Remove all inserted ATA devices. // Remove all inserted ATA devices.
// //
@ -542,13 +865,22 @@ AtaAtapiPassThruStop (
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR; return EFI_DEVICE_ERROR;
} }
Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS(AtaPassThru); Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (AtaPassThru);
PciIo = Instance->PciIo;
//
// 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. // Disable this ATA host controller.
// //
PciIo = Instance->PciIo;
Status = PciIo->Attributes ( Status = PciIo->Attributes (
PciIo, PciIo,
EfiPciIoAttributeOperationSupported, EfiPciIoAttributeOperationSupported,
@ -672,7 +1004,7 @@ SearchDeviceInfoList (
} }
Node = GetNextNode (&Instance->DeviceList, Node); Node = GetNextNode (&Instance->DeviceList, Node);
} }
return NULL; 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. Enumerate all attached ATA devices at IDE mode or AHCI mode separately.
@ -863,17 +1231,16 @@ AtaPassThruPassThru (
IN UINT16 PortMultiplierPort, IN UINT16 PortMultiplierPort,
IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet, IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,
IN EFI_EVENT Event OPTIONAL IN EFI_EVENT Event OPTIONAL
) )
{ {
EFI_STATUS Status;
ATA_ATAPI_PASS_THRU_INSTANCE *Instance; ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
EFI_ATA_PASS_THRU_CMD_PROTOCOL Protocol;
EFI_ATA_HC_WORK_MODE Mode;
LIST_ENTRY *Node; LIST_ENTRY *Node;
EFI_ATA_DEVICE_INFO *DeviceInfo; EFI_ATA_DEVICE_INFO *DeviceInfo;
EFI_IDENTIFY_DATA *IdentifyData; EFI_IDENTIFY_DATA *IdentifyData;
UINT64 Capacity; UINT64 Capacity;
UINT32 MaxSectorCount; UINT32 MaxSectorCount;
ATA_NONBLOCK_TASK *Task;
EFI_TPL OldTpl;
Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This); Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);
@ -940,173 +1307,37 @@ AtaPassThruPassThru (
return EFI_BAD_BUFFER_SIZE; return EFI_BAD_BUFFER_SIZE;
} }
Status = EFI_UNSUPPORTED; //
Protocol = Packet->Protocol; // 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;
Mode = Instance->Mode; OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
switch (Mode) { InsertTailList (&Instance->NonBlockingTaskList, &Task->Link);
case EfiAtaIdeMode: gBS->RestoreTPL (OldTpl);
//
// 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;
default: return EFI_SUCCESS;
Status = EFI_DEVICE_ERROR; } else {
break; return AtaPassThruPassThruExecute (
Port,
PortMultiplierPort,
Packet,
Instance,
NULL
);
} }
return Status;
} }
/** /**
@ -1197,7 +1428,7 @@ AtaPassThruGetNextPort (
// //
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
Exit: Exit:
// //
// Update the PreviousPort and PreviousPortMultiplier. // Update the PreviousPort and PreviousPortMultiplier.
@ -1216,20 +1447,20 @@ Exit:
The GetNextDevice() function retrieves the port multiplier port number of an ATA device The GetNextDevice() function retrieves the port multiplier port number of an ATA device
present on a port of an ATA controller. present on a port of an ATA controller.
If PortMultiplierPort points to a port multiplier port number value that was returned on a 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 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 on the port of the ATA controller is returned in PortMultiplierPort, and EFI_SUCCESS is
returned. returned.
If PortMultiplierPort points to 0xFFFF, then the port multiplier port number of the first 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 ATA device on port of the ATA controller is returned in PortMultiplierPort and
EFI_SUCCESS is returned. EFI_SUCCESS is returned.
If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort 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 was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
is returned. is returned.
If PortMultiplierPort is the port multiplier port number of the last ATA device on the port of 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. the ATA controller, then EFI_NOT_FOUND is returned.
@ -1309,7 +1540,7 @@ AtaPassThruGetNextDevice (
// //
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
Exit: Exit:
// //
// Update the PreviousPort and PreviousPortMultiplier. // Update the PreviousPort and PreviousPortMultiplier.
@ -1377,7 +1608,7 @@ AtaPassThruBuildDevicePath (
if (Node == NULL) { if (Node == NULL) {
return EFI_NOT_FOUND; return EFI_NOT_FOUND;
} }
if (Instance->Mode == EfiAtaIdeMode) { if (Instance->Mode == EfiAtaIdeMode) {
DevicePathNode = AllocateCopyPool (sizeof (ATAPI_DEVICE_PATH), &mAtapiDevicePathTemplate); DevicePathNode = AllocateCopyPool (sizeof (ATAPI_DEVICE_PATH), &mAtapiDevicePathTemplate);
if (DevicePathNode == NULL) { 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 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 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 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 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 @param Target On input, a pointer to the Target ID (an array of size
@ -1840,7 +2071,7 @@ Exit:
Instance->PreviousLun = *Lun; Instance->PreviousLun = *Lun;
return EFI_SUCCESS; return EFI_SUCCESS;
} }
/** /**
Used to allocate and build a device path node for a SCSI device on a SCSI channel. 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; return EFI_UNSUPPORTED;
} }
/** /**
Resets a SCSI logical unit that is connected to a SCSI channel. Resets a SCSI logical unit that is connected to a SCSI channel.
@ -2061,7 +2292,7 @@ ExtScsiPassThruResetTargetLun (
) )
{ {
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
/** /**
Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either 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; Instance->PreviousTargetId = *Target16;
return EFI_SUCCESS; return EFI_SUCCESS;
} }

View File

@ -1,7 +1,7 @@
/** @file /** @file
Header file for ATA/ATAPI PASS THRU driver. Header file for ATA/ATAPI PASS THRU driver.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 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_PASS_THRU_SIGNATURE SIGNATURE_32 ('a', 'a', 'p', 't')
#define ATA_ATAPI_DEVICE_SIGNATURE SIGNATURE_32 ('a', 'd', 'e', 'v') #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 { typedef enum {
EfiAtaIdeMode, EfiAtaIdeMode,
@ -111,9 +114,33 @@ typedef struct {
// //
UINT16 PreviousTargetId; UINT16 PreviousTargetId;
UINT64 PreviousLun; UINT64 PreviousLun;
//
// For Non-blocking.
//
EFI_EVENT TimerEvent;
LIST_ENTRY NonBlockingTaskList;
} ATA_ATAPI_PASS_THRU_INSTANCE; } 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. // Timeout value which uses 100ns as a unit.
// It means 3 second span. // It means 3 second span.
@ -142,6 +169,14 @@ typedef struct {
Link, \ Link, \
ATA_ATAPI_DEVICE_SIGNATURE \ 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. 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 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. Enumerate all attached ATA devices at IDE mode or AHCI mode separately.
@ -470,6 +517,21 @@ EnumerateAttachedDevice (
IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance 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 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, 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 The GetNextDevice() function retrieves the port multiplier port number of an ATA device
present on a port of an ATA controller. present on a port of an ATA controller.
If PortMultiplierPort points to a port multiplier port number value that was returned on a 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 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 on the port of the ATA controller is returned in PortMultiplierPort, and EFI_SUCCESS is
returned. returned.
If PortMultiplierPort points to 0xFFFF, then the port multiplier port number of the first 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 ATA device on port of the ATA controller is returned in PortMultiplierPort and
EFI_SUCCESS is returned. EFI_SUCCESS is returned.
If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort 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 was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER
is returned. is returned.
@ -673,6 +735,7 @@ AtaPassThruBuildDevicePath (
@retval EFI_UNSUPPORTED This driver does not support the device path node type in DevicePath. @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 @retval EFI_NOT_FOUND A valid translation from DevicePath to a port number and port multiplier
port number does not exist. port number does not exist.
**/ **/
EFI_STATUS EFI_STATUS
EFIAPI 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 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 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 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 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 @param Target On input, a pointer to the Target ID (an array of size
@ -918,7 +981,7 @@ EFIAPI
ExtScsiPassThruResetChannel ( ExtScsiPassThruResetChannel (
IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
); );
/** /**
Resets a SCSI logical unit that is connected to a SCSI channel. Resets a SCSI logical unit that is connected to a SCSI channel.
@ -1003,5 +1066,231 @@ AhciModeInitialization (
IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance 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 #endif

View File

@ -1,7 +1,7 @@
/** @file /** @file
Header file for AHCI mode of ATA host controller. Header file for AHCI mode of ATA host controller.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 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. 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[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data
@param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. structure.
@param Buffer A pointer to the source buffer for the data. @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
@param ByteCount The length of the data. @param[in, out] Buffer A pointer to the source buffer for the data.
@param Read Flag used to determine the data transfer direction. @param[in] ByteCount The length of the data.
Read equals 1, means data transferred from device to host; @param[in] Read Flag used to determine the data transfer direction.
Read equals 0, means data transferred from host to device. Read equals 1, means data transferred from device
@param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. to host;Read equals 0, means data transferred
@param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. from host to device.
@param Timeout The time to complete the command. @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_SUCCESS send out the ATA command and device send required data successfully.
@retval EFI_DEVICE_ERROR command sent failed. @retval EFI_DEVICE_ERROR command sent failed.
@ -1148,7 +1152,8 @@ AtaPioDataInOut (
IN BOOLEAN Read, IN BOOLEAN Read,
IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
IN UINT64 Timeout IN UINT64 Timeout,
IN ATA_NONBLOCK_TASK *Task
) )
{ {
UINTN WordCount; UINTN WordCount;
@ -1248,17 +1253,24 @@ Exit:
// //
DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock); DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);
//
// Not support the Non-blocking now,just do the blocking process.
//
return Status; return Status;
} }
/** /**
Send ATA command into device with NON_DATA protocol Send ATA command into device with NON_DATA protocol
@param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure. @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE
@param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. data structure.
@param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
@param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data
@param Timeout The time to complete the command. 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_SUCCESS Reading succeed
@retval EFI_ABORTED Command failed @retval EFI_ABORTED Command failed
@ -1272,7 +1284,8 @@ AtaNonDataCommandIn (
IN EFI_IDE_REGISTERS *IdeRegisters, IN EFI_IDE_REGISTERS *IdeRegisters,
IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
IN UINT64 Timeout IN UINT64 Timeout,
IN ATA_NONBLOCK_TASK *Task
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
@ -1310,24 +1323,123 @@ Exit:
// Dump All Ide registers to ATA_STATUS_BLOCK // Dump All Ide registers to ATA_STATUS_BLOCK
// //
DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock); 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; 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). Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).
@param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure. @param[in] Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data
@param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure. structure.
@param Read Flag used to determine the data transfer direction. @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.
Read equals 1, means data transferred from device to host; @param[in] Read Flag used to determine the data transfer
Read equals 0, means data transferred from host to device. direction. Read equals 1, means data transferred
@param DataBuffer A pointer to the source buffer for the data. from device to host;Read equals 0, means data
@param DataLength The length of the data. transferred from host to device.
@param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure. @param[in] DataBuffer A pointer to the source buffer for the data.
@param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure. @param[in] DataLength The length of the data.
@param Timeout The time to complete the command. @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_SUCCESS the operation is successful.
@retval EFI_OUT_OF_RESOURCES Build PRD table failed @retval EFI_OUT_OF_RESOURCES Build PRD table failed
@ -1338,14 +1450,15 @@ Exit:
EFI_STATUS EFI_STATUS
EFIAPI EFIAPI
AtaUdmaInOut ( AtaUdmaInOut (
IN EFI_PCI_IO_PROTOCOL *PciIo, IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,
IN EFI_IDE_REGISTERS *IdeRegisters, IN EFI_IDE_REGISTERS *IdeRegisters,
IN BOOLEAN Read, IN BOOLEAN Read,
IN VOID *DataBuffer, IN VOID *DataBuffer,
IN UINT64 DataLength, IN UINT64 DataLength,
IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
IN UINT64 Timeout IN UINT64 Timeout,
IN ATA_NONBLOCK_TASK *Task
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
@ -1353,18 +1466,16 @@ AtaUdmaInOut (
UINT16 IoPortForBmis; UINT16 IoPortForBmis;
UINT16 IoPortForBmid; UINT16 IoPortForBmid;
UINT8 RegisterValue;
EFI_ATA_DMA_PRD *PrdBaseAddr;
UINTN PrdTableNum;
UINTN PrdTableSize; UINTN PrdTableSize;
EFI_PHYSICAL_ADDRESS PrdTableMapAddr; EFI_PHYSICAL_ADDRESS PrdTableMapAddr;
VOID *PrdTableMap; VOID *PrdTableMap;
EFI_ATA_DMA_PRD *PrdBaseAddr;
UINTN PrdTableNum;
UINT8 RegisterValue;
UINTN PageCount; UINTN PageCount;
UINTN ByteCount; UINTN ByteCount;
UINTN ByteRemaining; UINTN ByteRemaining;
UINT8 DeviceControl; UINT8 DeviceControl;
VOID *BufferMap; VOID *BufferMap;
@ -1373,14 +1484,36 @@ AtaUdmaInOut (
UINT8 DeviceHead; UINT8 DeviceHead;
UINT8 AtaCommand; 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)) { if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {
return EFI_INVALID_PARAMETER; 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 // The data buffer should be even alignment
// //
@ -1389,163 +1522,187 @@ AtaUdmaInOut (
} }
// //
// Calculate the number of PRD entry. // Set relevant IO Port address.
// Every entry in PRD table can specify a 64K memory region.
// //
PrdTableNum = (UINTN)(RShiftU64(DataLength, 16) + 1);
//
// 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;
}
//
// 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;
}
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;
}
ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);
//
// Map the host address of DataBuffer to DMA master address.
//
if (Read) {
PciIoOperation = EfiPciIoOperationBusMasterWrite;
} else {
PciIoOperation = EfiPciIoOperationBusMasterRead;
}
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;
}
PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);
PrdBaseAddr->ByteCount = (UINT16) 0x0;
ByteRemaining -= 0x10000;
BufferMapAddress += 0x10000;
PrdBaseAddr++;
}
//
// Start to enable the DMA operation
//
DeviceHead = AtaCommandBlock->AtaDeviceHead;
AtaCommand = AtaCommandBlock->AtaCommand;
IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead));
//
// Enable interrupt to support UDMA
//
DeviceControl = 0;
IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);
IoPortForBmic = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET); IoPortForBmic = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET);
IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET); IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);
IoPortForBmid = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMID_OFFSET); IoPortForBmid = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMID_OFFSET);
// //
// Read BMIS register and clear ERROR and INTR bit // For Blocking mode, start the command.
// // For non-blocking mode, when the command is not started, start it, otherwise
RegisterValue = IdeReadPortB(PciIo, IoPortForBmis); // go to check the status.
RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); //
IdeWritePortB(PciIo, IoPortForBmis, RegisterValue); 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);
// //
// Set the base address to BMID register // Make sure that the memory region of PRD table is not cross 64K boundary
// //
IdeWritePortDW(PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr); PrdTableSize = PrdTableNum * sizeof (EFI_ATA_DMA_PRD);
if (PrdTableSize > 0x10000) {
return EFI_INVALID_PARAMETER;
}
// //
// Set BMIC register to identify the operation direction // Allocate buffer for PRD table initialization.
// //
RegisterValue = IdeReadPortB(PciIo, IoPortForBmic); PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);
if (Read) { Status = PciIo->AllocateBuffer (
RegisterValue |= BMIC_NREAD; PciIo,
} else { AllocateAnyPages,
RegisterValue &= ~((UINT8) BMIC_NREAD); EfiBootServicesData,
PageCount,
(VOID **)&PrdBaseAddr,
0
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
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;
}
ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);
//
// Map the host address of DataBuffer to DMA master address.
//
if (Read) {
PciIoOperation = EfiPciIoOperationBusMasterWrite;
} else {
PciIoOperation = EfiPciIoOperationBusMasterRead;
}
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;
}
PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);
PrdBaseAddr->ByteCount = (UINT16) 0x0;
ByteRemaining -= 0x10000;
BufferMapAddress += 0x10000;
PrdBaseAddr++;
}
//
// Start to enable the DMA operation
//
DeviceHead = AtaCommandBlock->AtaDeviceHead;
AtaCommand = AtaCommandBlock->AtaCommand;
IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead));
//
// 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);
//
// Set the base address to BMID register
//
IdeWritePortDW (PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr);
//
// 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);
//
// Issue ATA command
//
Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
goto Exit;
}
//
// Set START bit of BMIC register
//
RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);
RegisterValue |= BMIC_START;
IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);
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;
}
} }
IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);
//
// Issue ATA command
//
Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
goto Exit;
}
//
// 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 // Check the INTERRUPT and ERROR bit of BMIS
@ -1553,70 +1710,72 @@ AtaUdmaInOut (
// it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps). // 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. // So set the variable Count to 2000, for about 2 second Timeout time.
// //
Timeout = 2000; if (Task != NULL) {
while (TRUE) { Status = AtaUdmStatusCheck (PciIo, Task, IoPortForBmis);
RegisterValue = IdeReadPortB(PciIo, IoPortForBmis); } else {
Status = AtaUdmStatusWait (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--;
} }
// //
// 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); if ((Task == NULL) || Status != EFI_NOT_READY) {
RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR); //
IdeWritePortB(PciIo, IoPortForBmis, RegisterValue); // 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 // Read Status Register of IDE device to clear interrupt
// //
RegisterValue = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus); RegisterValue = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus);
// //
// Clear START bit of BMIC register // Clear START bit of BMIC register
// //
RegisterValue = IdeReadPortB(PciIo, IoPortForBmic); RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);
RegisterValue &= ~((UINT8) BMIC_START); RegisterValue &= ~((UINT8) BMIC_START);
IdeWritePortB(PciIo, IoPortForBmic, RegisterValue); IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);
// //
// Disable interrupt of Select device // Disable interrupt of Select device
// //
DeviceControl = IdeReadPortB (PciIo, IdeRegisters->AltOrDev); DeviceControl = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);
DeviceControl |= ATA_CTLREG_IEN_L; DeviceControl |= ATA_CTLREG_IEN_L;
IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl); IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);
// //
// Stall for 10 milliseconds. // Stall for 10 milliseconds.
// //
MicroSecondDelay (10000); MicroSecondDelay (10000);
}
Exit: Exit:
// //
// Free all allocated resource // Free all allocated resource
// //
PciIo->Unmap (PciIo, PrdTableMap); if ((Task == NULL) || Status != EFI_NOT_READY) {
PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr); if (Task != NULL) {
PciIo->Unmap (PciIo, BufferMap); PciIo->Unmap (PciIo, Task->TableMap);
PciIo->FreeBuffer (PciIo, Task->PageCount, Task->MapBaseAddress);
// PciIo->Unmap (PciIo, Task->Map);
// Dump All Ide registers to ATA_STATUS_BLOCK } else {
// PciIo->Unmap (PciIo, PrdTableMap);
DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock); PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);
PciIo->Unmap (PciIo, BufferMap);
}
//
// Dump All Ide registers to ATA_STATUS_BLOCK
//
DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);
}
return Status; return Status;
} }
@ -2021,7 +2180,8 @@ SetDeviceTransferMode (
&Instance->IdeRegisters[Channel], &Instance->IdeRegisters[Channel],
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
return Status; return Status;
@ -2069,7 +2229,8 @@ SetDriveParameters (
&Instance->IdeRegisters[Channel], &Instance->IdeRegisters[Channel],
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
// //
@ -2084,7 +2245,8 @@ SetDriveParameters (
&Instance->IdeRegisters[Channel], &Instance->IdeRegisters[Channel],
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
return Status; return Status;
@ -2132,7 +2294,8 @@ IdeAtaSmartReturnStatusCheck (
&Instance->IdeRegisters[Channel], &Instance->IdeRegisters[Channel],
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
@ -2212,7 +2375,8 @@ IdeAtaSmartSupport (
&Instance->IdeRegisters[Channel], &Instance->IdeRegisters[Channel],
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
if (!EFI_ERROR (Status)) { if (!EFI_ERROR (Status)) {
@ -2233,7 +2397,8 @@ IdeAtaSmartSupport (
&Instance->IdeRegisters[Channel], &Instance->IdeRegisters[Channel],
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
if (!EFI_ERROR (Status)) { if (!EFI_ERROR (Status)) {
Status = IdeAtaSmartReturnStatusCheck ( Status = IdeAtaSmartReturnStatusCheck (
@ -2254,6 +2419,7 @@ IdeAtaSmartSupport (
return ; return ;
} }
/** /**
Sends out an ATA Identify Command to the specified device. Sends out an ATA Identify Command to the specified device.
@ -2274,6 +2440,7 @@ IdeAtaSmartSupport (
@retval EFI_SUCCESS Identify ATA device successfully. @retval EFI_SUCCESS Identify ATA device successfully.
@retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device. @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.
@retval EFI_OUT_OF_RESOURCES Allocate memory failed. @retval EFI_OUT_OF_RESOURCES Allocate memory failed.
**/ **/
EFI_STATUS EFI_STATUS
EFIAPI EFIAPI
@ -2286,10 +2453,10 @@ AtaIdentify (
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_ATA_COMMAND_BLOCK AtaCommandBlock; EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK)); ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE; AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4); AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);
@ -2301,7 +2468,8 @@ AtaIdentify (
TRUE, TRUE,
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
return Status; return Status;
@ -2368,7 +2536,8 @@ AtaIdentifyPacket (
TRUE, TRUE,
&AtaCommandBlock, &AtaCommandBlock,
AtaStatusBlock, AtaStatusBlock,
ATA_ATAPI_TIMEOUT ATA_ATAPI_TIMEOUT,
NULL
); );
return Status; return Status;
@ -2425,7 +2594,7 @@ DetectAndConfigIdeDevice (
IdeInit = Instance->IdeControllerInit; IdeInit = Instance->IdeControllerInit;
PciIo = Instance->PciIo; PciIo = Instance->PciIo;
for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) { for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {
// //
// Send ATA Device Execut Diagnostic command. // Send ATA Device Execut Diagnostic command.
// This command should work no matter DRDY is ready or not // This command should work no matter DRDY is ready or not
@ -2483,7 +2652,7 @@ DetectAndConfigIdeDevice (
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DeviceType = EfiIdeHarddisk; DeviceType = EfiIdeHarddisk;
Status = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL); Status = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);
} }
} }
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
@ -2491,12 +2660,11 @@ DetectAndConfigIdeDevice (
// No device is found at this port // No device is found at this port
// //
continue; continue;
} }
DEBUG ((EFI_D_INFO, "[%a] channel [%a] [%a] device\n", DEBUG ((EFI_D_INFO, "[%a] channel [%a] [%a] device\n",
(IdeChannel == 1) ? "secondary" : "primary ", (IdeDevice == 1) ? "slave " : "master", (IdeChannel == 1) ? "secondary" : "primary ", (IdeDevice == 1) ? "slave " : "master",
DeviceType == EfiIdeCdrom ? "cdrom " : "harddisk")); DeviceType == EfiIdeCdrom ? "cdrom " : "harddisk"));
// //
// If the device is a hard disk, then try to enable S.M.A.R.T feature // If the device is a hard disk, then try to enable S.M.A.R.T feature
// //
@ -2548,7 +2716,7 @@ DetectAndConfigIdeDevice (
continue; continue;
} }
} }
// //
// Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't // 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 // 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.ModeCategory = EFI_ATA_MODE_UDMA;
TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode); TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);
Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL); Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status)); DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
continue; continue;
@ -2568,13 +2736,13 @@ DetectAndConfigIdeDevice (
TransferMode.ModeCategory = EFI_ATA_MODE_MDMA; TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;
TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode; TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;
Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL); Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status)); DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));
continue; continue;
} }
} }
// //
// Set Parameters for the device: // Set Parameters for the device:
// 1) Init // 1) Init
@ -2587,10 +2755,10 @@ DetectAndConfigIdeDevice (
DriveParameters.Sector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->sectors_per_track; DriveParameters.Sector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->sectors_per_track;
DriveParameters.Heads = (UINT8) (((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->heads - 1); DriveParameters.Heads = (UINT8) (((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->heads - 1);
DriveParameters.MultipleSector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->multi_sector_cmd_max_sct_cnt; DriveParameters.MultipleSector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->multi_sector_cmd_max_sct_cnt;
Status = SetDriveParameters (Instance, IdeChannel, IdeDevice, &DriveParameters, NULL); Status = SetDriveParameters (Instance, IdeChannel, IdeDevice, &DriveParameters, NULL);
} }
// //
// Set IDE controller Timing Blocks in the PCI Configuration Space // Set IDE controller Timing Blocks in the PCI Configuration Space
// //

View File

@ -1,7 +1,7 @@
/** @file /** @file
Header file for IDE mode of ATA host controller. Header file for IDE mode of ATA host controller.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 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 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 #endif

View File

@ -44,6 +44,13 @@ ATA_DEVICE gAtaDeviceTemplate = {
AtaBlockIoWriteBlocks, AtaBlockIoWriteBlocks,
AtaBlockIoFlushBlocks AtaBlockIoFlushBlocks
}, },
{ // BlockIo2
NULL,
AtaBlockIoResetEx,
AtaBlockIoReadBlocksEx,
AtaBlockIoWriteBlocksEx,
AtaBlockIoFlushBlocksEx
},
{ // BlockMedia { // BlockMedia
0, // MediaId 0, // MediaId
FALSE, // RemovableMedia FALSE, // RemovableMedia
@ -75,7 +82,8 @@ ATA_DEVICE gAtaDeviceTemplate = {
FALSE, // Lba48Bit FALSE, // Lba48Bit
NULL, // IdentifyData NULL, // IdentifyData
NULL, // ControllerNameTable NULL, // ControllerNameTable
{L'\0', } // ModelName {L'\0', }, // ModelName
{NULL, NULL} // AtaTaskList
}; };
/** /**
@ -135,12 +143,34 @@ ReleaseAtaResources (
IN ATA_DEVICE *AtaDevice IN ATA_DEVICE *AtaDevice
) )
{ {
ATA_BUS_ASYN_TASK *Task;
LIST_ENTRY *Entry;
LIST_ENTRY *DelEntry;
EFI_TPL OldTpl;
FreeUnicodeStringTable (AtaDevice->ControllerNameTable); FreeUnicodeStringTable (AtaDevice->ControllerNameTable);
FreeAlignedBuffer (AtaDevice->Asb, sizeof (*AtaDevice->Asb)); FreeAlignedBuffer (AtaDevice->Asb, sizeof (*AtaDevice->Asb));
FreeAlignedBuffer (AtaDevice->IdentifyData, sizeof (*AtaDevice->IdentifyData)); FreeAlignedBuffer (AtaDevice->IdentifyData, sizeof (*AtaDevice->IdentifyData));
if (AtaDevice->DevicePath != NULL) { if (AtaDevice->DevicePath != NULL) {
FreePool (AtaDevice->DevicePath); 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); FreePool (AtaDevice);
} }
@ -218,10 +248,11 @@ RegisterAtaDevice (
// //
// Initializes ATA device structures and allocates the required buffer. // Initializes ATA device structures and allocates the required buffer.
// //
AtaDevice->BlockIo.Media = &AtaDevice->BlockMedia; AtaDevice->BlockIo.Media = &AtaDevice->BlockMedia;
AtaDevice->AtaBusDriverData = AtaBusDriverData; AtaDevice->BlockIo2.Media = &AtaDevice->BlockMedia;
AtaDevice->DevicePath = DevicePath; AtaDevice->AtaBusDriverData = AtaBusDriverData;
AtaDevice->Port = Port; AtaDevice->DevicePath = DevicePath;
AtaDevice->Port = Port;
AtaDevice->PortMultiplierPort = PortMultiplierPort; AtaDevice->PortMultiplierPort = PortMultiplierPort;
AtaDevice->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->Asb)); AtaDevice->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->Asb));
if (AtaDevice->Asb == NULL) { if (AtaDevice->Asb == NULL) {
@ -234,6 +265,11 @@ RegisterAtaDevice (
goto Done; goto Done;
} }
//
// Initial Ata Task List
//
InitializeListHead (&AtaDevice->AtaTaskList);
// //
// Try to identify the ATA device via the ATA pass through command. // Try to identify the ATA device via the ATA pass through command.
// //
@ -241,7 +277,7 @@ RegisterAtaDevice (
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Done; goto Done;
} }
// //
// Build controller name for Component Name (2) protocol. // Build controller name for Component Name (2) protocol.
// //
@ -281,6 +317,8 @@ RegisterAtaDevice (
AtaDevice->DevicePath, AtaDevice->DevicePath,
&gEfiBlockIoProtocolGuid, &gEfiBlockIoProtocolGuid,
&AtaDevice->BlockIo, &AtaDevice->BlockIo,
&gEfiBlockIo2ProtocolGuid,
&AtaDevice->BlockIo2,
&gEfiDiskInfoProtocolGuid, &gEfiDiskInfoProtocolGuid,
&AtaDevice->DiskInfo, &AtaDevice->DiskInfo,
NULL NULL
@ -334,8 +372,11 @@ UnregisterAtaDevice (
{ {
EFI_STATUS Status; EFI_STATUS Status;
EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO_PROTOCOL *BlockIo;
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
ATA_DEVICE *AtaDevice; ATA_DEVICE *AtaDevice;
EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
BlockIo2 = NULL;
BlockIo = NULL;
Status = gBS->OpenProtocol ( Status = gBS->OpenProtocol (
Handle, Handle,
@ -346,10 +387,30 @@ UnregisterAtaDevice (
EFI_OPEN_PROTOCOL_GET_PROTOCOL EFI_OPEN_PROTOCOL_GET_PROTOCOL
); );
if (EFI_ERROR (Status)) { 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 // Close the child handle
@ -361,12 +422,18 @@ UnregisterAtaDevice (
Handle Handle
); );
//
// The Ata Bus driver installs the BlockIo and BlockIo2 in the DriverBindingStart().
// Here should uninstall both of them.
//
Status = gBS->UninstallMultipleProtocolInterfaces ( Status = gBS->UninstallMultipleProtocolInterfaces (
Handle, Handle,
&gEfiDevicePathProtocolGuid, &gEfiDevicePathProtocolGuid,
AtaDevice->DevicePath, AtaDevice->DevicePath,
&gEfiBlockIoProtocolGuid, &gEfiBlockIoProtocolGuid,
&AtaDevice->BlockIo, &AtaDevice->BlockIo,
&gEfiBlockIo2ProtocolGuid,
&AtaDevice->BlockIo2,
&gEfiDiskInfoProtocolGuid, &gEfiDiskInfoProtocolGuid,
&AtaDevice->DiskInfo, &AtaDevice->DiskInfo,
NULL NULL
@ -385,7 +452,6 @@ UnregisterAtaDevice (
} }
ReleaseAtaResources (AtaDevice); ReleaseAtaResources (AtaDevice);
return Status; return Status;
} }
@ -446,7 +512,7 @@ AtaBusDriverBindingSupported (
EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru; EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;
UINT16 Port; UINT16 Port;
UINT16 PortMultiplierPort; UINT16 PortMultiplierPort;
// //
// Test EFI_ATA_PASS_THRU_PROTOCOL on controller handle. // 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 @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 parameter is ignored by device drivers, and is optional for bus
drivers. For a bus driver, if this parameter is NULL, then handles 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 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 not the End of Device Path Node, then only the handle for the
child device specified by the first Device Path Node of child device specified by the first Device Path Node of
@ -589,7 +655,7 @@ AtaBusDriverBindingStart (
} }
AtaBusDriverData->AtaPassThru = AtaPassThru; AtaBusDriverData->AtaPassThru = AtaPassThru;
AtaBusDriverData->Controller = Controller; AtaBusDriverData->Controller = Controller;
AtaBusDriverData->ParentDevicePath = ParentDevicePath; AtaBusDriverData->ParentDevicePath = ParentDevicePath;
AtaBusDriverData->DriverBindingHandle = This->DriverBindingHandle; AtaBusDriverData->DriverBindingHandle = This->DriverBindingHandle;
@ -628,7 +694,7 @@ AtaBusDriverBindingStart (
// //
break; break;
} }
PortMultiplierPort = 0xFFFF; PortMultiplierPort = 0xFFFF;
while (TRUE) { while (TRUE) {
Status = AtaPassThru->GetNextDevice (AtaPassThru, Port, &PortMultiplierPort); Status = AtaPassThru->GetNextDevice (AtaPassThru, Port, &PortMultiplierPort);
@ -649,7 +715,7 @@ AtaBusDriverBindingStart (
Status = RegisterAtaDevice (AtaBusDriverData,Port, PortMultiplierPort); Status = RegisterAtaDevice (AtaBusDriverData,Port, PortMultiplierPort);
} }
} }
return Status; return Status;
ErrorExit: ErrorExit:
@ -789,7 +855,7 @@ AtaBlockIoReset (
AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This); AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This);
Status = ResetAtaDevice (AtaDevice); Status = ResetAtaDevice (AtaDevice);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR; Status = EFI_DEVICE_ERROR;
@ -803,13 +869,18 @@ AtaBlockIoReset (
/** /**
Read/Write BufferSize bytes from Lba from/into Buffer. Read/Write BufferSize bytes from Lba from/into Buffer.
@param This Indicates a pointer to the calling context. @param[in] This Indicates a pointer to the calling context. Either be
@param MediaId The media ID that the read/write request is for. block I/O or block I/O2.
@param Lba The starting logical block address to be read/written. The caller is @param[in] MediaId The media ID that the read/write request is for.
responsible for reading/writing to only legitimate locations. @param[in] Lba The starting logical block address to be read/written.
@param BufferSize Size of Buffer, must be a multiple of device block size. The caller is responsible for reading/writing to only
@param Buffer A pointer to the destination/source buffer for the data. legitimate locations.
@param IsWrite Indicates whether it is a write operation. @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_SUCCESS The data was read/written correctly to the device.
@retval EFI_WRITE_PROTECTED The device can not be read/written to. @retval EFI_WRITE_PROTECTED The device can not be read/written to.
@ -823,12 +894,14 @@ AtaBlockIoReset (
**/ **/
EFI_STATUS EFI_STATUS
BlockIoReadWrite ( BlockIoReadWrite (
IN EFI_BLOCK_IO_PROTOCOL *This, IN VOID *This,
IN UINT32 MediaId, IN UINT32 MediaId,
IN EFI_LBA Lba, IN EFI_LBA Lba,
IN UINTN BufferSize, IN OUT EFI_BLOCK_IO2_TOKEN *Token,
OUT VOID *Buffer, IN UINTN BufferSize,
IN BOOLEAN IsWrite OUT VOID *Buffer,
IN BOOLEAN IsBlockIo2,
IN BOOLEAN IsWrite
) )
{ {
ATA_DEVICE *AtaDevice; ATA_DEVICE *AtaDevice;
@ -839,21 +912,28 @@ BlockIoReadWrite (
UINTN NumberOfBlocks; UINTN NumberOfBlocks;
UINTN IoAlign; UINTN IoAlign;
// if (IsBlockIo2) {
// Check parameters. Media = ((EFI_BLOCK_IO2_PROTOCOL *) This)->Media;
// AtaDevice = ATA_DEVICE_FROM_BLOCK_IO2 (This);
Media = This->Media; } else {
Media = ((EFI_BLOCK_IO_PROTOCOL *) This)->Media;
AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This);
}
if (MediaId != Media->MediaId) { if (MediaId != Media->MediaId) {
return EFI_MEDIA_CHANGED; return EFI_MEDIA_CHANGED;
} }
//
// Check parameters.
//
if (Buffer == NULL) { if (Buffer == NULL) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
if (BufferSize == 0) { if (BufferSize == 0) {
return EFI_SUCCESS; return EFI_SUCCESS;
} }
BlockSize = Media->BlockSize; BlockSize = Media->BlockSize;
if ((BufferSize % BlockSize) != 0) { if ((BufferSize % BlockSize) != 0) {
@ -871,13 +951,11 @@ BlockIoReadWrite (
} }
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
AtaDevice = ATA_DEVICE_FROM_BLOCK_IO (This);
// //
// Invoke low level AtaDevice Access Routine. // Invoke low level AtaDevice Access Routine.
// //
Status = AccessAtaDevice (AtaDevice, Buffer, Lba, NumberOfBlocks, IsWrite); Status = AccessAtaDevice (AtaDevice, Buffer, Lba, NumberOfBlocks, IsWrite, Token);
gBS->RestoreTPL (OldTpl); gBS->RestoreTPL (OldTpl);
@ -914,7 +992,7 @@ AtaBlockIoReadBlocks (
OUT VOID *Buffer 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 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; 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. Provides inquiry information for the controller type.

View File

@ -22,6 +22,7 @@
#include <Protocol/AtaPassThru.h> #include <Protocol/AtaPassThru.h>
#include <Protocol/BlockIo.h> #include <Protocol/BlockIo.h>
#include <Protocol/BlockIo2.h>
#include <Protocol/DiskInfo.h> #include <Protocol/DiskInfo.h>
#include <Protocol/DevicePath.h> #include <Protocol/DevicePath.h>
@ -59,13 +60,37 @@
// //
// The maximum ATA transaction sector count in 48 bit addressing mode. // 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 // The maximum model name in ATA identify data
// //
#define MAX_MODEL_NAME_LEN 40 #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 // ATA bus data structure for ATA controller
@ -77,46 +102,48 @@ typedef struct {
EFI_HANDLE DriverBindingHandle; EFI_HANDLE DriverBindingHandle;
} ATA_BUS_DRIVER_DATA; } ATA_BUS_DRIVER_DATA;
#define ATA_DEVICE_SIGNATURE SIGNATURE_32 ('A', 'B', 'I', 'D')
// //
// ATA device data structure for each child device // ATA device data structure for each child device
// //
typedef struct { typedef struct {
UINT32 Signature; UINT32 Signature;
EFI_HANDLE Handle; EFI_HANDLE Handle;
EFI_BLOCK_IO_PROTOCOL BlockIo; EFI_BLOCK_IO_PROTOCOL BlockIo;
EFI_BLOCK_IO_MEDIA BlockMedia; EFI_BLOCK_IO2_PROTOCOL BlockIo2;
EFI_DISK_INFO_PROTOCOL DiskInfo; EFI_BLOCK_IO_MEDIA BlockMedia;
EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DISK_INFO_PROTOCOL DiskInfo;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
ATA_BUS_DRIVER_DATA *AtaBusDriverData; ATA_BUS_DRIVER_DATA *AtaBusDriverData;
UINT16 Port; UINT16 Port;
UINT16 PortMultiplierPort; UINT16 PortMultiplierPort;
// //
// Buffer for the execution of ATA pass through protocol // Buffer for the execution of ATA pass through protocol
// //
EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
EFI_ATA_COMMAND_BLOCK Acb; EFI_ATA_COMMAND_BLOCK Acb;
EFI_ATA_STATUS_BLOCK *Asb; EFI_ATA_STATUS_BLOCK *Asb;
BOOLEAN UdmaValid; BOOLEAN UdmaValid;
BOOLEAN Lba48Bit; BOOLEAN Lba48Bit;
// //
// Cached data for ATA identify data // Cached data for ATA identify data
// //
ATA_IDENTIFY_DATA *IdentifyData; ATA_IDENTIFY_DATA *IdentifyData;
EFI_UNICODE_STRING_TABLE *ControllerNameTable; EFI_UNICODE_STRING_TABLE *ControllerNameTable;
CHAR16 ModelName[MAX_MODEL_NAME_LEN + 1]; CHAR16 ModelName[MAX_MODEL_NAME_LEN + 1];
LIST_ENTRY AtaTaskList;
} ATA_DEVICE; } ATA_DEVICE;
#define ATA_DEVICE_FROM_BLOCK_IO(a) CR (a, ATA_DEVICE, BlockIo, ATA_DEVICE_SIGNATURE) #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_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 // Global Variables
@ -125,6 +152,52 @@ extern EFI_DRIVER_BINDING_PROTOCOL gAtaBusDriverBinding;
extern EFI_COMPONENT_NAME_PROTOCOL gAtaBusComponentName; extern EFI_COMPONENT_NAME_PROTOCOL gAtaBusComponentName;
extern EFI_COMPONENT_NAME2_PROTOCOL gAtaBusComponentName2; 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(). Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.ResetDevice().
@ -162,7 +235,6 @@ DiscoverAtaDevice (
IN OUT ATA_DEVICE *AtaDevice IN OUT ATA_DEVICE *AtaDevice
); );
/** /**
Read or write a number of blocks from ATA device. 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 ATA device. It may separate the read/write request into several ATA pass through
transactions. transactions.
@param AtaDevice The ATA child device involved for the operation. @param[in, out] AtaDevice The ATA child device involved for the operation.
@param Buffer The pointer to the current transaction buffer. @param[in, out] Buffer The pointer to the current transaction buffer.
@param StartLba The starting logical block address to be accessed. @param[in] StartLba The starting logical block address to be accessed.
@param NumberOfBlocks The block number or sector count of the transfer. @param[in] NumberOfBlocks The block number or sector count of the transfer.
@param IsWrite Indicates whether it is a write operation. @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. @retval EFI_SUCCESS The data transfer is complete successfully.
@return others Some error occurs when transferring data. @return others Some error occurs when transferring data.
@ -186,7 +259,8 @@ AccessAtaDevice(
IN OUT UINT8 *Buffer, IN OUT UINT8 *Buffer,
IN EFI_LBA StartLba, IN EFI_LBA StartLba,
IN UINTN NumberOfBlocks, 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 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. Provides inquiry information for the controller type.

View File

@ -5,7 +5,7 @@
# in UEFI spec 2.2. It installs Block IO and Disk Info protocol for each ATA device # in UEFI spec 2.2. It installs Block IO and Disk Info protocol for each ATA device
# it enumerates and identifies successfully. # it enumerates and identifies successfully.
# #
# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR> # Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
# #
# This program and the accompanying materials # This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License # are licensed and made available under the terms and conditions of the BSD License
@ -63,6 +63,7 @@
[Protocols] [Protocols]
gEfiDiskInfoProtocolGuid # BY_START gEfiDiskInfoProtocolGuid # BY_START
gEfiBlockIoProtocolGuid # BY_START gEfiBlockIoProtocolGuid # BY_START
gEfiBlockIo2ProtocolGuid # BY_START
gEfiAtaPassThruProtocolGuid # TO_START gEfiAtaPassThruProtocolGuid # TO_START
gEfiDevicePathProtocolGuid # TO_START gEfiDevicePathProtocolGuid # TO_START

View File

@ -5,7 +5,7 @@
It transforms the high level identity, read/write, reset command to ATA pass It transforms the high level identity, read/write, reset command to ATA pass
through command and protocol. through command and protocol.
Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR> Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 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 for an ATA device. It assembles the ATA pass through command packet for ATA
transaction. 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(). @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().
**/ **/
EFI_STATUS EFI_STATUS
AtaDevicePassThru ( 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; EFI_STATUS Status;
@ -90,12 +101,19 @@ AtaDevicePassThru (
EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet; 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; if (TaskPacket != NULL) {
Packet->Asb = AtaDevice->Asb; Packet = TaskPacket;
Packet->Acb = &AtaDevice->Acb; Packet->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->Asb));
Packet->Timeout = ATA_TIMEOUT; 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; AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;
@ -104,7 +122,7 @@ AtaDevicePassThru (
AtaDevice->Port, AtaDevice->Port,
AtaDevice->PortMultiplierPort, AtaDevice->PortMultiplierPort,
Packet, Packet,
NULL Event
); );
// //
// Ensure ATA pass through caller and callee have the same // Ensure ATA pass through caller and callee have the same
@ -257,6 +275,8 @@ IdentifyAtaDevice (
return EFI_UNSUPPORTED; 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 // Check whether the WORD 88 (supported UltraDMA by drive) is valid
// //
@ -319,7 +339,7 @@ IdentifyAtaDevice (
// //
// Get ATA model name from identify data structure. // Get ATA model name from identify data structure.
// //
PrintAtaModelName (AtaDevice); PrintAtaModelName (AtaDevice);
return EFI_SUCCESS; return EFI_SUCCESS;
} }
@ -354,7 +374,7 @@ DiscoverAtaDevice (
// //
Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb)); Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb));
Acb->AtaCommand = ATA_CMD_IDENTIFY_DRIVE; 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. // Prepare for ATA pass through packet.
@ -363,11 +383,12 @@ DiscoverAtaDevice (
Packet->InDataBuffer = AtaDevice->IdentifyData; Packet->InDataBuffer = AtaDevice->IdentifyData;
Packet->InTransferLength = sizeof (*AtaDevice->IdentifyData); Packet->InTransferLength = sizeof (*AtaDevice->IdentifyData);
Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN; 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; Retry = MAX_RETRY_TIMES;
do { do {
Status = AtaDevicePassThru (AtaDevice); Status = AtaDevicePassThru (AtaDevice, NULL, NULL);
if (!EFI_ERROR (Status)) { if (!EFI_ERROR (Status)) {
// //
// The command is issued successfully // The command is issued successfully
@ -389,11 +410,20 @@ DiscoverAtaDevice (
ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru
interface of ATA pass through. interface of ATA pass through.
@param AtaDevice The ATA child device involved for the operation. @param[in, out] AtaDevice The ATA child device involved for the operation.
@param Buffer The pointer to the current transaction buffer. @param[in, out] TaskPacket Pointer to a Pass Thru Command Packet. Optional,
@param StartLba The starting logical block address to be accessed. if it is NULL, blocking mode, and use the packet
@param TransferLength The block number or sector count of the transfer. in AtaDevice. If it is not NULL, non blocking mode,
@param IsWrite Indicates whether it is a write operation. 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. @retval EFI_SUCCESS The data transfer is complete successfully.
@return others Some error occurs when transferring data. @return others Some error occurs when transferring data.
@ -401,11 +431,13 @@ DiscoverAtaDevice (
**/ **/
EFI_STATUS EFI_STATUS
TransferAtaDevice ( TransferAtaDevice (
IN OUT ATA_DEVICE *AtaDevice, IN OUT ATA_DEVICE *AtaDevice,
IN OUT VOID *Buffer, IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL
IN EFI_LBA StartLba, IN OUT VOID *Buffer,
IN UINT32 TransferLength, IN EFI_LBA StartLba,
IN BOOLEAN IsWrite IN UINT32 TransferLength,
IN BOOLEAN IsWrite,
IN EFI_EVENT Event OPTIONAL
) )
{ {
EFI_ATA_COMMAND_BLOCK *Acb; EFI_ATA_COMMAND_BLOCK *Acb;
@ -425,7 +457,7 @@ TransferAtaDevice (
Acb->AtaSectorNumber = (UINT8) StartLba; Acb->AtaSectorNumber = (UINT8) StartLba;
Acb->AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8); Acb->AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);
Acb->AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16); 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; Acb->AtaSectorCount = (UINT8) TransferLength;
if (AtaDevice->Lba48Bit) { if (AtaDevice->Lba48Bit) {
Acb->AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24); Acb->AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);
@ -439,7 +471,12 @@ TransferAtaDevice (
// //
// Prepare for ATA pass through packet. // 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) { if (IsWrite) {
Packet->OutDataBuffer = Buffer; Packet->OutDataBuffer = Buffer;
Packet->OutTransferLength = TransferLength; Packet->OutTransferLength = TransferLength;
@ -447,10 +484,109 @@ TransferAtaDevice (
Packet->InDataBuffer = Buffer; Packet->InDataBuffer = Buffer;
Packet->InTransferLength = TransferLength; Packet->InTransferLength = TransferLength;
} }
Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsWrite]; Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsWrite];
Packet->Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT; Packet->Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;
Packet->Timeout = ATA_TIMEOUT;
return AtaDevicePassThru (AtaDevice); 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);
}
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 ATA device. It may separate the read/write request into several ATA pass through
transactions. transactions.
@param AtaDevice The ATA child device involved for the operation. @param[in, out] AtaDevice The ATA child device involved for the operation.
@param Buffer The pointer to the current transaction buffer. @param[in, out] Buffer The pointer to the current transaction buffer.
@param StartLba The starting logical block address to be accessed. @param[in] StartLba The starting logical block address to be accessed.
@param NumberOfBlocks The block number or sector count of the transfer. @param[in] NumberOfBlocks The block number or sector count of the transfer.
@param IsWrite Indicates whether it is a write operation. @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. @retval EFI_SUCCESS The data transfer is complete successfully.
@return others Some error occurs when transferring data. @return others Some error occurs when transferring data.
@ -476,36 +613,146 @@ AccessAtaDevice(
IN OUT UINT8 *Buffer, IN OUT UINT8 *Buffer,
IN EFI_LBA StartLba, IN EFI_LBA StartLba,
IN UINTN NumberOfBlocks, IN UINTN NumberOfBlocks,
IN BOOLEAN IsWrite IN BOOLEAN IsWrite,
IN OUT EFI_BLOCK_IO2_TOKEN *Token
) )
{ {
EFI_STATUS Status; EFI_STATUS Status;
UINTN MaxTransferBlockNumber; UINTN MaxTransferBlockNumber;
UINTN TransferBlockNumber; UINTN TransferBlockNumber;
UINTN BlockSize; 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 // Ensure AtaDevice->Lba48Bit is a valid boolean value
// //
ASSERT ((UINTN) AtaDevice->Lba48Bit < 2); ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);
MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit]; MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit];
BlockSize = AtaDevice->BlockMedia.BlockSize; BlockSize = AtaDevice->BlockMedia.BlockSize;
TempCount = (NumberOfBlocks + MaxTransferBlockNumber - 1) / MaxTransferBlockNumber;
*EventCount = TempCount;
Index = 0;
do { do {
if (NumberOfBlocks > MaxTransferBlockNumber) { if (NumberOfBlocks > MaxTransferBlockNumber) {
TransferBlockNumber = MaxTransferBlockNumber; TransferBlockNumber = MaxTransferBlockNumber;
NumberOfBlocks -= MaxTransferBlockNumber; NumberOfBlocks -= MaxTransferBlockNumber;
} else { } else {
TransferBlockNumber = NumberOfBlocks; TransferBlockNumber = NumberOfBlocks;
NumberOfBlocks = 0; NumberOfBlocks = 0;
} }
Status = TransferAtaDevice (AtaDevice, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite); //
if (EFI_ERROR (Status)) { // Create sub event for the sub Ata task. Non-Blocking Mode.
return Status; //
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)) {
goto EXIT;
}
StartLba += TransferBlockNumber; StartLba += TransferBlockNumber;
Buffer += TransferBlockNumber * BlockSize; Buffer += TransferBlockNumber * BlockSize;
} while (NumberOfBlocks > 0); } while (NumberOfBlocks > 0);
EXIT:
if (*EventCount == 0) {
FreePool (EventCount);
FreePool (IsError);
}
return Status; return Status;
} }

View File

@ -1,7 +1,7 @@
/** @file /** @file
Decode an El Torito formatted CD-ROM Decode an El Torito formatted CD-ROM
Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR> Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 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. Install child handles if the Handle supports El Torito format.
@param[in] This Calling context. @param[in] This Calling context.
@param[in] Handle Parent Handle @param[in] Handle Parent Handle.
@param[in] DiskIo Parent DiskIo interface @param[in] DiskIo Parent DiskIo interface.
@param[in] BlockIo Parent BlockIo interface @param[in] BlockIo Parent BlockIo interface.
@param[in] BlockIo2 Parent BlockIo2 interface.
@param[in] DevicePath Parent Device Path @param[in] DevicePath Parent Device Path
@retval EFI_SUCCESS Child handle(s) was added @retval EFI_SUCCESS Child handle(s) was added.
@retval EFI_MEDIA_CHANGED Media changed Detected @retval EFI_MEDIA_CHANGED Media changed Detected.
@retval other no child handle was added @retval other no child handle was added.
**/ **/
EFI_STATUS EFI_STATUS
@ -37,6 +38,7 @@ PartitionInstallElToritoChildHandles (
IN EFI_HANDLE Handle, IN EFI_HANDLE Handle,
IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
) )
{ {
@ -59,6 +61,7 @@ PartitionInstallElToritoChildHandles (
Found = EFI_NOT_FOUND; Found = EFI_NOT_FOUND;
Media = BlockIo->Media; Media = BlockIo->Media;
VolSpaceSize = 0; VolSpaceSize = 0;
// //
@ -256,6 +259,7 @@ PartitionInstallElToritoChildHandles (
Handle, Handle,
DiskIo, DiskIo,
BlockIo, BlockIo,
BlockIo2,
DevicePath, DevicePath,
(EFI_DEVICE_PATH_PROTOCOL *) &CdDev, (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
Catalog->Boot.Lba, Catalog->Boot.Lba,

View File

@ -2,7 +2,7 @@
Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0 Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
specification. specification.
Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR> Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 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" #include "Partition.h"
/** /**
Install child handles if the Handle supports GPT partition structure. 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] DiskIo Disk Io protocol.
@param[in] Lba The starting Lba of the Partition Table @param[in] Lba The starting Lba of the Partition Table
@param[out] PartHeader Stores the partition table that is read @param[out] PartHeader Stores the partition table that is read
@ -37,7 +36,6 @@ PartitionValidGptTable (
OUT EFI_PARTITION_TABLE_HEADER *PartHeader OUT EFI_PARTITION_TABLE_HEADER *PartHeader
); );
/** /**
Check if the CRC field in the Partition table header is valid Check if the CRC field in the Partition table header is valid
for Partition entry array. for Partition entry array.
@ -60,11 +58,11 @@ PartitionCheckGptEntryArrayCRC (
/** /**
Restore Partition Table to its alternate place 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] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure @param[in] PartHeader Partition table header structure.
@retval TRUE Restoring succeeds @retval TRUE Restoring succeeds
@retval FALSE Restoring failed @retval FALSE Restoring failed
@ -160,15 +158,16 @@ PartitionSetCrc (
/** /**
Install child handles if the Handle supports GPT partition structure. Install child handles if the Handle supports GPT partition structure.
@param[in] This - Calling context. @param[in] This Calling context.
@param[in] Handle - Parent Handle @param[in] Handle Parent Handle.
@param[in] DiskIo - Parent DiskIo interface @param[in] DiskIo Parent DiskIo interface.
@param[in] BlockIo - Parent BlockIo interface @param[in] BlockIo Parent BlockIo interface.
@param[in] DevicePath - Parent Device Path @param[in] BlockIo2 Parent BlockIo2 interface.
@param[in] DevicePath Parent Device Path.
@retval EFI_SUCCESS Valid GPT disk @retval EFI_SUCCESS Valid GPT disk.
@retval EFI_MEDIA_CHANGED Media changed Detected @retval EFI_MEDIA_CHANGED Media changed Detected.
@retval other Not a valid GPT disk @retval other Not a valid GPT disk.
**/ **/
EFI_STATUS EFI_STATUS
@ -177,6 +176,7 @@ PartitionInstallGptChildHandles (
IN EFI_HANDLE Handle, IN EFI_HANDLE Handle,
IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
) )
{ {
@ -191,6 +191,7 @@ PartitionInstallGptChildHandles (
UINTN Index; UINTN Index;
EFI_STATUS GptValidStatus; EFI_STATUS GptValidStatus;
HARDDRIVE_DEVICE_PATH HdDev; HARDDRIVE_DEVICE_PATH HdDev;
UINT32 MediaId;
ProtectiveMbr = NULL; ProtectiveMbr = NULL;
PrimaryHeader = NULL; PrimaryHeader = NULL;
@ -200,6 +201,7 @@ PartitionInstallGptChildHandles (
BlockSize = BlockIo->Media->BlockSize; BlockSize = BlockIo->Media->BlockSize;
LastBlock = BlockIo->Media->LastBlock; LastBlock = BlockIo->Media->LastBlock;
MediaId = BlockIo->Media->MediaId;
DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize)); DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize));
DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock)); DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock));
@ -219,15 +221,16 @@ PartitionInstallGptChildHandles (
// //
Status = DiskIo->ReadDisk ( Status = DiskIo->ReadDisk (
DiskIo, DiskIo,
BlockIo->Media->MediaId, MediaId,
0, 0,
BlockIo->Media->BlockSize, BlockSize,
ProtectiveMbr ProtectiveMbr
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
GptValidStatus = Status; GptValidStatus = Status;
goto Done; goto Done;
} }
// //
// Verify that the Protective MBR is valid // Verify that the Protective MBR is valid
// //
@ -302,7 +305,7 @@ PartitionInstallGptChildHandles (
Status = DiskIo->ReadDisk ( Status = DiskIo->ReadDisk (
DiskIo, DiskIo,
BlockIo->Media->MediaId, MediaId,
MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize), MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize),
PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry), PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),
PartEntry PartEntry
@ -369,17 +372,18 @@ PartitionInstallGptChildHandles (
DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (PartEntry[Index].EndingLBA, BlockSize))); DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (PartEntry[Index].EndingLBA, BlockSize)));
Status = PartitionInstallChildHandle ( Status = PartitionInstallChildHandle (
This, This,
Handle, Handle,
DiskIo, DiskIo,
BlockIo, BlockIo,
DevicePath, BlockIo2,
(EFI_DEVICE_PATH_PROTOCOL *) &HdDev, DevicePath,
PartEntry[Index].StartingLBA, (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
PartEntry[Index].EndingLBA, PartEntry[Index].StartingLBA,
BlockSize, PartEntry[Index].EndingLBA,
CompareGuid(&PartEntry[Index].PartitionTypeGUID, &gEfiPartTypeSystemPartGuid) BlockSize,
); CompareGuid(&PartEntry[Index].PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)
);
} }
DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n")); DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n"));
@ -404,11 +408,10 @@ Done:
return GptValidStatus; return GptValidStatus;
} }
/** /**
Install child handles if the Handle supports GPT partition structure. 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] DiskIo Disk Io protocol.
@param[in] Lba The starting Lba of the Partition Table @param[in] Lba The starting Lba of the Partition Table
@param[out] PartHeader Stores the partition table that is read @param[out] PartHeader Stores the partition table that is read
@ -428,9 +431,10 @@ PartitionValidGptTable (
EFI_STATUS Status; EFI_STATUS Status;
UINT32 BlockSize; UINT32 BlockSize;
EFI_PARTITION_TABLE_HEADER *PartHdr; EFI_PARTITION_TABLE_HEADER *PartHdr;
UINT32 MediaId;
BlockSize = BlockIo->Media->BlockSize; BlockSize = BlockIo->Media->BlockSize;
MediaId = BlockIo->Media->MediaId;
PartHdr = AllocateZeroPool (BlockSize); PartHdr = AllocateZeroPool (BlockSize);
if (PartHdr == NULL) { if (PartHdr == NULL) {
@ -442,7 +446,7 @@ PartitionValidGptTable (
// //
Status = DiskIo->ReadDisk ( Status = DiskIo->ReadDisk (
DiskIo, DiskIo,
BlockIo->Media->MediaId, MediaId,
MultU64x32 (Lba, BlockSize), MultU64x32 (Lba, BlockSize),
BlockSize, BlockSize,
PartHdr PartHdr
@ -472,12 +476,12 @@ PartitionValidGptTable (
return TRUE; return TRUE;
} }
/** /**
Check if the CRC field in the Partition table header is valid Check if the CRC field in the Partition table header is valid
for Partition entry array. for Partition entry array.
@param[in] BlockIo Parent BlockIo interface @param[in] BlockIo Parent BlockIo interface
@param[in] BlockIo2 Parent BlockIo2 interface.
@param[in] DiskIo Disk Io Protocol. @param[in] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure @param[in] PartHeader Partition table header structure
@ -535,11 +539,11 @@ PartitionCheckGptEntryArrayCRC (
/** /**
Restore Partition Table to its alternate place 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] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure @param[in] PartHeader Partition table header structure.
@retval TRUE Restoring succeeds @retval TRUE Restoring succeeds
@retval FALSE Restoring failed @retval FALSE Restoring failed
@ -557,11 +561,13 @@ PartitionRestoreGptTable (
EFI_PARTITION_TABLE_HEADER *PartHdr; EFI_PARTITION_TABLE_HEADER *PartHdr;
EFI_LBA PEntryLBA; EFI_LBA PEntryLBA;
UINT8 *Ptr; UINT8 *Ptr;
UINT32 MediaId;
PartHdr = NULL; PartHdr = NULL;
Ptr = NULL; Ptr = NULL;
BlockSize = BlockIo->Media->BlockSize; BlockSize = BlockIo->Media->BlockSize;
MediaId = BlockIo->Media->MediaId;
PartHdr = AllocateZeroPool (BlockSize); PartHdr = AllocateZeroPool (BlockSize);
@ -583,8 +589,8 @@ PartitionRestoreGptTable (
Status = DiskIo->WriteDisk ( Status = DiskIo->WriteDisk (
DiskIo, DiskIo,
BlockIo->Media->MediaId, MediaId,
MultU64x32 (PartHdr->MyLBA, BlockIo->Media->BlockSize), MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize),
BlockSize, BlockSize,
PartHdr PartHdr
); );
@ -601,8 +607,8 @@ PartitionRestoreGptTable (
Status = DiskIo->ReadDisk ( Status = DiskIo->ReadDisk (
DiskIo, DiskIo,
BlockIo->Media->MediaId, MediaId,
MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize),
PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry, PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
Ptr Ptr
); );
@ -612,8 +618,8 @@ PartitionRestoreGptTable (
Status = DiskIo->WriteDisk ( Status = DiskIo->WriteDisk (
DiskIo, DiskIo,
BlockIo->Media->MediaId, MediaId,
MultU64x32(PEntryLBA, BlockIo->Media->BlockSize), MultU64x32(PEntryLBA, (UINT32) BlockSize),
PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry, PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
Ptr Ptr
); );

View File

@ -11,7 +11,7 @@
always on the first sector of a media. The first sector also contains always on the first sector of a media. The first sector also contains
the legacy boot strap code. the legacy boot strap code.
Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR> Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 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. Install child handles if the Handle supports MBR format.
@param This Calling context. @param[in] This Calling context.
@param Handle Parent Handle. @param[in] Handle Parent Handle.
@param DiskIo Parent DiskIo interface. @param[in] DiskIo Parent DiskIo interface.
@param BlockIo Parent BlockIo interface. @param[in] BlockIo Parent BlockIo interface.
@param DevicePath Parent Device Path. @param[in] BlockIo2 Parent BlockIo2 interface.
@param[in] DevicePath Parent Device Path.
@retval EFI_SUCCESS A child handle was added. @retval EFI_SUCCESS A child handle was added.
@retval EFI_MEDIA_CHANGED Media change was detected. @retval EFI_MEDIA_CHANGED Media change was detected.
@ -118,6 +119,7 @@ PartitionInstallMbrChildHandles (
IN EFI_HANDLE Handle, IN EFI_HANDLE Handle,
IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
) )
{ {
@ -131,26 +133,33 @@ PartitionInstallMbrChildHandles (
UINT32 PartitionNumber; UINT32 PartitionNumber;
EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode; EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
UINT32 BlockSize;
UINT32 MediaId;
EFI_LBA LastBlock;
Found = EFI_NOT_FOUND; 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) { if (Mbr == NULL) {
return Found; return Found;
} }
Status = DiskIo->ReadDisk ( Status = DiskIo->ReadDisk (
DiskIo, DiskIo,
BlockIo->Media->MediaId, MediaId,
0, 0,
BlockIo->Media->BlockSize, BlockSize,
Mbr Mbr
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
Found = Status; Found = Status;
goto Done; goto Done;
} }
if (!PartitionValidMbr (Mbr, BlockIo->Media->LastBlock)) { if (!PartitionValidMbr (Mbr, LastBlock)) {
goto Done; goto Done;
} }
// //
@ -218,6 +227,7 @@ PartitionInstallMbrChildHandles (
Handle, Handle,
DiskIo, DiskIo,
BlockIo, BlockIo,
BlockIo2,
DevicePath, DevicePath,
(EFI_DEVICE_PATH_PROTOCOL *) &HdDev, (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
HdDev.PartitionStart, HdDev.PartitionStart,
@ -241,9 +251,9 @@ PartitionInstallMbrChildHandles (
Status = DiskIo->ReadDisk ( Status = DiskIo->ReadDisk (
DiskIo, DiskIo,
BlockIo->Media->MediaId, MediaId,
MultU64x32 (ExtMbrStartingLba, BlockIo->Media->BlockSize), MultU64x32 (ExtMbrStartingLba, BlockSize),
BlockIo->Media->BlockSize, BlockSize,
Mbr Mbr
); );
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
@ -274,17 +284,18 @@ PartitionInstallMbrChildHandles (
*((UINT32 *) &HdDev.Signature[0]) = 0; *((UINT32 *) &HdDev.Signature[0]) = 0;
Status = PartitionInstallChildHandle ( Status = PartitionInstallChildHandle (
This, This,
Handle, Handle,
DiskIo, DiskIo,
BlockIo, BlockIo,
DevicePath, BlockIo2,
(EFI_DEVICE_PATH_PROTOCOL *) &HdDev, DevicePath,
HdDev.PartitionStart - ParentHdDev.PartitionStart, (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1, HdDev.PartitionStart - ParentHdDev.PartitionStart,
MBR_SIZE, HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,
(BOOLEAN) (Mbr->Partition[0].OSIndicator == EFI_PARTITION) MBR_SIZE,
); (BOOLEAN) (Mbr->Partition[0].OSIndicator == EFI_PARTITION)
);
if (!EFI_ERROR (Status)) { if (!EFI_ERROR (Status)) {
Found = EFI_SUCCESS; Found = EFI_SUCCESS;
} }

View File

@ -40,16 +40,15 @@ PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
NULL NULL
}; };
/** /**
Test to see if this driver supports ControllerHandle. Any ControllerHandle 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[in] This Protocol instance pointer.
@param ControllerHandle Handle of device to test @param[in] ControllerHandle Handle of device to test.
@param RemainingDevicePath Optional parameter use to pick a specific child @param[in] RemainingDevicePath Optional parameter use to pick a specific child
device to start. device to start.
@retval EFI_SUCCESS This driver supports this device @retval EFI_SUCCESS This driver supports this device
@retval EFI_ALREADY_STARTED This driver is already running on 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 || if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||
Node->DevPath.SubType != MEDIA_HARDDRIVE_DP || Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||
DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) { DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
} }
} }
} }
@ -105,7 +104,6 @@ PartitionDriverBindingSupported (
if (Status == EFI_ALREADY_STARTED) { if (Status == EFI_ALREADY_STARTED) {
return EFI_SUCCESS; return EFI_SUCCESS;
} }
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return Status; return Status;
} }
@ -159,20 +157,39 @@ PartitionDriverBindingSupported (
ControllerHandle, ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL EFI_OPEN_PROTOCOL_TEST_PROTOCOL
); );
if (EFI_ERROR (Status)) {
return 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 Start this driver on ControllerHandle by opening a Block IO or a Block IO2
protocol, reading Device Path, and creating a child handle with a or both, and Disk IO protocol, reading Device Path, and creating a child
Disk IO and device path protocol. handle with a Disk IO and device path protocol.
@param This Protocol instance pointer. @param[in] This Protocol instance pointer.
@param ControllerHandle Handle of device to bind driver to @param[in] ControllerHandle Handle of device to bind driver to
@param RemainingDevicePath Optional parameter use to pick a specific child @param[in] RemainingDevicePath Optional parameter use to pick a specific child
device to start. device to start.
@retval EFI_SUCCESS This driver is added to ControllerHandle @retval EFI_SUCCESS This driver is added to ControllerHandle
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
@ -190,6 +207,7 @@ PartitionDriverBindingStart (
EFI_STATUS Status; EFI_STATUS Status;
EFI_STATUS OpenStatus; EFI_STATUS OpenStatus;
EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO_PROTOCOL *BlockIo;
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
EFI_DISK_IO_PROTOCOL *DiskIo; EFI_DISK_IO_PROTOCOL *DiskIo;
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
PARTITION_DETECT_ROUTINE *Routine; 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 ( Status = gBS->OpenProtocol (
ControllerHandle, ControllerHandle,
&gEfiBlockIoProtocolGuid, &gEfiBlockIoProtocolGuid,
@ -222,8 +244,27 @@ PartitionDriverBindingStart (
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Exit; 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 ( Status = gBS->OpenProtocol (
ControllerHandle, ControllerHandle,
@ -276,6 +317,7 @@ PartitionDriverBindingStart (
ControllerHandle, ControllerHandle,
DiskIo, DiskIo,
BlockIo, BlockIo,
BlockIo2,
ParentDevicePath ParentDevicePath
); );
if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) { if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
@ -306,6 +348,15 @@ PartitionDriverBindingStart (
This->DriverBindingHandle, This->DriverBindingHandle,
ControllerHandle ControllerHandle
); );
//
// Close Parent BlockIO2 if has.
//
gBS->CloseProtocol (
ControllerHandle,
&gEfiBlockIo2ProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol ( gBS->CloseProtocol (
ControllerHandle, ControllerHandle,
@ -320,7 +371,6 @@ Exit:
return Status; return Status;
} }
/** /**
Stop this driver on ControllerHandle. Support stopping any child handles Stop this driver on ControllerHandle. Support stopping any child handles
created by this driver. created by this driver.
@ -347,10 +397,15 @@ PartitionDriverBindingStop (
EFI_STATUS Status; EFI_STATUS Status;
UINTN Index; UINTN Index;
EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO_PROTOCOL *BlockIo;
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
BOOLEAN AllChildrenStopped; BOOLEAN AllChildrenStopped;
PARTITION_PRIVATE_DATA *Private; PARTITION_PRIVATE_DATA *Private;
EFI_DISK_IO_PROTOCOL *DiskIo; EFI_DISK_IO_PROTOCOL *DiskIo;
BlockIo = NULL;
BlockIo2 = NULL;
Private = NULL;
if (NumberOfChildren == 0) { if (NumberOfChildren == 0) {
// //
// Close the bus driver // Close the bus driver
@ -361,6 +416,15 @@ PartitionDriverBindingStop (
This->DriverBindingHandle, This->DriverBindingHandle,
ControllerHandle ControllerHandle
); );
//
// Close Parent BlockIO2 if has.
//
gBS->CloseProtocol (
ControllerHandle,
&gEfiBlockIo2ProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol ( gBS->CloseProtocol (
ControllerHandle, ControllerHandle,
@ -368,60 +432,91 @@ PartitionDriverBindingStop (
This->DriverBindingHandle, This->DriverBindingHandle,
ControllerHandle ControllerHandle
); );
return EFI_SUCCESS; return EFI_SUCCESS;
} }
AllChildrenStopped = TRUE; AllChildrenStopped = TRUE;
for (Index = 0; Index < NumberOfChildren; Index++) { for (Index = 0; Index < NumberOfChildren; Index++) {
Status = gBS->OpenProtocol ( gBS->OpenProtocol (
ChildHandleBuffer[Index], ChildHandleBuffer[Index],
&gEfiBlockIoProtocolGuid, &gEfiBlockIoProtocolGuid,
(VOID **) &BlockIo, (VOID **) &BlockIo,
This->DriverBindingHandle, This->DriverBindingHandle,
ControllerHandle, ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL EFI_OPEN_PROTOCOL_GET_PROTOCOL
); );
if (!EFI_ERROR (Status)) { //
// 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); Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
} else if (BlockIo2 != NULL) {
Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (BlockIo2);
} else {
ASSERT (FALSE);
}
// Status = gBS->CloseProtocol (
// All Software protocols have be freed from the handle so remove it. 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); BlockIo->FlushBlocks (BlockIo);
BlockIo2->FlushBlocksEx (BlockIo2, NULL);
Status = gBS->CloseProtocol (
ControllerHandle,
&gEfiDiskIoProtocolGuid,
This->DriverBindingHandle,
ChildHandleBuffer[Index]
);
Status = gBS->UninstallMultipleProtocolInterfaces ( Status = gBS->UninstallMultipleProtocolInterfaces (
ChildHandleBuffer[Index], ChildHandleBuffer[Index],
&gEfiDevicePathProtocolGuid, &gEfiDevicePathProtocolGuid,
Private->DevicePath, Private->DevicePath,
&gEfiBlockIoProtocolGuid, &gEfiBlockIoProtocolGuid,
&Private->BlockIo, &Private->BlockIo,
Private->EspGuid, &gEfiBlockIo2ProtocolGuid,
NULL, &Private->BlockIo2,
NULL Private->EspGuid,
); NULL,
if (EFI_ERROR (Status)) { NULL
gBS->OpenProtocol ( );
ControllerHandle, } else {
&gEfiDiskIoProtocolGuid, BlockIo->FlushBlocks (BlockIo);
(VOID **) &DiskIo, Status = gBS->UninstallMultipleProtocolInterfaces (
This->DriverBindingHandle, ChildHandleBuffer[Index],
ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER Private->DevicePath,
); &gEfiBlockIoProtocolGuid,
} else { &Private->BlockIo,
FreePool (Private->DevicePath); Private->EspGuid,
FreePool (Private); 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)) { if (EFI_ERROR (Status)) {
@ -551,11 +646,11 @@ PartitionReadBlocks (
Write by using the Disk IO protocol on the parent device. Lba addresses Write by using the Disk IO protocol on the parent device. Lba addresses
must be converted to byte offsets. must be converted to byte offsets.
@param This Protocol instance pointer. @param[in] This Protocol instance pointer.
@param MediaId Id of the media, changes every time the media is replaced. @param[in] MediaId Id of the media, changes every time the media is replaced.
@param Lba The starting Logical Block Address to read from @param[in] Lba The starting Logical Block Address to read from
@param BufferSize Size of Buffer, must be a multiple of device block size. @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param Buffer Buffer containing read data @param[in] Buffer Buffer containing data to be written to device.
@retval EFI_SUCCESS The data was written correctly to the device. @retval EFI_SUCCESS The data was written correctly to the device.
@retval EFI_WRITE_PROTECTED The device can not be written to. @retval EFI_WRITE_PROTECTED The device can not be written to.
@ -574,7 +669,7 @@ PartitionWriteBlocks (
IN UINT32 MediaId, IN UINT32 MediaId,
IN EFI_LBA Lba, IN EFI_LBA Lba,
IN UINTN BufferSize, IN UINTN BufferSize,
OUT VOID *Buffer IN VOID *Buffer
) )
{ {
PARTITION_PRIVATE_DATA *Private; PARTITION_PRIVATE_DATA *Private;
@ -622,25 +717,261 @@ PartitionFlushBlocks (
return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo); 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 Create a child handle for a logical block device that represents the
bytes Start to End of the Parent Block IO device. bytes Start to End of the Parent Block IO device.
@param[in] This Protocol instance pointer @param[in] This Protocol instance pointer.
@param[in] ParentHandle Parent Handle for new child @param[in] ParentHandle Parent Handle for new child.
@param[in] ParentDiskIo Parent DiskIo interface @param[in] ParentDiskIo Parent DiskIo interface.
@param[in] ParentBlockIo Parent BlockIo interface @param[in] ParentBlockIo Parent BlockIo interface.
@param[in] ParentDevicePath Parent Device Path @param[in] ParentBlockIo2 Parent BlockIo2 interface.
@param[in] DevicePathNode Child Device Path node @param[in] ParentDevicePath Parent Device Path.
@param[in] Start Start Block @param[in] DevicePathNode Child Device Path node.
@param[in] End End Block @param[in] Start Start Block.
@param[in] BlockSize Child block size @param[in] End End Block.
@param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle @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 EFI_SUCCESS A child handle was added.
@retval other A child handle was not added @retval other A child handle was not added.
**/ **/
EFI_STATUS EFI_STATUS
@ -649,6 +980,7 @@ PartitionInstallChildHandle (
IN EFI_HANDLE ParentHandle, IN EFI_HANDLE ParentHandle,
IN EFI_DISK_IO_PROTOCOL *ParentDiskIo, IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo, IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
IN EFI_LBA Start, IN EFI_LBA Start,
@ -660,6 +992,7 @@ PartitionInstallChildHandle (
EFI_STATUS Status; EFI_STATUS Status;
PARTITION_PRIVATE_DATA *Private; PARTITION_PRIVATE_DATA *Private;
Status = EFI_SUCCESS;
Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA)); Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
if (Private == NULL) { if (Private == NULL) {
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
@ -672,28 +1005,51 @@ PartitionInstallChildHandle (
Private->BlockSize = BlockSize; Private->BlockSize = BlockSize;
Private->ParentBlockIo = ParentBlockIo; Private->ParentBlockIo = ParentBlockIo;
Private->ParentBlockIo2 = ParentBlockIo2;
Private->DiskIo = ParentDiskIo; Private->DiskIo = ParentDiskIo;
Private->BlockIo.Revision = ParentBlockIo->Revision; if (Private->ParentBlockIo != NULL) {
Private->BlockIo.Revision = ParentBlockIo->Revision;
Private->BlockIo.Media = &Private->Media; Private->BlockIo.Media = &Private->Media;
CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA)); CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
Private->Media.LogicalPartition = TRUE;
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.IoAlign = 0;
Private->Media.LogicalPartition = TRUE;
Private->Media.LastBlock = DivU64x32 ( Private->Media.LastBlock = DivU64x32 (
MultU64x32 ( MultU64x32 (
End - Start + 1, End - Start + 1,
ParentBlockIo->Media->BlockSize (ParentBlockIo != NULL) ? ParentBlockIo->Media->BlockSize : ParentBlockIo2->Media->BlockSize
), ),
BlockSize BlockSize
) - 1; ) - 1;
Private->Media.BlockSize = (UINT32) BlockSize; 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 // Per UEFI Spec, LowestAlignedLba and LogicalBlocksPerPhysicalBlock must be 0
// for logical partitions. // for logical partitions.
@ -703,12 +1059,7 @@ PartitionInstallChildHandle (
Private->BlockIo.Media->LogicalBlocksPerPhysicalBlock = 0; Private->BlockIo.Media->LogicalBlocksPerPhysicalBlock = 0;
} }
Private->BlockIo.Reset = PartitionReset; Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
Private->BlockIo.ReadBlocks = PartitionReadBlocks;
Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
if (Private->DevicePath == NULL) { if (Private->DevicePath == NULL) {
FreePool (Private); FreePool (Private);
@ -723,20 +1074,61 @@ PartitionInstallChildHandle (
// //
Private->EspGuid = NULL; 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; Private->Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces ( if ((Private->ParentBlockIo != NULL) &&
&Private->Handle, (Private->ParentBlockIo2 != NULL) &&
&gEfiDevicePathProtocolGuid, (Private->ParentBlockIo2->Media->BlockSize == BlockSize)
Private->DevicePath, ) {
&gEfiBlockIoProtocolGuid, Status = gBS->InstallMultipleProtocolInterfaces (
&Private->BlockIo, &Private->Handle,
Private->EspGuid, &gEfiDevicePathProtocolGuid,
NULL, Private->DevicePath,
NULL &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)) { if (!EFI_ERROR (Status)) {
// //

View File

@ -4,7 +4,7 @@
of the raw block devices media. Currently "El Torito CD-ROM", Legacy of the raw block devices media. Currently "El Torito CD-ROM", Legacy
MBR, and GPT partition schemes are supported. MBR, and GPT partition schemes are supported.
Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR> Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License 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 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 <Uefi.h> #include <Uefi.h>
#include <Protocol/BlockIo.h> #include <Protocol/BlockIo.h>
#include <Protocol/BlockIo2.h>
#include <Guid/Gpt.h> #include <Guid/Gpt.h>
#include <Protocol/ComponentName.h> #include <Protocol/ComponentName.h>
#include <Protocol/DevicePath.h> #include <Protocol/DevicePath.h>
@ -48,10 +49,13 @@ typedef struct {
EFI_HANDLE Handle; EFI_HANDLE Handle;
EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_BLOCK_IO_PROTOCOL BlockIo; EFI_BLOCK_IO_PROTOCOL BlockIo;
EFI_BLOCK_IO2_PROTOCOL BlockIo2;
EFI_BLOCK_IO_MEDIA Media; EFI_BLOCK_IO_MEDIA Media;
EFI_BLOCK_IO_MEDIA Media2;//For BlockIO2
EFI_DISK_IO_PROTOCOL *DiskIo; EFI_DISK_IO_PROTOCOL *DiskIo;
EFI_BLOCK_IO_PROTOCOL *ParentBlockIo; EFI_BLOCK_IO_PROTOCOL *ParentBlockIo;
EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2;
UINT64 Start; UINT64 Start;
UINT64 End; UINT64 End;
UINT32 BlockSize; UINT32 BlockSize;
@ -61,6 +65,7 @@ typedef struct {
} PARTITION_PRIVATE_DATA; } 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_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 // Global Variables
@ -300,19 +305,20 @@ PartitionComponentNameGetControllerName (
Create a child handle for a logical block device that represents the Create a child handle for a logical block device that represents the
bytes Start to End of the Parent Block IO device. bytes Start to End of the Parent Block IO device.
@param[in] This Protocol instance pointer @param[in] This Protocol instance pointer.
@param[in] ParentHandle Parent Handle for new child @param[in] ParentHandle Parent Handle for new child.
@param[in] ParentDiskIo Parent DiskIo interface @param[in] ParentDiskIo Parent DiskIo interface.
@param[in] ParentBlockIo Parent BlockIo interface @param[in] ParentBlockIo Parent BlockIo interface.
@param[in] ParentDevicePath Parent Device Path @param[in] ParentBlockIo2 Parent BlockIo2 interface.
@param[in] DevicePathNode Child Device Path node @param[in] ParentDevicePath Parent Device Path.
@param[in] Start Start Block @param[in] DevicePathNode Child Device Path node.
@param[in] End End Block @param[in] Start Start Block.
@param[in] BlockSize Child block size @param[in] End End Block.
@param[in] InstallEspGuid Flag to install EFI System Partition GUID on handle @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 EFI_SUCCESS A child handle was added.
@retval other A child handle was not added @retval other A child handle was not added.
**/ **/
EFI_STATUS EFI_STATUS
@ -321,6 +327,7 @@ PartitionInstallChildHandle (
IN EFI_HANDLE ParentHandle, IN EFI_HANDLE ParentHandle,
IN EFI_DISK_IO_PROTOCOL *ParentDiskIo, IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo, IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
IN EFI_LBA Start, IN EFI_LBA Start,
@ -332,15 +339,17 @@ PartitionInstallChildHandle (
/** /**
Install child handles if the Handle supports GPT partition structure. Install child handles if the Handle supports GPT partition structure.
@param[in] This - Calling context. @param[in] This Calling context.
@param[in] Handle - Parent Handle @param[in] Handle Parent Handle.
@param[in] DiskIo - Parent DiskIo interface @param[in] DiskIo Parent DiskIo interface.
@param[in] BlockIo - Parent BlockIo interface @param[in] BlockIo Parent BlockIo interface.
@param[in] DevicePath - Parent Device Path @param[in] BlockIo2 Parent BlockIo2 interface.
@param[in] DevicePath Parent Device Path.
@retval EFI_SUCCESS Valid GPT disk @retval EFI_SUCCESS Valid GPT disk.
@retval EFI_MEDIA_CHANGED Media changed Detected @retval EFI_MEDIA_CHANGED Media changed Detected.
@retval other Not a valid GPT disk @retval EFI_INVALID_PARAMETER If both BlockIo and BlockIo2 are NULL;
@retval other Not a valid GPT disk.
**/ **/
EFI_STATUS EFI_STATUS
@ -349,6 +358,7 @@ PartitionInstallGptChildHandles (
IN EFI_HANDLE Handle, IN EFI_HANDLE Handle,
IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
); );
@ -356,15 +366,16 @@ PartitionInstallGptChildHandles (
Install child handles if the Handle supports El Torito format. Install child handles if the Handle supports El Torito format.
@param[in] This Calling context. @param[in] This Calling context.
@param[in] Handle Parent Handle @param[in] Handle Parent Handle.
@param[in] DiskIo Parent DiskIo interface @param[in] DiskIo Parent DiskIo interface.
@param[in] BlockIo Parent BlockIo interface @param[in] BlockIo Parent BlockIo interface.
@param[in] BlockIo2 Parent BlockIo2 interface.
@param[in] DevicePath Parent Device Path @param[in] DevicePath Parent Device Path
@retval EFI_SUCCESS Child handle(s) was added @retval EFI_SUCCESS Child handle(s) was added.
@retval EFI_MEDIA_CHANGED Media changed Detected @retval EFI_MEDIA_CHANGED Media changed Detected.
@retval other no child handle was added @retval other no child handle was added.
**/ **/
EFI_STATUS EFI_STATUS
@ -373,17 +384,19 @@ PartitionInstallElToritoChildHandles (
IN EFI_HANDLE Handle, IN EFI_HANDLE Handle,
IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
); );
/** /**
Install child handles if the Handle supports MBR format. Install child handles if the Handle supports MBR format.
@param This Calling context. @param[in] This Calling context.
@param Handle Parent Handle. @param[in] Handle Parent Handle.
@param DiskIo Parent DiskIo interface. @param[in] DiskIo Parent DiskIo interface.
@param BlockIo Parent BlockIo interface. @param[in] BlockIo Parent BlockIo interface.
@param DevicePath Parent Device Path. @param[in] BlockIo2 Parent BlockIo2 interface.
@param[in] DevicePath Parent Device Path.
@retval EFI_SUCCESS A child handle was added. @retval EFI_SUCCESS A child handle was added.
@retval EFI_MEDIA_CHANGED Media change was detected. @retval EFI_MEDIA_CHANGED Media change was detected.
@ -396,6 +409,7 @@ PartitionInstallMbrChildHandles (
IN EFI_HANDLE Handle, IN EFI_HANDLE Handle,
IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
); );
@ -406,6 +420,7 @@ EFI_STATUS
IN EFI_HANDLE Handle, IN EFI_HANDLE Handle,
IN EFI_DISK_IO_PROTOCOL *DiskIo, IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
); );

View File

@ -7,7 +7,7 @@
# The partition of physical BlockIo device supported is one of legacy MBR, GPT, # The partition of physical BlockIo device supported is one of legacy MBR, GPT,
# and "El Torito" partitions. # and "El Torito" partitions.
# #
# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> # Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials # This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License # 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 # which accompanies this distribution. The full text of the license may be found at
@ -70,5 +70,6 @@
gEfiDevicePathProtocolGuid ## BY_START gEfiDevicePathProtocolGuid ## BY_START
gEfiDiskIoProtocolGuid ## BY_START gEfiDiskIoProtocolGuid ## BY_START
gEfiBlockIoProtocolGuid ## TO_START gEfiBlockIoProtocolGuid ## TO_START
gEfiBlockIo2ProtocolGuid ## TO_START
gEfiDevicePathProtocolGuid ## TO_START gEfiDevicePathProtocolGuid ## TO_START
gEfiDiskIoProtocolGuid ## TO_START gEfiDiskIoProtocolGuid ## TO_START

View File

@ -894,6 +894,9 @@
## Include/Protocol/BlockIo.h ## Include/Protocol/BlockIo.h
gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }} 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 ## Include/Protocol/UnicodeCollation.h
gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }} gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }}