return Status;\r
}\r
\r
+/**\r
+ Set the erase start address through sync or async I/O request.\r
+\r
+ @param[in] Partition A pointer to the EMMC_PARTITION 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
+EmmcEraseBlockStart (\r
+ IN EMMC_PARTITION *Partition,\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
+ EMMC_DEVICE *Device;\r
+ EMMC_REQUEST *EraseBlockStart;\r
+ EFI_TPL OldTpl;\r
+\r
+ EraseBlockStart = NULL;\r
+\r
+ Device = Partition->Device;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ EraseBlockStart = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+ if (EraseBlockStart == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ EraseBlockStart->Signature = EMMC_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Partition->Queue, &EraseBlockStart->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;\r
+ EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;\r
+ EraseBlockStart->Packet.Timeout = EMMC_GENERIC_TIMEOUT;\r
+\r
+ EraseBlockStart->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_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, Partition->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_CALLBACK,\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
+ RemoveEntryList (&EraseBlockStart->Link);\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
+ RemoveEntryList (&EraseBlockStart->Link);\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] Partition A pointer to the EMMC_PARTITION 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
+EmmcEraseBlockEnd (\r
+ IN EMMC_PARTITION *Partition,\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
+ EMMC_DEVICE *Device;\r
+ EMMC_REQUEST *EraseBlockEnd;\r
+ EFI_TPL OldTpl;\r
+\r
+ EraseBlockEnd = NULL;\r
+\r
+ Device = Partition->Device;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ EraseBlockEnd = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+ if (EraseBlockEnd == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ EraseBlockEnd->Signature = EMMC_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Partition->Queue, &EraseBlockEnd->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;\r
+ EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;\r
+ EraseBlockEnd->Packet.Timeout = EMMC_GENERIC_TIMEOUT;\r
+\r
+ EraseBlockEnd->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_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, Partition->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_CALLBACK,\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
+ RemoveEntryList (&EraseBlockEnd->Link);\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
+ RemoveEntryList (&EraseBlockEnd->Link);\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] Partition A pointer to the EMMC_PARTITION 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
+EmmcEraseBlock (\r
+ IN EMMC_PARTITION *Partition,\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
+ EMMC_DEVICE *Device;\r
+ EMMC_REQUEST *EraseBlock;\r
+ EFI_TPL OldTpl;\r
+\r
+ EraseBlock = NULL;\r
+\r
+ Device = Partition->Device;\r
+ PassThru = Device->Private->PassThru;\r
+\r
+ EraseBlock = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+ if (EraseBlock == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
+ }\r
+\r
+ EraseBlock->Signature = EMMC_REQUEST_SIGNATURE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ InsertTailList (&Partition->Queue, &EraseBlock->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+ EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;\r
+ EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;\r
+ EraseBlock->Packet.Timeout = EMMC_GENERIC_TIMEOUT;\r
+\r
+ EraseBlock->SdMmcCmdBlk.CommandIndex = EMMC_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_CALLBACK,\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
+ RemoveEntryList (&EraseBlock->Link);\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
+ RemoveEntryList (&EraseBlock->Link);\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
+EmmcEraseBlocks (\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
+ UINT8 PartitionConfig;\r
+ EMMC_PARTITION *Partition;\r
+ EMMC_DEVICE *Device;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Partition = EMMC_PARTITION_DATA_FROM_ERASEBLK (This);\r
+ Device = Partition->Device;\r
+ Media = &Partition->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
+ //\r
+ // Check if needs to switch partition access.\r
+ //\r
+ PartitionConfig = Device->ExtCsd.PartitionConfig;\r
+ if ((PartitionConfig & 0x7) != Partition->PartitionType) {\r
+ PartitionConfig &= (UINT8)~0x7;\r
+ PartitionConfig |= Partition->PartitionType;\r
+ Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ Device->ExtCsd.PartitionConfig = PartitionConfig;\r
+ }\r
+\r
+ Status = EmmcEraseBlockStart (Partition, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcEraseBlockEnd (Partition, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = EmmcEraseBlock (Partition, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_ERROR, "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", Lba, BlockNum, Token->Event, Status));\r
+\r
+ return Status;\r
+}\r
+\r