From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c | 1381 +++++++++++++++++++++++ 1 file changed, 1381 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c (limited to 'roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c') diff --git a/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c new file mode 100644 index 000000000..721f26437 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c @@ -0,0 +1,1381 @@ +/** @file + The helper functions for BlockIo and BlockIo2 protocol. + + Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SdDxe.h" + +/** + Nonblocking I/O callback function when the 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 +AsyncIoCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + SD_REQUEST *Request; + + gBS->CloseEvent (Event); + + Request = (SD_REQUEST *) Context; + + DEBUG_CODE_BEGIN (); + DEBUG ((EFI_D_INFO, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n", + Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument, + Request->Packet.TransactionStatus)); + DEBUG_CODE_END (); + + if (EFI_ERROR (Request->Packet.TransactionStatus)) { + Request->Token->TransactionStatus = Request->Packet.TransactionStatus; + } + + RemoveEntryList (&Request->Link); + + if (Request->IsEnd) { + gBS->SignalEvent (Request->Token->Event); + } + + FreePool (Request); +} + +/** + Send command SET_RELATIVE_ADDRESS to the device to set the device address. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[out] Rca The relative device address to assign. + + @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 +SdSetRca ( + IN SD_DEVICE *Device, + OUT UINT16 *Rca + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + + PassThru = Device->Private->PassThru; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6; + + Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL); + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0)); + *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16); + } + + return Status; +} + +/** + Send command SELECT to the device to select/deselect the device. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[in] Rca The relative device address to use. + + @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 +SdSelect ( + IN SD_DEVICE *Device, + IN UINT16 Rca + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + + PassThru = Device->Private->PassThru; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + if (Rca != 0) { + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b; + } + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL); + + return Status; +} + +/** + Send command SEND_STATUS to the device to get device status. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[in] Rca The relative device address to use. + @param[out] DevStatus The buffer to store the device status. + + @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 +SdSendStatus ( + IN SD_DEVICE *Device, + IN UINT16 Rca, + OUT UINT32 *DevStatus + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + + PassThru = Device->Private->PassThru; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL); + if (!EFI_ERROR (Status)) { + CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32)); + } + return Status; +} + +/** + Send command SEND_CSD to the device to get the CSD register data. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[in] Rca The relative device address to use. + @param[out] Csd The buffer to store the SD_CSD register data. + + @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 +SdGetCsd ( + IN SD_DEVICE *Device, + IN UINT16 Rca, + OUT SD_CSD *Csd + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + + PassThru = Device->Private->PassThru; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + ZeroMem (Csd, sizeof (SD_CSD)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_CSD; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL); + + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1); + } + + return Status; +} + +/** + Send command SEND_CID to the device to get the CID register data. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[in] Rca The relative device address to use. + @param[out] Cid The buffer to store the SD_CID register data. + + @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 +SdGetCid ( + IN SD_DEVICE *Device, + IN UINT16 Rca, + OUT SD_CID *Cid + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; + EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk; + EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; + + PassThru = Device->Private->PassThru; + + ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); + ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); + ZeroMem (&Packet, sizeof (Packet)); + ZeroMem (Cid, sizeof (SD_CID)); + + Packet.SdMmcCmdBlk = &SdMmcCmdBlk; + Packet.SdMmcStatusBlk = &SdMmcStatusBlk; + Packet.Timeout = SD_GENERIC_TIMEOUT; + + SdMmcCmdBlk.CommandIndex = SD_SEND_CID; + SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc; + SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2; + SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16; + + Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL); + + if (!EFI_ERROR (Status)) { + // + // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12. + // + CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CID) - 1); + } + + return Status; +} + +/** + Read/write single block through sync or async I/O request. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[in] Lba The starting logical block address to be read/written. + The caller is responsible for reading/writing to only + legitimate locations. + @param[in] Buffer A pointer to the destination/source buffer for the data. + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[in] IsRead Indicates it is a read or write operation. + @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 +SdRwSingleBlock ( + IN SD_DEVICE *Device, + IN EFI_LBA Lba, + IN VOID *Buffer, + IN UINTN BufferSize, + IN BOOLEAN IsRead, + IN EFI_BLOCK_IO2_TOKEN *Token, + IN BOOLEAN IsEnd + ) +{ + EFI_STATUS Status; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + SD_REQUEST *RwSingleBlkReq; + EFI_TPL OldTpl; + + RwSingleBlkReq = NULL; + PassThru = Device->Private->PassThru; + + RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST)); + if (RwSingleBlkReq == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE; + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Device->Queue, &RwSingleBlkReq->Link); + gBS->RestoreTPL (OldTpl); + RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk; + RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk; + // + // Calculate timeout value through the below formula. + // Timeout = (transfer size) / (2MB/s). + // Taking 2MB/s as divisor as it's the lowest transfer speed + // above class 2. + // Refer to SD Physical Layer Simplified spec section 3.4 for details. + // + RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000; + + if (IsRead) { + RwSingleBlkReq->Packet.InDataBuffer = Buffer; + RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize; + + RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK; + RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + } else { + RwSingleBlkReq->Packet.OutDataBuffer = Buffer; + RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize; + + RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK; + RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + } + + if (Device->SectorAddressing) { + RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba; + } else { + RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize); + } + + RwSingleBlkReq->IsEnd = IsEnd; + RwSingleBlkReq->Token = Token; + + if ((Token != NULL) && (Token->Event != NULL)) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + AsyncIoCallback, + RwSingleBlkReq, + &RwSingleBlkReq->Event + ); + if (EFI_ERROR (Status)) { + goto Error; + } + } else { + RwSingleBlkReq->Event = NULL; + } + + Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->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) && (RwSingleBlkReq != NULL)) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&RwSingleBlkReq->Link); + gBS->RestoreTPL (OldTpl); + if (RwSingleBlkReq->Event != NULL) { + gBS->CloseEvent (RwSingleBlkReq->Event); + } + FreePool (RwSingleBlkReq); + } + } else { + // + // For synchronous operation, free request whatever the execution result is. + // + if (RwSingleBlkReq != NULL) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&RwSingleBlkReq->Link); + gBS->RestoreTPL (OldTpl); + FreePool (RwSingleBlkReq); + } + } + + return Status; +} + +/** + Read/write multiple blocks through sync or async I/O request. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[in] Lba The starting logical block address to be read/written. + The caller is responsible for reading/writing to only + legitimate locations. + @param[in] Buffer A pointer to the destination/source buffer for the data. + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[in] IsRead Indicates it is a read or write operation. + @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 +SdRwMultiBlocks ( + IN SD_DEVICE *Device, + IN EFI_LBA Lba, + IN VOID *Buffer, + IN UINTN BufferSize, + IN BOOLEAN IsRead, + IN EFI_BLOCK_IO2_TOKEN *Token, + IN BOOLEAN IsEnd + ) +{ + EFI_STATUS Status; + SD_REQUEST *RwMultiBlkReq; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + EFI_TPL OldTpl; + + RwMultiBlkReq = NULL; + + PassThru = Device->Private->PassThru; + + RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST)); + if (RwMultiBlkReq == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE; + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + InsertTailList (&Device->Queue, &RwMultiBlkReq->Link); + gBS->RestoreTPL (OldTpl); + RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk; + RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk; + // + // Calculate timeout value through the below formula. + // Timeout = (transfer size) / (2MB/s). + // Taking 2MB/s as divisor as it's the lowest transfer speed + // above class 2. + // Refer to SD Physical Layer Simplified spec section 3.4 for details. + // + RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000; + + if (IsRead) { + RwMultiBlkReq->Packet.InDataBuffer = Buffer; + RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize; + + RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK; + RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + } else { + RwMultiBlkReq->Packet.OutDataBuffer = Buffer; + RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize; + + RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK; + RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc; + RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1; + } + + if (Device->SectorAddressing) { + RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba; + } else { + RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize); + } + + RwMultiBlkReq->IsEnd = IsEnd; + RwMultiBlkReq->Token = Token; + + if ((Token != NULL) && (Token->Event != NULL)) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + AsyncIoCallback, + RwMultiBlkReq, + &RwMultiBlkReq->Event + ); + if (EFI_ERROR (Status)) { + goto Error; + } + } else { + RwMultiBlkReq->Event = NULL; + } + + Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->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) && (RwMultiBlkReq != NULL)) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&RwMultiBlkReq->Link); + gBS->RestoreTPL (OldTpl); + if (RwMultiBlkReq->Event != NULL) { + gBS->CloseEvent (RwMultiBlkReq->Event); + } + FreePool (RwMultiBlkReq); + } + } else { + // + // For synchronous operation, free request whatever the execution result is. + // + if (RwMultiBlkReq != NULL) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&RwMultiBlkReq->Link); + gBS->RestoreTPL (OldTpl); + FreePool (RwMultiBlkReq); + } + } + + return Status; +} + +/** + This function transfers data from/to the sd memory card device. + + @param[in] Device A pointer to the SD_DEVICE instance. + @param[in] MediaId The media ID that the read/write request is for. + @param[in] Lba The starting logical block address to be read/written. + The caller is responsible for reading/writing to only + legitimate locations. + @param[in, out] Buffer A pointer to the destination/source buffer for the data. + @param[in] BufferSize Size of Buffer, must be a multiple of device block size. + @param[in] IsRead Indicates it is a read or write operation. + @param[in, out] Token A pointer to the token associated with the transaction. + + @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_DEVICE_ERROR The device reported an error while performing the read/write. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId does not match 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 read/write request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +SdReadWrite ( + IN SD_DEVICE *Device, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN OUT VOID *Buffer, + IN UINTN BufferSize, + IN BOOLEAN IsRead, + IN OUT EFI_BLOCK_IO2_TOKEN *Token + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN BlockNum; + UINTN IoAlign; + UINTN Remaining; + UINT32 MaxBlock; + BOOLEAN LastRw; + + Status = EFI_SUCCESS; + Media = &Device->BlockMedia; + LastRw = FALSE; + + if (MediaId != Media->MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (!IsRead && Media->ReadOnly) { + return EFI_WRITE_PROTECTED; + } + + // + // Check parameters. + // + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize == 0) { + if ((Token != NULL) && (Token->Event != NULL)) { + Token->TransactionStatus = EFI_SUCCESS; + gBS->SignalEvent (Token->Event); + } + return EFI_SUCCESS; + } + + BlockSize = Media->BlockSize; + if ((BufferSize % BlockSize) != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + BlockNum = BufferSize / BlockSize; + if ((Lba + BlockNum - 1) > Media->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + IoAlign = Media->IoAlign; + if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + if ((Token != NULL) && (Token->Event != NULL)) { + Token->TransactionStatus = EFI_SUCCESS; + } + + // + // Start to execute data transfer. The max block number in single cmd is 65535 blocks. + // + Remaining = BlockNum; + MaxBlock = 0xFFFF; + + while (Remaining > 0) { + if (Remaining <= MaxBlock) { + BlockNum = Remaining; + LastRw = TRUE; + } else { + BlockNum = MaxBlock; + } + + BufferSize = BlockNum * BlockSize; + if (BlockNum == 1) { + Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw); + } else { + Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw); + } + if (EFI_ERROR (Status)) { + return Status; + } + DEBUG ((DEBUG_BLKIO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", + IsRead ? "Read" : "Write", Lba, BlockNum, + (Token != NULL) ? Token->Event : NULL, Status)); + Lba += BlockNum; + Buffer = (UINT8*)Buffer + BufferSize; + Remaining -= BlockNum; + } + + return Status; +} + +/** + Reset the Block Device. + + @param This Indicates a pointer to the calling context. + @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 +SdReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_STATUS Status; + SD_DEVICE *Device; + EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru; + + Device = SD_DEVICE_DATA_FROM_BLKIO (This); + + PassThru = Device->Private->PassThru; + Status = PassThru->ResetDevice (PassThru, Device->Slot); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + Read BufferSize bytes from Lba into Buffer. + + @param This Indicates a pointer to the calling context. + @param MediaId Id of the media, changes every time the media is replaced. + @param Lba The starting Logical Block Address to read from + @param BufferSize Size of Buffer, must be a multiple of device block size. + @param Buffer 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 data was read correctly from the device. + @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 does not match 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 read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +SdReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + SD_DEVICE *Device; + + Device = SD_DEVICE_DATA_FROM_BLKIO (This); + + Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL); + return Status; +} + +/** + Write BufferSize bytes from Lba into Buffer. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the write request is for. + @param Lba The starting logical block address to be written. The caller is + responsible for writing to only legitimate locations. + @param BufferSize Size of Buffer, must be a multiple of device block size. + @param 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_CHANGED The MediaId does not match 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 +SdWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + SD_DEVICE *Device; + + Device = SD_DEVICE_DATA_FROM_BLKIO (This); + + Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL); + return Status; +} + +/** + Flush the Block Device. + + @param This Indicates a pointer to the calling context. + + @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 +SdFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + // + // return directly + // + 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 +SdResetEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + SD_DEVICE *Device; + LIST_ENTRY *Link; + LIST_ENTRY *NextLink; + SD_REQUEST *Request; + EFI_TPL OldTpl; + + Device = SD_DEVICE_DATA_FROM_BLKIO2 (This); + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + for (Link = GetFirstNode (&Device->Queue); + !IsNull (&Device->Queue, Link); + Link = NextLink) { + NextLink = GetNextNode (&Device->Queue, Link); + RemoveEntryList (Link); + + Request = SD_REQUEST_FROM_LINK (Link); + + gBS->CloseEvent (Request->Event); + Request->Token->TransactionStatus = EFI_ABORTED; + + if (Request->IsEnd) { + gBS->SignalEvent (Request->Token->Event); + } + + FreePool (Request); + } + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; +} + +/** + 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 +SdReadBlocksEx ( + 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 + ) +{ + EFI_STATUS Status; + SD_DEVICE *Device; + + Device = SD_DEVICE_DATA_FROM_BLKIO2 (This); + + Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token); + return Status; +} + +/** + 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_CHANGED The MediaId does not match 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 +SdWriteBlocksEx ( + 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 + ) +{ + EFI_STATUS Status; + SD_DEVICE *Device; + + Device = SD_DEVICE_DATA_FROM_BLKIO2 (This); + + Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token); + return Status; +} + +/** + 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 +SdFlushBlocksEx ( + IN EFI_BLOCK_IO2_PROTOCOL *This, + IN OUT EFI_BLOCK_IO2_TOKEN *Token + ) +{ + // + // Signal event and return directly. + // + if (Token != NULL && Token->Event != NULL) { + Token->TransactionStatus = EFI_SUCCESS; + gBS->SignalEvent (Token->Event); + } + + 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_NOTIFY); + 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_NOTIFY, + 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)) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&EraseBlockStart->Link); + gBS->RestoreTPL (OldTpl); + if (EraseBlockStart->Event != NULL) { + gBS->CloseEvent (EraseBlockStart->Event); + } + FreePool (EraseBlockStart); + } + } else { + // + // For synchronous operation, free request whatever the execution result is. + // + if (EraseBlockStart != NULL) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&EraseBlockStart->Link); + gBS->RestoreTPL (OldTpl); + 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_NOTIFY); + 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_NOTIFY, + 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)) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&EraseBlockEnd->Link); + gBS->RestoreTPL (OldTpl); + if (EraseBlockEnd->Event != NULL) { + gBS->CloseEvent (EraseBlockEnd->Event); + } + FreePool (EraseBlockEnd); + } + } else { + // + // For synchronous operation, free request whatever the execution result is. + // + if (EraseBlockEnd != NULL) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&EraseBlockEnd->Link); + gBS->RestoreTPL (OldTpl); + 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_NOTIFY); + 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_NOTIFY, + 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)) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&EraseBlock->Link); + gBS->RestoreTPL (OldTpl); + if (EraseBlock->Event != NULL) { + gBS->CloseEvent (EraseBlock->Event); + } + FreePool (EraseBlock); + } + } else { + // + // For synchronous operation, free request whatever the execution result is. + // + if (EraseBlock != NULL) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + RemoveEntryList (&EraseBlock->Link); + gBS->RestoreTPL (OldTpl); + 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 (( + DEBUG_INFO, + "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", + Lba, + BlockNum, + (Token != NULL) ? Token->Event : NULL, + Status + )); + + return Status; +} + -- cgit 1.2.3-korg