MdeModulePkg/Sd: add Erase Block support on sd/emmc device

It's done by producing EFI_ERASE_BLOCK_PROTOCOL protocol instance.

Cc: Hao Wu <hao.a.wu@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Hao Wu <hao.a.wu@intel.com>
This commit is contained in:
Feng Tian 2016-05-03 14:07:38 +08:00
parent 140cc8000f
commit 275d51369a
10 changed files with 978 additions and 6 deletions

View File

@ -1589,3 +1589,416 @@ EmmcSecurityProtocolOut (
return Status;
}
/**
Set the erase start address through sync or async I/O request.
@param[in] Partition A pointer to the EMMC_PARTITION instance.
@param[in] StartLba The starting logical block address to be erased.
@param[in] Token A pointer to the token associated with the transaction.
@param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
This parameter is only meaningful in async I/O request.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
EmmcEraseBlockStart (
IN EMMC_PARTITION *Partition,
IN EFI_LBA StartLba,
IN EFI_BLOCK_IO2_TOKEN *Token,
IN BOOLEAN IsEnd
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EMMC_DEVICE *Device;
EMMC_REQUEST *EraseBlockStart;
EFI_TPL OldTpl;
EraseBlockStart = NULL;
Device = Partition->Device;
PassThru = Device->Private->PassThru;
EraseBlockStart = AllocateZeroPool (sizeof (EMMC_REQUEST));
if (EraseBlockStart == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
EraseBlockStart->Signature = EMMC_REQUEST_SIGNATURE;
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&Partition->Queue, &EraseBlockStart->Link);
gBS->RestoreTPL (OldTpl);
EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;
EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
EraseBlockStart->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
EraseBlockStart->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_START;
EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
if (Device->SectorAddressing) {
EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
} else {
EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Partition->BlockMedia.BlockSize);
}
EraseBlockStart->IsEnd = IsEnd;
EraseBlockStart->Token = Token;
if ((Token != NULL) && (Token->Event != NULL)) {
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
AsyncIoCallback,
EraseBlockStart,
&EraseBlockStart->Event
);
if (EFI_ERROR (Status)) {
goto Error;
}
} else {
EraseBlockStart->Event = NULL;
}
Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
Error:
if ((Token != NULL) && (Token->Event != NULL)) {
//
// For asynchronous operation, only free request and event in error case.
// The request and event will be freed in asynchronous callback for success case.
//
if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
RemoveEntryList (&EraseBlockStart->Link);
if (EraseBlockStart->Event != NULL) {
gBS->CloseEvent (EraseBlockStart->Event);
}
FreePool (EraseBlockStart);
}
} else {
//
// For synchronous operation, free request whatever the execution result is.
//
if (EraseBlockStart != NULL) {
RemoveEntryList (&EraseBlockStart->Link);
FreePool (EraseBlockStart);
}
}
return Status;
}
/**
Set the erase end address through sync or async I/O request.
@param[in] Partition A pointer to the EMMC_PARTITION instance.
@param[in] EndLba The ending logical block address to be erased.
@param[in] Token A pointer to the token associated with the transaction.
@param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
This parameter is only meaningful in async I/O request.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
EmmcEraseBlockEnd (
IN EMMC_PARTITION *Partition,
IN EFI_LBA EndLba,
IN EFI_BLOCK_IO2_TOKEN *Token,
IN BOOLEAN IsEnd
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EMMC_DEVICE *Device;
EMMC_REQUEST *EraseBlockEnd;
EFI_TPL OldTpl;
EraseBlockEnd = NULL;
Device = Partition->Device;
PassThru = Device->Private->PassThru;
EraseBlockEnd = AllocateZeroPool (sizeof (EMMC_REQUEST));
if (EraseBlockEnd == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
EraseBlockEnd->Signature = EMMC_REQUEST_SIGNATURE;
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&Partition->Queue, &EraseBlockEnd->Link);
gBS->RestoreTPL (OldTpl);
EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;
EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
EraseBlockEnd->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
EraseBlockEnd->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_END;
EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
if (Device->SectorAddressing) {
EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
} else {
EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Partition->BlockMedia.BlockSize);
}
EraseBlockEnd->IsEnd = IsEnd;
EraseBlockEnd->Token = Token;
if ((Token != NULL) && (Token->Event != NULL)) {
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
AsyncIoCallback,
EraseBlockEnd,
&EraseBlockEnd->Event
);
if (EFI_ERROR (Status)) {
goto Error;
}
} else {
EraseBlockEnd->Event = NULL;
}
Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
Error:
if ((Token != NULL) && (Token->Event != NULL)) {
//
// For asynchronous operation, only free request and event in error case.
// The request and event will be freed in asynchronous callback for success case.
//
if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
RemoveEntryList (&EraseBlockEnd->Link);
if (EraseBlockEnd->Event != NULL) {
gBS->CloseEvent (EraseBlockEnd->Event);
}
FreePool (EraseBlockEnd);
}
} else {
//
// For synchronous operation, free request whatever the execution result is.
//
if (EraseBlockEnd != NULL) {
RemoveEntryList (&EraseBlockEnd->Link);
FreePool (EraseBlockEnd);
}
}
return Status;
}
/**
Erase specified blocks through sync or async I/O request.
@param[in] Partition A pointer to the EMMC_PARTITION instance.
@param[in] Token A pointer to the token associated with the transaction.
@param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
This parameter is only meaningful in async I/O request.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
EmmcEraseBlock (
IN EMMC_PARTITION *Partition,
IN EFI_BLOCK_IO2_TOKEN *Token,
IN BOOLEAN IsEnd
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
EMMC_DEVICE *Device;
EMMC_REQUEST *EraseBlock;
EFI_TPL OldTpl;
EraseBlock = NULL;
Device = Partition->Device;
PassThru = Device->Private->PassThru;
EraseBlock = AllocateZeroPool (sizeof (EMMC_REQUEST));
if (EraseBlock == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
EraseBlock->Signature = EMMC_REQUEST_SIGNATURE;
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&Partition->Queue, &EraseBlock->Link);
gBS->RestoreTPL (OldTpl);
EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;
EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
EraseBlock->Packet.Timeout = EMMC_GENERIC_TIMEOUT;
EraseBlock->SdMmcCmdBlk.CommandIndex = EMMC_ERASE;
EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
EraseBlock->IsEnd = IsEnd;
EraseBlock->Token = Token;
if ((Token != NULL) && (Token->Event != NULL)) {
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
AsyncIoCallback,
EraseBlock,
&EraseBlock->Event
);
if (EFI_ERROR (Status)) {
goto Error;
}
} else {
EraseBlock->Event = NULL;
}
Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
Error:
if ((Token != NULL) && (Token->Event != NULL)) {
//
// For asynchronous operation, only free request and event in error case.
// The request and event will be freed in asynchronous callback for success case.
//
if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
RemoveEntryList (&EraseBlock->Link);
if (EraseBlock->Event != NULL) {
gBS->CloseEvent (EraseBlock->Event);
}
FreePool (EraseBlock);
}
} else {
//
// For synchronous operation, free request whatever the execution result is.
//
if (EraseBlock != NULL) {
RemoveEntryList (&EraseBlock->Link);
FreePool (EraseBlock);
}
}
return Status;
}
/**
Erase a specified number of device blocks.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId The media ID that the erase request is for.
@param[in] Lba The starting logical block address to be
erased. The caller is responsible for erasing
only legitimate locations.
@param[in, out] Token A pointer to the token associated with the
transaction.
@param[in] Size The size in bytes to be erased. This must be
a multiple of the physical block size of the
device.
@retval EFI_SUCCESS The erase request was queued if Event is not
NULL. The data was erased correctly to the
device if the Event is NULL.to the device.
@retval EFI_WRITE_PROTECTED The device cannot be erased due to write
protection.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to perform the erase operation.
@retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
valid.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
**/
EFI_STATUS
EFIAPI
EmmcEraseBlocks (
IN EFI_ERASE_BLOCK_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
IN UINTN Size
)
{
EFI_STATUS Status;
EFI_BLOCK_IO_MEDIA *Media;
UINTN BlockSize;
UINTN BlockNum;
EFI_LBA LastLba;
UINT8 PartitionConfig;
EMMC_PARTITION *Partition;
EMMC_DEVICE *Device;
Status = EFI_SUCCESS;
Partition = EMMC_PARTITION_DATA_FROM_ERASEBLK (This);
Device = Partition->Device;
Media = &Partition->BlockMedia;
if (MediaId != Media->MediaId) {
return EFI_MEDIA_CHANGED;
}
if (Media->ReadOnly) {
return EFI_WRITE_PROTECTED;
}
//
// Check parameters.
//
BlockSize = Media->BlockSize;
if ((Size % BlockSize) != 0) {
return EFI_INVALID_PARAMETER;
}
BlockNum = Size / BlockSize;
if ((Lba + BlockNum - 1) > Media->LastBlock) {
return EFI_INVALID_PARAMETER;
}
if ((Token != NULL) && (Token->Event != NULL)) {
Token->TransactionStatus = EFI_SUCCESS;
}
LastLba = Lba + BlockNum - 1;
//
// Check if needs to switch partition access.
//
PartitionConfig = Device->ExtCsd.PartitionConfig;
if ((PartitionConfig & 0x7) != Partition->PartitionType) {
PartitionConfig &= (UINT8)~0x7;
PartitionConfig |= Partition->PartitionType;
Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
if (EFI_ERROR (Status)) {
return Status;
}
Device->ExtCsd.PartitionConfig = PartitionConfig;
}
Status = EmmcEraseBlockStart (Partition, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
if (EFI_ERROR (Status)) {
return Status;
}
Status = EmmcEraseBlockEnd (Partition, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
if (EFI_ERROR (Status)) {
return Status;
}
Status = EmmcEraseBlock (Partition, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((EFI_D_ERROR, "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", Lba, BlockNum, Token->Event, Status));
return Status;
}

View File

@ -4,7 +4,7 @@
This file defines common data structures, macro definitions and some module
internal function header files.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
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
@ -462,5 +462,42 @@ EmmcSecurityProtocolOut (
IN VOID *PayloadBuffer
);
/**
Erase a specified number of device blocks.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId The media ID that the erase request is for.
@param[in] Lba The starting logical block address to be
erased. The caller is responsible for erasing
only legitimate locations.
@param[in, out] Token A pointer to the token associated with the
transaction.
@param[in] Size The size in bytes to be erased. This must be
a multiple of the physical block size of the
device.
@retval EFI_SUCCESS The erase request was queued if Event is not
NULL. The data was erased correctly to the
device if the Event is NULL.to the device.
@retval EFI_WRITE_PROTECTED The device cannot be erased due to write
protection.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to perform the erase operation.
@retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
valid.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
**/
EFI_STATUS
EFIAPI
EmmcEraseBlocks (
IN EFI_ERASE_BLOCK_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
IN UINTN Size
);
#endif

View File

@ -68,6 +68,11 @@ EMMC_PARTITION mEmmcPartitionTemplate = {
EmmcSecurityProtocolIn,
EmmcSecurityProtocolOut
},
{ // EraseBlock
EFI_ERASE_BLOCK_PROTOCOL_REVISION,
1,
EmmcEraseBlocks
},
{
NULL,
NULL
@ -369,6 +374,16 @@ DiscoverAllPartitions (
Partition->Enable = TRUE;
Partition->BlockMedia.LastBlock = DivU64x32 (Capacity, Partition->BlockMedia.BlockSize) - 1;
}
if ((ExtCsd->EraseGroupDef & BIT0) == 0) {
if (Csd->WriteBlLen < 9) {
Partition->EraseBlock.EraseLengthGranularity = 1;
} else {
Partition->EraseBlock.EraseLengthGranularity = (Csd->EraseGrpMult + 1) * (Csd->EraseGrpSize + 1) * (1 << (Csd->WriteBlLen - 9));
}
} else {
Partition->EraseBlock.EraseLengthGranularity = 1024 * ExtCsd->HcEraseGrpSize;
}
}
return EFI_SUCCESS;
@ -438,10 +453,32 @@ InstallProtocolOnPartition (
&Partition->BlockIo2,
NULL
);
if (EFI_ERROR (Status)) {
if (EFI_ERROR (Status)) {
goto Error;
}
if (Partition->PartitionType != EmmcPartitionRPMB) {
Status = gBS->InstallProtocolInterface (
&Partition->Handle,
&gEfiEraseBlockProtocolGuid,
EFI_NATIVE_INTERFACE,
&Partition->EraseBlock
);
if (EFI_ERROR (Status)) {
gBS->UninstallMultipleProtocolInterfaces (
&Partition->Handle,
&gEfiDevicePathProtocolGuid,
Partition->DevicePath,
&gEfiBlockIoProtocolGuid,
&Partition->BlockIo,
&gEfiBlockIo2ProtocolGuid,
&Partition->BlockIo2,
NULL
);
goto Error;
}
}
if (((Partition->PartitionType == EmmcPartitionUserData) ||
(Partition->PartitionType == EmmcPartitionBoot1) ||
(Partition->PartitionType == EmmcPartitionBoot2)) &&
@ -461,6 +498,8 @@ InstallProtocolOnPartition (
&Partition->BlockIo,
&gEfiBlockIo2ProtocolGuid,
&Partition->BlockIo2,
&gEfiEraseBlockProtocolGuid,
&Partition->EraseBlock,
NULL
);
goto Error;
@ -954,6 +993,7 @@ EmmcDxeDriverBindingStop (
EFI_BLOCK_IO_PROTOCOL *BlockIo;
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
EFI_ERASE_BLOCK_PROTOCOL *EraseBlock;
LIST_ENTRY *Link;
LIST_ENTRY *NextLink;
EMMC_REQUEST *Request;
@ -1095,6 +1135,38 @@ EmmcDxeDriverBindingStop (
continue;
}
//
// If Erase Block Protocol is installed, then uninstall this protocol.
//
Status = gBS->OpenProtocol (
ChildHandleBuffer[Index],
&gEfiEraseBlockProtocolGuid,
(VOID **) &EraseBlock,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status)) {
Status = gBS->UninstallProtocolInterface (
ChildHandleBuffer[Index],
&gEfiEraseBlockProtocolGuid,
&Partition->EraseBlock
);
if (EFI_ERROR (Status)) {
gBS->OpenProtocol (
Controller,
&gEfiSdMmcPassThruProtocolGuid,
(VOID **) &Partition->Device->Private->PassThru,
This->DriverBindingHandle,
ChildHandleBuffer[Index],
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
AllChildrenStopped = FALSE;
continue;
}
}
//
// If Storage Security Command Protocol is installed, then uninstall this protocol.
//

View File

@ -25,6 +25,7 @@
#include <Protocol/BlockIo.h>
#include <Protocol/BlockIo2.h>
#include <Protocol/StorageSecurityCommand.h>
#include <Protocol/EraseBlock.h>
#include <Protocol/DevicePath.h>
@ -57,6 +58,9 @@ extern EFI_COMPONENT_NAME2_PROTOCOL gEmmcDxeComponentName2;
#define EMMC_PARTITION_DATA_FROM_SSP(a) \
CR(a, EMMC_PARTITION, StorageSecurity, EMMC_PARTITION_SIGNATURE)
#define EMMC_PARTITION_DATA_FROM_ERASEBLK(a) \
CR(a, EMMC_PARTITION, EraseBlock, EMMC_PARTITION_SIGNATURE)
//
// Take 2.5 seconds as generic time out value, 1 microsecond as unit.
//
@ -97,6 +101,7 @@ typedef struct {
EFI_BLOCK_IO2_PROTOCOL BlockIo2;
EFI_BLOCK_IO_MEDIA BlockMedia;
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
EFI_ERASE_BLOCK_PROTOCOL EraseBlock;
LIST_ENTRY Queue;

View File

@ -4,7 +4,7 @@
# It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer
# access the EMMC device.
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
@ -60,6 +60,7 @@
gEfiBlockIoProtocolGuid ## BY_START
gEfiBlockIo2ProtocolGuid ## BY_START
gEfiStorageSecurityCommandProtocolGuid ## SOMETIMES_PRODUCES
gEfiEraseBlockProtocolGuid ## BY_START
## TO_START
## BY_START
gEfiDevicePathProtocolGuid

View File

@ -970,4 +970,390 @@ SdFlushBlocksEx (
return EFI_SUCCESS;
}
/**
Set the erase start address through sync or async I/O request.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] StartLba The starting logical block address to be erased.
@param[in] Token A pointer to the token associated with the transaction.
@param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
This parameter is only meaningful in async I/O request.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdEraseBlockStart (
IN SD_DEVICE *Device,
IN EFI_LBA StartLba,
IN EFI_BLOCK_IO2_TOKEN *Token,
IN BOOLEAN IsEnd
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
SD_REQUEST *EraseBlockStart;
EFI_TPL OldTpl;
EraseBlockStart = NULL;
PassThru = Device->Private->PassThru;
EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));
if (EraseBlockStart == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&Device->Queue, &EraseBlockStart->Link);
gBS->RestoreTPL (OldTpl);
EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;
EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
EraseBlockStart->Packet.Timeout = SD_GENERIC_TIMEOUT;
EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;
EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
if (Device->SectorAddressing) {
EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
} else {
EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->BlockMedia.BlockSize);
}
EraseBlockStart->IsEnd = IsEnd;
EraseBlockStart->Token = Token;
if ((Token != NULL) && (Token->Event != NULL)) {
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
AsyncIoCallback,
EraseBlockStart,
&EraseBlockStart->Event
);
if (EFI_ERROR (Status)) {
goto Error;
}
} else {
EraseBlockStart->Event = NULL;
}
Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
Error:
if ((Token != NULL) && (Token->Event != NULL)) {
//
// For asynchronous operation, only free request and event in error case.
// The request and event will be freed in asynchronous callback for success case.
//
if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
RemoveEntryList (&EraseBlockStart->Link);
if (EraseBlockStart->Event != NULL) {
gBS->CloseEvent (EraseBlockStart->Event);
}
FreePool (EraseBlockStart);
}
} else {
//
// For synchronous operation, free request whatever the execution result is.
//
if (EraseBlockStart != NULL) {
RemoveEntryList (&EraseBlockStart->Link);
FreePool (EraseBlockStart);
}
}
return Status;
}
/**
Set the erase end address through sync or async I/O request.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] EndLba The ending logical block address to be erased.
@param[in] Token A pointer to the token associated with the transaction.
@param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
This parameter is only meaningful in async I/O request.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdEraseBlockEnd (
IN SD_DEVICE *Device,
IN EFI_LBA EndLba,
IN EFI_BLOCK_IO2_TOKEN *Token,
IN BOOLEAN IsEnd
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
SD_REQUEST *EraseBlockEnd;
EFI_TPL OldTpl;
EraseBlockEnd = NULL;
PassThru = Device->Private->PassThru;
EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));
if (EraseBlockEnd == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&Device->Queue, &EraseBlockEnd->Link);
gBS->RestoreTPL (OldTpl);
EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;
EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
EraseBlockEnd->Packet.Timeout = SD_GENERIC_TIMEOUT;
EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;
EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
if (Device->SectorAddressing) {
EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
} else {
EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->BlockMedia.BlockSize);
}
EraseBlockEnd->IsEnd = IsEnd;
EraseBlockEnd->Token = Token;
if ((Token != NULL) && (Token->Event != NULL)) {
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
AsyncIoCallback,
EraseBlockEnd,
&EraseBlockEnd->Event
);
if (EFI_ERROR (Status)) {
goto Error;
}
} else {
EraseBlockEnd->Event = NULL;
}
Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
Error:
if ((Token != NULL) && (Token->Event != NULL)) {
//
// For asynchronous operation, only free request and event in error case.
// The request and event will be freed in asynchronous callback for success case.
//
if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
RemoveEntryList (&EraseBlockEnd->Link);
if (EraseBlockEnd->Event != NULL) {
gBS->CloseEvent (EraseBlockEnd->Event);
}
FreePool (EraseBlockEnd);
}
} else {
//
// For synchronous operation, free request whatever the execution result is.
//
if (EraseBlockEnd != NULL) {
RemoveEntryList (&EraseBlockEnd->Link);
FreePool (EraseBlockEnd);
}
}
return Status;
}
/**
Erase specified blocks through sync or async I/O request.
@param[in] Device A pointer to the SD_DEVICE instance.
@param[in] Token A pointer to the token associated with the transaction.
@param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
This parameter is only meaningful in async I/O request.
@retval EFI_SUCCESS The request is executed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
@retval Others The request could not be executed successfully.
**/
EFI_STATUS
SdEraseBlock (
IN SD_DEVICE *Device,
IN EFI_BLOCK_IO2_TOKEN *Token,
IN BOOLEAN IsEnd
)
{
EFI_STATUS Status;
EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
SD_REQUEST *EraseBlock;
EFI_TPL OldTpl;
EraseBlock = NULL;
PassThru = Device->Private->PassThru;
EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));
if (EraseBlock == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error;
}
EraseBlock->Signature = SD_REQUEST_SIGNATURE;
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&Device->Queue, &EraseBlock->Link);
gBS->RestoreTPL (OldTpl);
EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;
EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
EraseBlock->Packet.Timeout = SD_GENERIC_TIMEOUT;
EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;
EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
EraseBlock->IsEnd = IsEnd;
EraseBlock->Token = Token;
if ((Token != NULL) && (Token->Event != NULL)) {
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
AsyncIoCallback,
EraseBlock,
&EraseBlock->Event
);
if (EFI_ERROR (Status)) {
goto Error;
}
} else {
EraseBlock->Event = NULL;
}
Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
Error:
if ((Token != NULL) && (Token->Event != NULL)) {
//
// For asynchronous operation, only free request and event in error case.
// The request and event will be freed in asynchronous callback for success case.
//
if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
RemoveEntryList (&EraseBlock->Link);
if (EraseBlock->Event != NULL) {
gBS->CloseEvent (EraseBlock->Event);
}
FreePool (EraseBlock);
}
} else {
//
// For synchronous operation, free request whatever the execution result is.
//
if (EraseBlock != NULL) {
RemoveEntryList (&EraseBlock->Link);
FreePool (EraseBlock);
}
}
return Status;
}
/**
Erase a specified number of device blocks.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId The media ID that the erase request is for.
@param[in] Lba The starting logical block address to be
erased. The caller is responsible for erasing
only legitimate locations.
@param[in, out] Token A pointer to the token associated with the
transaction.
@param[in] Size The size in bytes to be erased. This must be
a multiple of the physical block size of the
device.
@retval EFI_SUCCESS The erase request was queued if Event is not
NULL. The data was erased correctly to the
device if the Event is NULL.to the device.
@retval EFI_WRITE_PROTECTED The device cannot be erased due to write
protection.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to perform the erase operation.
@retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
valid.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
**/
EFI_STATUS
EFIAPI
SdEraseBlocks (
IN EFI_ERASE_BLOCK_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
IN UINTN Size
)
{
EFI_STATUS Status;
EFI_BLOCK_IO_MEDIA *Media;
UINTN BlockSize;
UINTN BlockNum;
EFI_LBA LastLba;
SD_DEVICE *Device;
Status = EFI_SUCCESS;
Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);
Media = &Device->BlockMedia;
if (MediaId != Media->MediaId) {
return EFI_MEDIA_CHANGED;
}
if (Media->ReadOnly) {
return EFI_WRITE_PROTECTED;
}
//
// Check parameters.
//
BlockSize = Media->BlockSize;
if ((Size % BlockSize) != 0) {
return EFI_INVALID_PARAMETER;
}
BlockNum = Size / BlockSize;
if ((Lba + BlockNum - 1) > Media->LastBlock) {
return EFI_INVALID_PARAMETER;
}
if ((Token != NULL) && (Token->Event != NULL)) {
Token->TransactionStatus = EFI_SUCCESS;
}
LastLba = Lba + BlockNum - 1;
Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
if (EFI_ERROR (Status)) {
return Status;
}
Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
if (EFI_ERROR (Status)) {
return Status;
}
Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((EFI_D_ERROR, "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", Lba, BlockNum, Token->Event, Status));
return Status;
}

View File

@ -4,7 +4,7 @@
This file defines common data structures, macro definitions and some module
internal function header files.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
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
@ -217,5 +217,42 @@ SdFlushBlocksEx (
IN OUT EFI_BLOCK_IO2_TOKEN *Token
);
/**
Erase a specified number of device blocks.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId The media ID that the erase request is for.
@param[in] Lba The starting logical block address to be
erased. The caller is responsible for erasing
only legitimate locations.
@param[in, out] Token A pointer to the token associated with the
transaction.
@param[in] Size The size in bytes to be erased. This must be
a multiple of the physical block size of the
device.
@retval EFI_SUCCESS The erase request was queued if Event is not
NULL. The data was erased correctly to the
device if the Event is NULL.to the device.
@retval EFI_WRITE_PROTECTED The device cannot be erased due to write
protection.
@retval EFI_DEVICE_ERROR The device reported an error while attempting
to perform the erase operation.
@retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
valid.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
**/
EFI_STATUS
EFIAPI
SdEraseBlocks (
IN EFI_ERASE_BLOCK_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
IN UINTN Size
);
#endif

View File

@ -64,6 +64,11 @@ SD_DEVICE mSdDeviceTemplate = {
0, // IoAlign
0 // LastBlock
},
{ // EraseBlock
EFI_ERASE_BLOCK_PROTOCOL_REVISION,
1,
SdEraseBlocks
},
{ // Queue
NULL,
NULL
@ -247,6 +252,12 @@ DiscoverUserArea (
Device->BlockMedia.LogicalPartition = FALSE;
Device->BlockMedia.LastBlock = DivU64x32 (Capacity, Device->BlockMedia.BlockSize) - 1;
if (Csd->EraseBlkEn) {
Device->EraseBlock.EraseLengthGranularity = 1;
} else {
Device->EraseBlock.EraseLengthGranularity = (Csd->SectorSize + 1) * (1 << (Csd->WriteBlLen - 9));
}
return Status;
}
@ -369,6 +380,8 @@ DiscoverSdDevice (
&Device->BlockIo,
&gEfiBlockIo2ProtocolGuid,
&Device->BlockIo2,
&gEfiEraseBlockProtocolGuid,
&Device->EraseBlock,
NULL
);
@ -825,6 +838,8 @@ SdDxeDriverBindingStop (
&Device->BlockIo,
&gEfiBlockIo2ProtocolGuid,
&Device->BlockIo2,
&gEfiEraseBlockProtocolGuid,
&Device->EraseBlock,
NULL
);
if (EFI_ERROR (Status)) {

View File

@ -4,7 +4,7 @@
This file defines common data structures, macro definitions and some module
internal function header files.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
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
@ -24,6 +24,7 @@
#include <Protocol/SdMmcPassThru.h>
#include <Protocol/BlockIo.h>
#include <Protocol/BlockIo2.h>
#include <Protocol/EraseBlock.h>
#include <Protocol/DevicePath.h>
@ -53,6 +54,9 @@ extern EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2;
#define SD_DEVICE_DATA_FROM_BLKIO2(a) \
CR(a, SD_DEVICE, BlockIo2, SD_DEVICE_SIGNATURE)
#define SD_DEVICE_DATA_FROM_ERASEBLK(a) \
CR(a, SD_DEVICE, EraseBlock, SD_DEVICE_SIGNATURE)
//
// Take 2.5 seconds as generic time out value, 1 microsecond as unit.
//
@ -95,6 +99,7 @@ struct _SD_DEVICE {
EFI_BLOCK_IO_PROTOCOL BlockIo;
EFI_BLOCK_IO2_PROTOCOL BlockIo2;
EFI_BLOCK_IO_MEDIA BlockMedia;
EFI_ERASE_BLOCK_PROTOCOL EraseBlock;
LIST_ENTRY Queue;

View File

@ -4,7 +4,7 @@
# It produces BlockIo and BlockIo2 protocols to allow upper layer
# access the SD memory card device.
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
@ -59,6 +59,7 @@
gEfiSdMmcPassThruProtocolGuid ## TO_START
gEfiBlockIoProtocolGuid ## BY_START
gEfiBlockIo2ProtocolGuid ## BY_START
gEfiEraseBlockProtocolGuid ## BY_START
## TO_START
## BY_START
gEfiDevicePathProtocolGuid