/** @file\r
The helper functions for BlockIo and BlockIo2 protocol.\r
\r
- Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "SdDxe.h"\r
\r
/**\r
- Nonblocking I/O callback funtion when the event is signaled.\r
+ Nonblocking I/O callback function when the event is signaled.\r
\r
@param[in] Event The Event this notify function registered to.\r
@param[in] Context Pointer to the context data registered to the\r
}\r
\r
RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);\r
gBS->RestoreTPL (OldTpl);\r
RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk;\r
if ((Token != NULL) && (Token->Event != NULL)) {\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
AsyncIoCallback,\r
RwSingleBlkReq,\r
&RwSingleBlkReq->Event\r
// The request and event will be freed in asynchronous callback for success case.\r
//\r
if (EFI_ERROR (Status) && (RwSingleBlkReq != NULL)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
RemoveEntryList (&RwSingleBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
if (RwSingleBlkReq->Event != NULL) {\r
gBS->CloseEvent (RwSingleBlkReq->Event);\r
}\r
// For synchronous operation, free request whatever the execution result is.\r
//\r
if (RwSingleBlkReq != NULL) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
RemoveEntryList (&RwSingleBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
FreePool (RwSingleBlkReq);\r
}\r
}\r
}\r
\r
RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);\r
gBS->RestoreTPL (OldTpl);\r
RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;\r
if ((Token != NULL) && (Token->Event != NULL)) {\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
+ TPL_NOTIFY,\r
AsyncIoCallback,\r
RwMultiBlkReq,\r
&RwMultiBlkReq->Event\r
// The request and event will be freed in asynchronous callback for success case.\r
//\r
if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
RemoveEntryList (&RwMultiBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
if (RwMultiBlkReq->Event != NULL) {\r
gBS->CloseEvent (RwMultiBlkReq->Event);\r
}\r
// For synchronous operation, free request whatever the execution result is.\r
//\r
if (RwMultiBlkReq != NULL) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
RemoveEntryList (&RwMultiBlkReq->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
FreePool (RwMultiBlkReq);\r
}\r
}\r
@retval EFI_WRITE_PROTECTED The device can not be read/written to.\r
@retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.\r
@retval EFI_NO_MEDIA There is no media in the device.\r
- @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
@retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,\r
or the buffer is not on proper alignment.\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- DEBUG ((EFI_D_INFO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", IsRead ? "Read" : "Write", Lba, BlockNum, Token->Event, Status));\r
-\r
+ DEBUG ((DEBUG_BLKIO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",\r
+ IsRead ? "Read" : "Write", Lba, BlockNum,\r
+ (Token != NULL) ? Token->Event : NULL, Status));\r
Lba += BlockNum;\r
Buffer = (UINT8*)Buffer + BufferSize;\r
Remaining -= BlockNum;\r
@retval EFI_SUCCESS The data was read correctly from the device.\r
@retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
@retval EFI_NO_MEDIA There is no media in the device.\r
- @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
or the buffer is not on proper alignment.\r
@retval EFI_WRITE_PROTECTED The device can not be written to.\r
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
@retval EFI_NO_MEDIA There is no media in the device.\r
- @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
or the buffer is not on proper alignment.\r
\r
Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
\r
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
for (Link = GetFirstNode (&Device->Queue);\r
!IsNull (&Device->Queue, Link);\r
Link = NextLink) {\r
@retval EFI_WRITE_PROTECTED The device can not be written to.\r
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
@retval EFI_NO_MEDIA There is no media in the device.\r
- @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
or the buffer is not on proper alignment.\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Set the erase start address through sync or async I/O request.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] StartLba The starting logical block address to be erased.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdEraseBlockStart (\r
+ IN SD_DEVICE *Device,\r
+ IN EFI_LBA StartLba,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ SD_REQUEST *EraseBlockStart;\r
+ EFI_TPL OldTpl;\r
+\r
+ EraseBlockStart = NULL;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));\r
+ if (EraseBlockStart == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ InsertTailList (&Device->Queue, &EraseBlockStart->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;\r
+ EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;\r
+ EraseBlockStart->Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;\r
+ EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+\r
+ if (Device->SectorAddressing) {\r
+ EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;\r
+ } else {\r
+ EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->BlockMedia.BlockSize);\r
+ }\r
+\r
+ EraseBlockStart->IsEnd = IsEnd;\r
+ EraseBlockStart->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ AsyncIoCallback,\r
+ EraseBlockStart,\r
+ &EraseBlockStart->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ EraseBlockStart->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ RemoveEntryList (&EraseBlockStart->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ if (EraseBlockStart->Event != NULL) {\r
+ gBS->CloseEvent (EraseBlockStart->Event);\r
+ }\r
+ FreePool (EraseBlockStart);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (EraseBlockStart != NULL) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ RemoveEntryList (&EraseBlockStart->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ FreePool (EraseBlockStart);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set the erase end address through sync or async I/O request.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] EndLba The ending logical block address to be erased.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdEraseBlockEnd (\r
+ IN SD_DEVICE *Device,\r
+ IN EFI_LBA EndLba,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ SD_REQUEST *EraseBlockEnd;\r
+ EFI_TPL OldTpl;\r
+\r
+ EraseBlockEnd = NULL;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));\r
+ if (EraseBlockEnd == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ InsertTailList (&Device->Queue, &EraseBlockEnd->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;\r
+ EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;\r
+ EraseBlockEnd->Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;\r
+ EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+\r
+ if (Device->SectorAddressing) {\r
+ EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;\r
+ } else {\r
+ EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->BlockMedia.BlockSize);\r
+ }\r
+\r
+ EraseBlockEnd->IsEnd = IsEnd;\r
+ EraseBlockEnd->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ AsyncIoCallback,\r
+ EraseBlockEnd,\r
+ &EraseBlockEnd->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ EraseBlockEnd->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ RemoveEntryList (&EraseBlockEnd->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ if (EraseBlockEnd->Event != NULL) {\r
+ gBS->CloseEvent (EraseBlockEnd->Event);\r
+ }\r
+ FreePool (EraseBlockEnd);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (EraseBlockEnd != NULL) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ RemoveEntryList (&EraseBlockEnd->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ FreePool (EraseBlockEnd);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Erase specified blocks through sync or async I/O request.\r
+\r
+ @param[in] Device A pointer to the SD_DEVICE instance.\r
+ @param[in] Token A pointer to the token associated with the transaction.\r
+ @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.\r
+ This parameter is only meaningful in async I/O request.\r
+\r
+ @retval EFI_SUCCESS The request is executed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.\r
+ @retval Others The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdEraseBlock (\r
+ IN SD_DEVICE *Device,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN BOOLEAN IsEnd\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+ SD_REQUEST *EraseBlock;\r
+ EFI_TPL OldTpl;\r
+\r
+ EraseBlock = NULL;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));\r
+ if (EraseBlock == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ EraseBlock->Signature = SD_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ InsertTailList (&Device->Queue, &EraseBlock->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;\r
+ EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;\r
+ EraseBlock->Packet.Timeout = SD_GENERIC_TIMEOUT;\r
+\r
+ EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;\r
+ EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
+ EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+\r
+ EraseBlock->IsEnd = IsEnd;\r
+ EraseBlock->Token = Token;\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ AsyncIoCallback,\r
+ EraseBlock,\r
+ &EraseBlock->Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else {\r
+ EraseBlock->Event = NULL;\r
+ }\r
+\r
+ Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);\r
+\r
+Error:\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ //\r
+ // For asynchronous operation, only free request and event in error case.\r
+ // The request and event will be freed in asynchronous callback for success case.\r
+ //\r
+ if (EFI_ERROR (Status) && (EraseBlock != NULL)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ RemoveEntryList (&EraseBlock->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ if (EraseBlock->Event != NULL) {\r
+ gBS->CloseEvent (EraseBlock->Event);\r
+ }\r
+ FreePool (EraseBlock);\r
+ }\r
+ } else {\r
+ //\r
+ // For synchronous operation, free request whatever the execution result is.\r
+ //\r
+ if (EraseBlock != NULL) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ RemoveEntryList (&EraseBlock->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ FreePool (EraseBlock);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Erase a specified number of device blocks.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId The media ID that the erase request is for.\r
+ @param[in] Lba The starting logical block address to be\r
+ erased. The caller is responsible for erasing\r
+ only legitimate locations.\r
+ @param[in, out] Token A pointer to the token associated with the\r
+ transaction.\r
+ @param[in] Size The size in bytes to be erased. This must be\r
+ a multiple of the physical block size of the\r
+ device.\r
+\r
+ @retval EFI_SUCCESS The erase request was queued if Event is not\r
+ NULL. The data was erased correctly to the\r
+ device if the Event is NULL.to the device.\r
+ @retval EFI_WRITE_PROTECTED The device cannot be erased due to write\r
+ protection.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the erase operation.\r
+ @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not\r
+ valid.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdEraseBlocks (\r
+ IN EFI_ERASE_BLOCK_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_ERASE_BLOCK_TOKEN *Token,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN BlockNum;\r
+ EFI_LBA LastLba;\r
+ SD_DEVICE *Device;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);\r
+ Media = &Device->BlockMedia;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (Media->ReadOnly) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ BlockSize = Media->BlockSize;\r
+ if ((Size % BlockSize) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ BlockNum = Size / BlockSize;\r
+ if ((Lba + BlockNum - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ }\r
+\r
+ LastLba = Lba + BlockNum - 1;\r
+\r
+ Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_ERROR, "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", Lba, BlockNum, Token->Event, Status));\r
+\r
+ return Status;\r
+}\r
\r