/** @file | |
Block I/O protocol for CE-ATA device | |
Copyright (c) 2013-2015 Intel Corporation. | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "SDMediaDevice.h" | |
/** | |
Implements EFI_BLOCK_IO_PROTOCOL.Reset() function. | |
@param This The EFI_BLOCK_IO_PROTOCOL instance. | |
@param ExtendedVerification Indicates that the driver may perform a more exhaustive. | |
verification operation of the device during reset. | |
(This parameter is ingored in this driver.) | |
@retval EFI_SUCCESS Success | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CEATABlockReset ( | |
IN EFI_BLOCK_IO_PROTOCOL *This, | |
IN BOOLEAN ExtendedVerification | |
) | |
{ | |
EFI_STATUS Status; | |
CARD_DATA *CardData; | |
EFI_SD_HOST_IO_PROTOCOL *SDHostIo; | |
CardData = CARD_DATA_FROM_THIS(This); | |
SDHostIo = CardData->SDHostIo; | |
if (!ExtendedVerification) { | |
Status = SoftwareReset (CardData); | |
} else { | |
Status = SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD); | |
if (EFI_ERROR (Status)) { | |
DEBUG((EFI_D_ERROR, "CEATABlockReset: Fail to ResetSDHost\n" )); | |
return Status; | |
} | |
Status = MMCSDCardInit (CardData); | |
} | |
return Status; | |
} | |
/** | |
Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function. | |
@param This The EFI_BLOCK_IO_PROTOCOL instance. | |
@param MediaId The media id that the write request is for. | |
@param LBA The starting logical block address to read from on the device. | |
The caller is responsible for writing to only legitimate locations. | |
@param BufferSize The size of the Buffer in bytes. This must be a multiple of the | |
intrinsic block size of the device. | |
@param Buffer A pointer to the destination buffer for the data. The caller | |
is responsible for either having implicit or explicit ownership | |
of the buffer. | |
@retval EFI_SUCCESS Success | |
@retval EFI_DEVICE_ERROR Hardware Error | |
@retval EFI_INVALID_PARAMETER Parameter is error | |
@retval EFI_NO_MEDIA No media | |
@retval EFI_MEDIA_CHANGED Media Change | |
@retval EFI_BAD_BUFFER_SIZE Buffer size is bad | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CEATABlockReadBlocks ( | |
IN EFI_BLOCK_IO_PROTOCOL *This, | |
IN UINT32 MediaId, | |
IN EFI_LBA LBA, | |
IN UINTN BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
EFI_STATUS Status; | |
CARD_DATA *CardData; | |
UINT32 TransferSize; | |
UINT8 *pBuf; | |
UINT32 Index; | |
UINT64 Address; | |
UINT32 Remainder; | |
UINT64 CEATALBA; | |
UINT32 BoundarySize; | |
Status = EFI_SUCCESS; | |
CardData = CARD_DATA_FROM_THIS(This); | |
pBuf = Buffer; | |
Index = 0; | |
Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize); | |
BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize; | |
if (!Buffer) { | |
Status = EFI_INVALID_PARAMETER; | |
DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" )); | |
goto Exit; | |
} | |
if (MediaId != CardData->BlockIoMedia.MediaId) { | |
Status = EFI_MEDIA_CHANGED; | |
DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Media changed\n" )); | |
goto Exit; | |
} | |
if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) { | |
Status = EFI_BAD_BUFFER_SIZE; | |
DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Bad buffer size\n" )); | |
goto Exit; | |
} | |
if (BufferSize == 0) { | |
Status = EFI_SUCCESS; | |
goto Exit; | |
} | |
if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) { | |
Status = EFI_INVALID_PARAMETER; | |
DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" )); | |
goto Exit; | |
} | |
do { | |
if (BufferSize < BoundarySize) { | |
TransferSize = (UINT32)BufferSize; | |
} else { | |
TransferSize = BoundarySize; | |
} | |
Address += Index * TransferSize; | |
CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder); | |
ASSERT(Remainder == 0); | |
Status = ReadDMAExt ( | |
CardData, | |
CEATALBA, | |
pBuf, | |
(UINT16)(TransferSize / DATA_UNIT_SIZE) | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG((EFI_D_ERROR, "Read Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize)); | |
This->Reset (This, TRUE); | |
goto Exit; | |
} | |
BufferSize -= TransferSize; | |
pBuf += TransferSize; | |
Index ++; | |
} while (BufferSize != 0); | |
Exit: | |
return Status; | |
} | |
/** | |
Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function. | |
@param This The EFI_BLOCK_IO_PROTOCOL instance. | |
@param MediaId The media id that the write request is for. | |
@param LBA The starting logical block address to read from on the device. | |
The caller is responsible for writing to only legitimate locations. | |
@param BufferSize The size of the Buffer in bytes. This must be a multiple of the | |
intrinsic block size of the device. | |
@param Buffer A pointer to the destination buffer for the data. The caller | |
is responsible for either having implicit or explicit ownership | |
of the buffer. | |
@retval EFI_SUCCESS Success | |
@retval EFI_DEVICE_ERROR Hardware Error | |
@retval EFI_INVALID_PARAMETER Parameter is error | |
@retval EFI_NO_MEDIA No media | |
@retval EFI_MEDIA_CHANGED Media Change | |
@retval EFI_BAD_BUFFER_SIZE Buffer size is bad | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CEATABlockWriteBlocks ( | |
IN EFI_BLOCK_IO_PROTOCOL *This, | |
IN UINT32 MediaId, | |
IN EFI_LBA LBA, | |
IN UINTN BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
EFI_STATUS Status; | |
CARD_DATA *CardData; | |
UINT32 TransferSize; | |
UINT8 *pBuf; | |
UINT32 Index; | |
UINT64 Address; | |
UINT32 Remainder; | |
UINT64 CEATALBA; | |
UINT32 BoundarySize; | |
Status = EFI_SUCCESS; | |
CardData = CARD_DATA_FROM_THIS(This); | |
pBuf = Buffer; | |
Index = 0; | |
Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize); | |
BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize; | |
if (!Buffer) { | |
Status = EFI_INVALID_PARAMETER; | |
goto Exit; | |
} | |
if (MediaId != CardData->BlockIoMedia.MediaId) { | |
Status = EFI_MEDIA_CHANGED; | |
goto Exit; | |
} | |
if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) { | |
Status = EFI_BAD_BUFFER_SIZE; | |
goto Exit; | |
} | |
if (BufferSize == 0) { | |
Status = EFI_SUCCESS; | |
goto Exit; | |
} | |
if (CardData->BlockIoMedia.ReadOnly) { | |
Status = EFI_WRITE_PROTECTED; | |
goto Exit; | |
} | |
if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) { | |
Status = EFI_INVALID_PARAMETER; | |
goto Exit; | |
} | |
CardData->NeedFlush = TRUE; | |
do { | |
if (BufferSize < BoundarySize) { | |
TransferSize = (UINT32)BufferSize; | |
} else { | |
TransferSize = BoundarySize; | |
} | |
Address += Index * TransferSize; | |
CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder); | |
ASSERT(Remainder == 0); | |
Status = WriteDMAExt ( | |
CardData, | |
CEATALBA, | |
pBuf, | |
(UINT16)(TransferSize / DATA_UNIT_SIZE) | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG((EFI_D_ERROR, "Write Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize)); | |
This->Reset (This, TRUE); | |
goto Exit; | |
} | |
BufferSize -= TransferSize; | |
pBuf += TransferSize; | |
Index ++; | |
} while (BufferSize != 0); | |
Exit: | |
return Status; | |
} | |
/** | |
Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function. | |
(In this driver, this function just returns EFI_SUCCESS.) | |
@param This The EFI_BLOCK_IO_PROTOCOL instance. | |
@retval EFI_SUCCESS | |
@retval Others | |
**/ | |
EFI_STATUS | |
EFIAPI | |
CEATABlockFlushBlocks ( | |
IN EFI_BLOCK_IO_PROTOCOL *This | |
) | |
{ | |
CARD_DATA *CardData; | |
CardData = CARD_DATA_FROM_THIS(This); | |
if (CardData->NeedFlush) { | |
CardData->NeedFlush = FALSE; | |
FlushCache (CardData); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
CEATA card BlockIo init function. | |
@param CardData Pointer to CARD_DATA. | |
@retval EFI_SUCCESS | |
@retval Others | |
**/ | |
EFI_STATUS | |
CEATABlockIoInit ( | |
IN CARD_DATA *CardData | |
) | |
/*++ | |
Routine Description: | |
CEATA card BlockIo init function | |
Arguments: | |
CardData - Pointer to CARD_DATA | |
Returns: | |
EFI_SUCCESS - Success | |
--*/ | |
{ | |
EFI_STATUS Status; | |
UINT64 MaxSize; | |
UINT32 Remainder; | |
// | |
//BlockIO protocol | |
// | |
CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION; | |
CardData->BlockIo.Media = &(CardData->BlockIoMedia); | |
CardData->BlockIo.Reset = CEATABlockReset; | |
CardData->BlockIo.ReadBlocks = CEATABlockReadBlocks ; | |
CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks; | |
CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks; | |
CardData->BlockIoMedia.MediaId = 0; | |
CardData->BlockIoMedia.RemovableMedia = FALSE; | |
CardData->BlockIoMedia.MediaPresent = TRUE; | |
CardData->BlockIoMedia.LogicalPartition = FALSE; | |
if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) { | |
CardData->BlockIoMedia.ReadOnly = TRUE; | |
} else { | |
CardData->BlockIoMedia.ReadOnly = FALSE; | |
} | |
CardData->BlockIoMedia.WriteCaching = FALSE; | |
CardData->BlockIoMedia.IoAlign = 1; | |
Status = IndentifyDevice (CardData); | |
if (EFI_ERROR (Status)) { | |
goto Exit; | |
} | |
// | |
//Some device does not support this feature | |
// | |
if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) { | |
CardData->BlockIoMedia.ReadOnly = TRUE; | |
} | |
CardData->BlockIoMedia.BlockSize = (1 << CardData->IndentifyDeviceData.Sectorsize); | |
ASSERT(CardData->BlockIoMedia.BlockSize >= 12); | |
MaxSize = *(UINT64*)(CardData->IndentifyDeviceData.MaximumLBA); | |
MaxSize = MultU64x32 (MaxSize, 512); | |
Remainder = 0; | |
CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder); | |
ASSERT(Remainder == 0); | |
CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1); | |
Exit: | |
return Status; | |
} | |