2 The helper functions for BlockIo and BlockIo2 protocol.
4 Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 Nonblocking I/O callback function when the event is signaled.
14 @param[in] Event The Event this notify function registered to.
15 @param[in] Context Pointer to the context data registered to the
26 EMMC_REQUEST
*Request
;
29 Status
= gBS
->CloseEvent (Event
);
30 if (EFI_ERROR (Status
)) {
34 Request
= (EMMC_REQUEST
*)Context
;
39 "Emmc Async Request: CmdIndex[%d] Arg[%08x] %r\n",
40 Request
->SdMmcCmdBlk
.CommandIndex
,
41 Request
->SdMmcCmdBlk
.CommandArgument
,
42 Request
->Packet
.TransactionStatus
46 if (EFI_ERROR (Request
->Packet
.TransactionStatus
)) {
47 Request
->Token
->TransactionStatus
= Request
->Packet
.TransactionStatus
;
50 RemoveEntryList (&Request
->Link
);
53 gBS
->SignalEvent (Request
->Token
->Event
);
60 Send command SELECT to the device to select/deselect the device.
62 @param[in] Device A pointer to the EMMC_DEVICE instance.
63 @param[in] Rca The relative device address to use.
65 @retval EFI_SUCCESS The request is executed successfully.
66 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
67 @retval Others The request could not be executed successfully.
72 IN EMMC_DEVICE
*Device
,
77 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
78 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk
;
79 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk
;
80 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet
;
82 PassThru
= Device
->Private
->PassThru
;
84 ZeroMem (&SdMmcCmdBlk
, sizeof (SdMmcCmdBlk
));
85 ZeroMem (&SdMmcStatusBlk
, sizeof (SdMmcStatusBlk
));
86 ZeroMem (&Packet
, sizeof (Packet
));
87 Packet
.SdMmcCmdBlk
= &SdMmcCmdBlk
;
88 Packet
.SdMmcStatusBlk
= &SdMmcStatusBlk
;
89 Packet
.Timeout
= EMMC_GENERIC_TIMEOUT
;
91 SdMmcCmdBlk
.CommandIndex
= EMMC_SELECT_DESELECT_CARD
;
92 SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
93 SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
94 SdMmcCmdBlk
.CommandArgument
= (UINT32
)Rca
<< 16;
96 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &Packet
, NULL
);
102 Send command SEND_STATUS to the device to get device status.
104 @param[in] Device A pointer to the EMMC_DEVICE instance.
105 @param[in] Rca The relative device address to use.
106 @param[out] DevStatus The buffer to store the device status.
108 @retval EFI_SUCCESS The request is executed successfully.
109 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
110 @retval Others The request could not be executed successfully.
115 IN EMMC_DEVICE
*Device
,
117 OUT UINT32
*DevStatus
121 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
122 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk
;
123 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk
;
124 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet
;
126 PassThru
= Device
->Private
->PassThru
;
128 ZeroMem (&SdMmcCmdBlk
, sizeof (SdMmcCmdBlk
));
129 ZeroMem (&SdMmcStatusBlk
, sizeof (SdMmcStatusBlk
));
130 ZeroMem (&Packet
, sizeof (Packet
));
131 Packet
.SdMmcCmdBlk
= &SdMmcCmdBlk
;
132 Packet
.SdMmcStatusBlk
= &SdMmcStatusBlk
;
133 Packet
.Timeout
= EMMC_GENERIC_TIMEOUT
;
135 SdMmcCmdBlk
.CommandIndex
= EMMC_SEND_STATUS
;
136 SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
137 SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
138 SdMmcCmdBlk
.CommandArgument
= (UINT32
)Rca
<< 16;
140 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &Packet
, NULL
);
141 if (!EFI_ERROR (Status
)) {
142 CopyMem (DevStatus
, &SdMmcStatusBlk
.Resp0
, sizeof (UINT32
));
149 Send command SEND_CSD to the device to get the CSD register data.
151 @param[in] Device A pointer to the EMMC_DEVICE instance.
152 @param[in] Rca The relative device address to use.
153 @param[out] Csd The buffer to store the EMMC_CSD register data.
155 @retval EFI_SUCCESS The request is executed successfully.
156 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
157 @retval Others The request could not be executed successfully.
162 IN EMMC_DEVICE
*Device
,
168 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
169 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk
;
170 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk
;
171 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet
;
173 PassThru
= Device
->Private
->PassThru
;
175 ZeroMem (&SdMmcCmdBlk
, sizeof (SdMmcCmdBlk
));
176 ZeroMem (&SdMmcStatusBlk
, sizeof (SdMmcStatusBlk
));
177 ZeroMem (&Packet
, sizeof (Packet
));
178 ZeroMem (Csd
, sizeof (EMMC_CSD
));
180 Packet
.SdMmcCmdBlk
= &SdMmcCmdBlk
;
181 Packet
.SdMmcStatusBlk
= &SdMmcStatusBlk
;
182 Packet
.Timeout
= EMMC_GENERIC_TIMEOUT
;
184 SdMmcCmdBlk
.CommandIndex
= EMMC_SEND_CSD
;
185 SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
186 SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR2
;
187 SdMmcCmdBlk
.CommandArgument
= (UINT32
)Rca
<< 16;
189 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &Packet
, NULL
);
190 if (!EFI_ERROR (Status
)) {
192 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
194 CopyMem (((UINT8
*)Csd
) + 1, &SdMmcStatusBlk
.Resp0
, sizeof (EMMC_CSD
) - 1);
201 Send command SEND_CID to the device to get the CID register data.
203 @param[in] Device A pointer to the EMMC_DEVICE instance.
204 @param[in] Rca The relative device address to use.
205 @param[out] Cid The buffer to store the EMMC_CID register data.
207 @retval EFI_SUCCESS The request is executed successfully.
208 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
209 @retval Others The request could not be executed successfully.
214 IN EMMC_DEVICE
*Device
,
220 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
221 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk
;
222 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk
;
223 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet
;
225 PassThru
= Device
->Private
->PassThru
;
227 ZeroMem (&SdMmcCmdBlk
, sizeof (SdMmcCmdBlk
));
228 ZeroMem (&SdMmcStatusBlk
, sizeof (SdMmcStatusBlk
));
229 ZeroMem (&Packet
, sizeof (Packet
));
230 ZeroMem (Cid
, sizeof (EMMC_CID
));
232 Packet
.SdMmcCmdBlk
= &SdMmcCmdBlk
;
233 Packet
.SdMmcStatusBlk
= &SdMmcStatusBlk
;
234 Packet
.Timeout
= EMMC_GENERIC_TIMEOUT
;
236 SdMmcCmdBlk
.CommandIndex
= EMMC_SEND_CID
;
237 SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
238 SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR2
;
239 SdMmcCmdBlk
.CommandArgument
= (UINT32
)Rca
<< 16;
241 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &Packet
, NULL
);
242 if (!EFI_ERROR (Status
)) {
244 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
246 CopyMem (((UINT8
*)Cid
) + 1, &SdMmcStatusBlk
.Resp0
, sizeof (EMMC_CID
) - 1);
253 Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.
255 @param[in] Device A pointer to the EMMC_DEVICE instance.
256 @param[out] ExtCsd The buffer to store the EXT_CSD register data.
258 @retval EFI_SUCCESS The request is executed successfully.
259 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
260 @retval Others The request could not be executed successfully.
265 IN EMMC_DEVICE
*Device
,
266 OUT EMMC_EXT_CSD
*ExtCsd
270 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
271 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk
;
272 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk
;
273 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet
;
275 PassThru
= Device
->Private
->PassThru
;
277 ZeroMem (&SdMmcCmdBlk
, sizeof (SdMmcCmdBlk
));
278 ZeroMem (&SdMmcStatusBlk
, sizeof (SdMmcStatusBlk
));
279 ZeroMem (&Packet
, sizeof (Packet
));
280 ZeroMem (ExtCsd
, sizeof (EMMC_EXT_CSD
));
281 Packet
.SdMmcCmdBlk
= &SdMmcCmdBlk
;
282 Packet
.SdMmcStatusBlk
= &SdMmcStatusBlk
;
283 Packet
.Timeout
= EMMC_GENERIC_TIMEOUT
;
285 SdMmcCmdBlk
.CommandIndex
= EMMC_SEND_EXT_CSD
;
286 SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAdtc
;
287 SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
288 SdMmcCmdBlk
.CommandArgument
= 0x00000000;
289 Packet
.InDataBuffer
= ExtCsd
;
290 Packet
.InTransferLength
= sizeof (EMMC_EXT_CSD
);
292 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &Packet
, NULL
);
298 Set the specified EXT_CSD register field through sync or async I/O request.
300 @param[in] Partition A pointer to the EMMC_PARTITION instance.
301 @param[in] Offset The offset of the specified field in EXT_CSD register.
302 @param[in] Value The byte value written to the field specified by Offset.
303 @param[in] Token A pointer to the token associated with the transaction.
304 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
305 This parameter is only meaningful in async I/O request.
307 @retval EFI_SUCCESS The request is executed successfully.
308 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
309 @retval Others The request could not be executed successfully.
314 IN EMMC_PARTITION
*Partition
,
317 IN EFI_BLOCK_IO2_TOKEN
*Token
,
323 EMMC_REQUEST
*SetExtCsdReq
;
324 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
325 UINT32 CommandArgument
;
330 Device
= Partition
->Device
;
331 PassThru
= Device
->Private
->PassThru
;
333 SetExtCsdReq
= AllocateZeroPool (sizeof (EMMC_REQUEST
));
334 if (SetExtCsdReq
== NULL
) {
335 Status
= EFI_OUT_OF_RESOURCES
;
339 SetExtCsdReq
->Signature
= EMMC_REQUEST_SIGNATURE
;
340 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
341 InsertTailList (&Partition
->Queue
, &SetExtCsdReq
->Link
);
342 gBS
->RestoreTPL (OldTpl
);
343 SetExtCsdReq
->Packet
.SdMmcCmdBlk
= &SetExtCsdReq
->SdMmcCmdBlk
;
344 SetExtCsdReq
->Packet
.SdMmcStatusBlk
= &SetExtCsdReq
->SdMmcStatusBlk
;
345 SetExtCsdReq
->Packet
.Timeout
= EMMC_GENERIC_TIMEOUT
;
347 SetExtCsdReq
->SdMmcCmdBlk
.CommandIndex
= EMMC_SWITCH
;
348 SetExtCsdReq
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
349 SetExtCsdReq
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1b
;
351 // Write the Value to the field specified by Offset.
353 CommandArgument
= (Value
<< 8) | (Offset
<< 16) | BIT24
| BIT25
;
354 SetExtCsdReq
->SdMmcCmdBlk
.CommandArgument
= CommandArgument
;
356 SetExtCsdReq
->IsEnd
= IsEnd
;
357 SetExtCsdReq
->Token
= Token
;
359 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
360 Status
= gBS
->CreateEvent (
367 if (EFI_ERROR (Status
)) {
371 SetExtCsdReq
->Event
= NULL
;
374 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &SetExtCsdReq
->Packet
, SetExtCsdReq
->Event
);
377 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
379 // For asynchronous operation, only free request and event in error case.
380 // The request and event will be freed in asynchronous callback for success case.
382 if (EFI_ERROR (Status
) && (SetExtCsdReq
!= NULL
)) {
383 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
384 RemoveEntryList (&SetExtCsdReq
->Link
);
385 gBS
->RestoreTPL (OldTpl
);
386 if (SetExtCsdReq
->Event
!= NULL
) {
387 gBS
->CloseEvent (SetExtCsdReq
->Event
);
390 FreePool (SetExtCsdReq
);
394 // For synchronous operation, free request whatever the execution result is.
396 if (SetExtCsdReq
!= NULL
) {
397 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
398 RemoveEntryList (&SetExtCsdReq
->Link
);
399 gBS
->RestoreTPL (OldTpl
);
400 FreePool (SetExtCsdReq
);
408 Set the number of blocks for a block read/write cmd through sync or async I/O request.
410 @param[in] Partition A pointer to the EMMC_PARTITION instance.
411 @param[in] BlockNum The number of blocks for transfer.
412 @param[in] Token A pointer to the token associated with the transaction.
413 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
414 This parameter is only meaningful in async I/O request.
416 @retval EFI_SUCCESS The request is executed successfully.
417 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
418 @retval Others The request could not be executed successfully.
423 IN EMMC_PARTITION
*Partition
,
425 IN EFI_BLOCK_IO2_TOKEN
*Token
,
431 EMMC_REQUEST
*SetBlkCntReq
;
432 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
437 Device
= Partition
->Device
;
438 PassThru
= Device
->Private
->PassThru
;
440 SetBlkCntReq
= AllocateZeroPool (sizeof (EMMC_REQUEST
));
441 if (SetBlkCntReq
== NULL
) {
442 Status
= EFI_OUT_OF_RESOURCES
;
446 SetBlkCntReq
->Signature
= EMMC_REQUEST_SIGNATURE
;
447 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
448 InsertTailList (&Partition
->Queue
, &SetBlkCntReq
->Link
);
449 gBS
->RestoreTPL (OldTpl
);
450 SetBlkCntReq
->Packet
.SdMmcCmdBlk
= &SetBlkCntReq
->SdMmcCmdBlk
;
451 SetBlkCntReq
->Packet
.SdMmcStatusBlk
= &SetBlkCntReq
->SdMmcStatusBlk
;
452 SetBlkCntReq
->Packet
.Timeout
= EMMC_GENERIC_TIMEOUT
;
454 SetBlkCntReq
->SdMmcCmdBlk
.CommandIndex
= EMMC_SET_BLOCK_COUNT
;
455 SetBlkCntReq
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
456 SetBlkCntReq
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
457 SetBlkCntReq
->SdMmcCmdBlk
.CommandArgument
= BlockNum
;
459 SetBlkCntReq
->IsEnd
= IsEnd
;
460 SetBlkCntReq
->Token
= Token
;
462 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
463 Status
= gBS
->CreateEvent (
470 if (EFI_ERROR (Status
)) {
474 SetBlkCntReq
->Event
= NULL
;
477 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &SetBlkCntReq
->Packet
, SetBlkCntReq
->Event
);
480 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
482 // For asynchronous operation, only free request and event in error case.
483 // The request and event will be freed in asynchronous callback for success case.
485 if (EFI_ERROR (Status
) && (SetBlkCntReq
!= NULL
)) {
486 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
487 RemoveEntryList (&SetBlkCntReq
->Link
);
488 gBS
->RestoreTPL (OldTpl
);
489 if (SetBlkCntReq
->Event
!= NULL
) {
490 gBS
->CloseEvent (SetBlkCntReq
->Event
);
493 FreePool (SetBlkCntReq
);
497 // For synchronous operation, free request whatever the execution result is.
499 if (SetBlkCntReq
!= NULL
) {
500 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
501 RemoveEntryList (&SetBlkCntReq
->Link
);
502 gBS
->RestoreTPL (OldTpl
);
503 FreePool (SetBlkCntReq
);
511 Read blocks through security protocol cmds with the way of sync or async I/O request.
513 @param[in] Partition A pointer to the EMMC_PARTITION instance.
514 @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
515 the security protocol command to be sent.
516 @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
517 of the security protocol command to be sent.
518 @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
519 @param[out] PayloadBuffer A pointer to a destination buffer to store the security
520 protocol command specific payload data for the security
521 protocol command. The caller is responsible for having
522 either implicit or explicit ownership of the buffer.
523 @param[in] IsRead Indicates it is a read or write operation.
524 @param[in] Timeout The timeout value, in 100ns units.
525 @param[in] Token A pointer to the token associated with the transaction.
526 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
527 This parameter is only meaningful in async I/O request.
529 @retval EFI_SUCCESS The request is executed successfully.
530 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
531 @retval Others The request could not be executed successfully.
536 IN EMMC_PARTITION
*Partition
,
537 IN UINT8 SecurityProtocol
,
538 IN UINT16 SecurityProtocolSpecificData
,
539 IN UINTN PayloadBufferSize
,
540 OUT VOID
*PayloadBuffer
,
543 IN EFI_BLOCK_IO2_TOKEN
*Token
,
549 EMMC_REQUEST
*ProtocolReq
;
550 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
555 Device
= Partition
->Device
;
556 PassThru
= Device
->Private
->PassThru
;
558 ProtocolReq
= AllocateZeroPool (sizeof (EMMC_REQUEST
));
559 if (ProtocolReq
== NULL
) {
560 Status
= EFI_OUT_OF_RESOURCES
;
564 ProtocolReq
->Signature
= EMMC_REQUEST_SIGNATURE
;
565 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
566 InsertTailList (&Partition
->Queue
, &ProtocolReq
->Link
);
567 gBS
->RestoreTPL (OldTpl
);
568 ProtocolReq
->Packet
.SdMmcCmdBlk
= &ProtocolReq
->SdMmcCmdBlk
;
569 ProtocolReq
->Packet
.SdMmcStatusBlk
= &ProtocolReq
->SdMmcStatusBlk
;
572 ProtocolReq
->Packet
.InDataBuffer
= PayloadBuffer
;
573 ProtocolReq
->Packet
.InTransferLength
= (UINT32
)PayloadBufferSize
;
575 ProtocolReq
->SdMmcCmdBlk
.CommandIndex
= EMMC_PROTOCOL_RD
;
576 ProtocolReq
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAdtc
;
577 ProtocolReq
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
579 ProtocolReq
->Packet
.OutDataBuffer
= PayloadBuffer
;
580 ProtocolReq
->Packet
.OutTransferLength
= (UINT32
)PayloadBufferSize
;
582 ProtocolReq
->SdMmcCmdBlk
.CommandIndex
= EMMC_PROTOCOL_WR
;
583 ProtocolReq
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAdtc
;
584 ProtocolReq
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
587 ProtocolReq
->SdMmcCmdBlk
.CommandArgument
= (SecurityProtocol
<< 8) | (SecurityProtocolSpecificData
<< 16);
589 // Convert to 1 microsecond unit.
591 ProtocolReq
->Packet
.Timeout
= DivU64x32 (Timeout
, 10) + 1;
593 ProtocolReq
->IsEnd
= IsEnd
;
594 ProtocolReq
->Token
= Token
;
596 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
597 Status
= gBS
->CreateEvent (
604 if (EFI_ERROR (Status
)) {
608 ProtocolReq
->Event
= NULL
;
611 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &ProtocolReq
->Packet
, ProtocolReq
->Event
);
614 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
616 // For asynchronous operation, only free request and event in error case.
617 // The request and event will be freed in asynchronous callback for success case.
619 if (EFI_ERROR (Status
) && (ProtocolReq
!= NULL
)) {
620 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
621 RemoveEntryList (&ProtocolReq
->Link
);
622 gBS
->RestoreTPL (OldTpl
);
623 if (ProtocolReq
->Event
!= NULL
) {
624 gBS
->CloseEvent (ProtocolReq
->Event
);
627 FreePool (ProtocolReq
);
631 // For synchronous operation, free request whatever the execution result is.
633 if (ProtocolReq
!= NULL
) {
634 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
635 RemoveEntryList (&ProtocolReq
->Link
);
636 gBS
->RestoreTPL (OldTpl
);
637 FreePool (ProtocolReq
);
645 Read/write multiple blocks through sync or async I/O request.
647 @param[in] Partition A pointer to the EMMC_PARTITION instance.
648 @param[in] Lba The starting logical block address to be read/written.
649 The caller is responsible for reading/writing to only
650 legitimate locations.
651 @param[in] Buffer A pointer to the destination/source buffer for the data.
652 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
653 @param[in] IsRead Indicates it is a read or write operation.
654 @param[in] Token A pointer to the token associated with the transaction.
655 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
656 This parameter is only meaningful in async I/O request.
658 @retval EFI_SUCCESS The request is executed successfully.
659 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
660 @retval Others The request could not be executed successfully.
665 IN EMMC_PARTITION
*Partition
,
670 IN EFI_BLOCK_IO2_TOKEN
*Token
,
676 EMMC_REQUEST
*RwMultiBlkReq
;
677 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
680 RwMultiBlkReq
= NULL
;
682 Device
= Partition
->Device
;
683 PassThru
= Device
->Private
->PassThru
;
685 RwMultiBlkReq
= AllocateZeroPool (sizeof (EMMC_REQUEST
));
686 if (RwMultiBlkReq
== NULL
) {
687 Status
= EFI_OUT_OF_RESOURCES
;
691 RwMultiBlkReq
->Signature
= EMMC_REQUEST_SIGNATURE
;
692 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
693 InsertTailList (&Partition
->Queue
, &RwMultiBlkReq
->Link
);
694 gBS
->RestoreTPL (OldTpl
);
695 RwMultiBlkReq
->Packet
.SdMmcCmdBlk
= &RwMultiBlkReq
->SdMmcCmdBlk
;
696 RwMultiBlkReq
->Packet
.SdMmcStatusBlk
= &RwMultiBlkReq
->SdMmcStatusBlk
;
698 // Calculate timeout value through the below formula.
699 // Timeout = (transfer size) / (2MB/s).
700 // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest
701 // transfer speed (2.4MB/s).
702 // Refer to eMMC 5.0 spec section 6.9.1 for details.
704 RwMultiBlkReq
->Packet
.Timeout
= (BufferSize
/ (2 * 1024 * 1024) + 1) * 1000 * 1000;
707 RwMultiBlkReq
->Packet
.InDataBuffer
= Buffer
;
708 RwMultiBlkReq
->Packet
.InTransferLength
= (UINT32
)BufferSize
;
710 RwMultiBlkReq
->SdMmcCmdBlk
.CommandIndex
= EMMC_READ_MULTIPLE_BLOCK
;
711 RwMultiBlkReq
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAdtc
;
712 RwMultiBlkReq
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
714 RwMultiBlkReq
->Packet
.OutDataBuffer
= Buffer
;
715 RwMultiBlkReq
->Packet
.OutTransferLength
= (UINT32
)BufferSize
;
717 RwMultiBlkReq
->SdMmcCmdBlk
.CommandIndex
= EMMC_WRITE_MULTIPLE_BLOCK
;
718 RwMultiBlkReq
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAdtc
;
719 RwMultiBlkReq
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
722 if (Partition
->Device
->SectorAddressing
) {
723 RwMultiBlkReq
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)Lba
;
725 RwMultiBlkReq
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)MultU64x32 (Lba
, Partition
->BlockMedia
.BlockSize
);
728 RwMultiBlkReq
->IsEnd
= IsEnd
;
729 RwMultiBlkReq
->Token
= Token
;
731 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
732 Status
= gBS
->CreateEvent (
737 &RwMultiBlkReq
->Event
739 if (EFI_ERROR (Status
)) {
743 RwMultiBlkReq
->Event
= NULL
;
746 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &RwMultiBlkReq
->Packet
, RwMultiBlkReq
->Event
);
749 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
751 // For asynchronous operation, only free request and event in error case.
752 // The request and event will be freed in asynchronous callback for success case.
754 if (EFI_ERROR (Status
) && (RwMultiBlkReq
!= NULL
)) {
755 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
756 RemoveEntryList (&RwMultiBlkReq
->Link
);
757 gBS
->RestoreTPL (OldTpl
);
758 if (RwMultiBlkReq
->Event
!= NULL
) {
759 gBS
->CloseEvent (RwMultiBlkReq
->Event
);
762 FreePool (RwMultiBlkReq
);
766 // For synchronous operation, free request whatever the execution result is.
768 if (RwMultiBlkReq
!= NULL
) {
769 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
770 RemoveEntryList (&RwMultiBlkReq
->Link
);
771 gBS
->RestoreTPL (OldTpl
);
772 FreePool (RwMultiBlkReq
);
780 This function transfers data from/to EMMC device.
782 @param[in] Partition A pointer to the EMMC_PARTITION instance.
783 @param[in] MediaId The media ID that the read/write request is for.
784 @param[in] Lba The starting logical block address to be read/written.
785 The caller is responsible for reading/writing to only
786 legitimate locations.
787 @param[in, out] Buffer A pointer to the destination/source buffer for the data.
788 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
789 @param[in] IsRead Indicates it is a read or write operation.
790 @param[in, out] Token A pointer to the token associated with the transaction.
792 @retval EFI_SUCCESS The data was read/written correctly to the device.
793 @retval EFI_WRITE_PROTECTED The device can not be read/written to.
794 @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
795 @retval EFI_NO_MEDIA There is no media in the device.
796 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
797 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
798 @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,
799 or the buffer is not on proper alignment.
804 IN EMMC_PARTITION
*Partition
,
810 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
815 EFI_BLOCK_IO_MEDIA
*Media
;
819 UINT8 PartitionConfig
;
824 Status
= EFI_SUCCESS
;
825 Device
= Partition
->Device
;
826 Media
= &Partition
->BlockMedia
;
829 if (MediaId
!= Media
->MediaId
) {
830 return EFI_MEDIA_CHANGED
;
833 if (!IsRead
&& Media
->ReadOnly
) {
834 return EFI_WRITE_PROTECTED
;
840 if (Buffer
== NULL
) {
841 return EFI_INVALID_PARAMETER
;
844 if (BufferSize
== 0) {
845 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
846 Token
->TransactionStatus
= EFI_SUCCESS
;
847 gBS
->SignalEvent (Token
->Event
);
853 BlockSize
= Media
->BlockSize
;
854 if ((BufferSize
% BlockSize
) != 0) {
855 return EFI_BAD_BUFFER_SIZE
;
858 BlockNum
= BufferSize
/ BlockSize
;
859 if ((Lba
+ BlockNum
- 1) > Media
->LastBlock
) {
860 return EFI_INVALID_PARAMETER
;
863 IoAlign
= Media
->IoAlign
;
864 if ((IoAlign
> 0) && (((UINTN
)Buffer
& (IoAlign
- 1)) != 0)) {
865 return EFI_INVALID_PARAMETER
;
868 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
869 Token
->TransactionStatus
= EFI_SUCCESS
;
873 // Check if needs to switch partition access.
875 PartitionConfig
= Device
->ExtCsd
.PartitionConfig
;
876 if ((PartitionConfig
& 0x7) != Partition
->PartitionType
) {
877 PartitionConfig
&= (UINT8
) ~0x7;
878 PartitionConfig
|= Partition
->PartitionType
;
879 Status
= EmmcSetExtCsd (Partition
, OFFSET_OF (EMMC_EXT_CSD
, PartitionConfig
), PartitionConfig
, Token
, FALSE
);
880 if (EFI_ERROR (Status
)) {
884 Device
->ExtCsd
.PartitionConfig
= PartitionConfig
;
888 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
890 Remaining
= BlockNum
;
893 while (Remaining
> 0) {
894 if (Remaining
<= MaxBlock
) {
895 BlockNum
= Remaining
;
901 Status
= EmmcSetBlkCount (Partition
, (UINT16
)BlockNum
, Token
, FALSE
);
902 if (EFI_ERROR (Status
)) {
906 BufferSize
= BlockNum
* BlockSize
;
907 Status
= EmmcRwMultiBlocks (Partition
, Lba
, Buffer
, BufferSize
, IsRead
, Token
, LastRw
);
908 if (EFI_ERROR (Status
)) {
914 "Emmc%a(): Part %d Lba 0x%x BlkNo 0x%x Event %p with %r\n",
915 IsRead
? "Read " : "Write",
916 Partition
->PartitionType
,
919 (Token
!= NULL
) ? Token
->Event
: NULL
,
924 Buffer
= (UINT8
*)Buffer
+ BufferSize
;
925 Remaining
-= BlockNum
;
932 Reset the Block Device.
934 @param This Indicates a pointer to the calling context.
935 @param ExtendedVerification Driver may perform diagnostics on reset.
937 @retval EFI_SUCCESS The device was reset.
938 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
945 IN EFI_BLOCK_IO_PROTOCOL
*This
,
946 IN BOOLEAN ExtendedVerification
950 EMMC_PARTITION
*Partition
;
951 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
953 Partition
= EMMC_PARTITION_DATA_FROM_BLKIO (This
);
955 PassThru
= Partition
->Device
->Private
->PassThru
;
956 Status
= PassThru
->ResetDevice (PassThru
, Partition
->Device
->Slot
);
957 if (EFI_ERROR (Status
)) {
958 Status
= EFI_DEVICE_ERROR
;
965 Read BufferSize bytes from Lba into Buffer.
967 @param This Indicates a pointer to the calling context.
968 @param MediaId Id of the media, changes every time the media is replaced.
969 @param Lba The starting Logical Block Address to read from
970 @param BufferSize Size of Buffer, must be a multiple of device block size.
971 @param Buffer A pointer to the destination buffer for the data. The caller is
972 responsible for either having implicit or explicit ownership of the buffer.
974 @retval EFI_SUCCESS The data was read correctly from the device.
975 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
976 @retval EFI_NO_MEDIA There is no media in the device.
977 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
978 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
979 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
980 or the buffer is not on proper alignment.
986 IN EFI_BLOCK_IO_PROTOCOL
*This
,
994 EMMC_PARTITION
*Partition
;
996 Partition
= EMMC_PARTITION_DATA_FROM_BLKIO (This
);
998 Status
= EmmcReadWrite (Partition
, MediaId
, Lba
, Buffer
, BufferSize
, TRUE
, NULL
);
1003 Write BufferSize bytes from Lba into Buffer.
1005 @param This Indicates a pointer to the calling context.
1006 @param MediaId The media ID that the write request is for.
1007 @param Lba The starting logical block address to be written. The caller is
1008 responsible for writing to only legitimate locations.
1009 @param BufferSize Size of Buffer, must be a multiple of device block size.
1010 @param Buffer A pointer to the source buffer for the data.
1012 @retval EFI_SUCCESS The data was written correctly to the device.
1013 @retval EFI_WRITE_PROTECTED The device can not be written to.
1014 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1015 @retval EFI_NO_MEDIA There is no media in the device.
1016 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
1017 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1018 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1019 or the buffer is not on proper alignment.
1025 IN EFI_BLOCK_IO_PROTOCOL
*This
,
1028 IN UINTN BufferSize
,
1033 EMMC_PARTITION
*Partition
;
1035 Partition
= EMMC_PARTITION_DATA_FROM_BLKIO (This
);
1037 Status
= EmmcReadWrite (Partition
, MediaId
, Lba
, Buffer
, BufferSize
, FALSE
, NULL
);
1042 Flush the Block Device.
1044 @param This Indicates a pointer to the calling context.
1046 @retval EFI_SUCCESS All outstanding data was written to the device
1047 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
1048 @retval EFI_NO_MEDIA There is no media in the device.
1054 IN EFI_BLOCK_IO_PROTOCOL
*This
1064 Reset the Block Device.
1066 @param[in] This Indicates a pointer to the calling context.
1067 @param[in] ExtendedVerification Driver may perform diagnostics on reset.
1069 @retval EFI_SUCCESS The device was reset.
1070 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
1077 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1078 IN BOOLEAN ExtendedVerification
1081 EMMC_PARTITION
*Partition
;
1083 LIST_ENTRY
*NextLink
;
1084 EMMC_REQUEST
*Request
;
1087 Partition
= EMMC_PARTITION_DATA_FROM_BLKIO2 (This
);
1089 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1090 for (Link
= GetFirstNode (&Partition
->Queue
);
1091 !IsNull (&Partition
->Queue
, Link
);
1094 NextLink
= GetNextNode (&Partition
->Queue
, Link
);
1095 RemoveEntryList (Link
);
1097 Request
= EMMC_REQUEST_FROM_LINK (Link
);
1099 gBS
->CloseEvent (Request
->Event
);
1100 Request
->Token
->TransactionStatus
= EFI_ABORTED
;
1102 if (Request
->IsEnd
) {
1103 gBS
->SignalEvent (Request
->Token
->Event
);
1109 gBS
->RestoreTPL (OldTpl
);
1115 Read BufferSize bytes from Lba into Buffer.
1117 @param[in] This Indicates a pointer to the calling context.
1118 @param[in] MediaId Id of the media, changes every time the media is replaced.
1119 @param[in] Lba The starting Logical Block Address to read from.
1120 @param[in, out] Token A pointer to the token associated with the transaction.
1121 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
1122 @param[out] Buffer A pointer to the destination buffer for the data. The caller is
1123 responsible for either having implicit or explicit ownership of the buffer.
1125 @retval EFI_SUCCESS The read request was queued if Event is not NULL.
1126 The data was read correctly from the device if
1128 @retval EFI_DEVICE_ERROR The device reported an error while performing
1130 @retval EFI_NO_MEDIA There is no media in the device.
1131 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1132 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
1133 intrinsic block size of the device.
1134 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
1135 or the buffer is not on proper alignment.
1136 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
1143 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1146 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1147 IN UINTN BufferSize
,
1152 EMMC_PARTITION
*Partition
;
1154 Partition
= EMMC_PARTITION_DATA_FROM_BLKIO2 (This
);
1156 Status
= EmmcReadWrite (Partition
, MediaId
, Lba
, Buffer
, BufferSize
, TRUE
, Token
);
1161 Write BufferSize bytes from Lba into Buffer.
1163 @param[in] This Indicates a pointer to the calling context.
1164 @param[in] MediaId The media ID that the write request is for.
1165 @param[in] Lba The starting logical block address to be written. The
1166 caller is responsible for writing to only legitimate
1168 @param[in, out] Token A pointer to the token associated with the transaction.
1169 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
1170 @param[in] Buffer A pointer to the source buffer for the data.
1172 @retval EFI_SUCCESS The data was written correctly to the device.
1173 @retval EFI_WRITE_PROTECTED The device can not be written to.
1174 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1175 @retval EFI_NO_MEDIA There is no media in the device.
1176 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
1177 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1178 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1179 or the buffer is not on proper alignment.
1185 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1188 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
1189 IN UINTN BufferSize
,
1194 EMMC_PARTITION
*Partition
;
1196 Partition
= EMMC_PARTITION_DATA_FROM_BLKIO2 (This
);
1198 Status
= EmmcReadWrite (Partition
, MediaId
, Lba
, Buffer
, BufferSize
, FALSE
, Token
);
1203 Flush the Block Device.
1205 @param[in] This Indicates a pointer to the calling context.
1206 @param[in, out] Token A pointer to the token associated with the transaction.
1208 @retval EFI_SUCCESS All outstanding data was written to the device
1209 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
1210 @retval EFI_NO_MEDIA There is no media in the device.
1216 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
1217 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
1221 // Signal event and return directly.
1223 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1224 Token
->TransactionStatus
= EFI_SUCCESS
;
1225 gBS
->SignalEvent (Token
->Event
);
1232 Send a security protocol command to a device that receives data and/or the result
1233 of one or more commands sent by SendData.
1235 The ReceiveData function sends a security protocol command to the given MediaId.
1236 The security protocol command sent is defined by SecurityProtocolId and contains
1237 the security protocol specific data SecurityProtocolSpecificData. The function
1238 returns the data from the security protocol command in PayloadBuffer.
1240 For devices supporting the SCSI command set, the security protocol command is sent
1241 using the SECURITY PROTOCOL IN command defined in SPC-4.
1243 For devices supporting the ATA command set, the security protocol command is sent
1244 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
1247 If the PayloadBufferSize is zero, the security protocol command is sent using the
1248 Trusted Non-Data command defined in ATA8-ACS.
1250 If PayloadBufferSize is too small to store the available data from the security
1251 protocol command, the function shall copy PayloadBufferSize bytes into the
1252 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1254 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1255 the function shall return EFI_INVALID_PARAMETER.
1257 If the given MediaId does not support security protocol commands, the function shall
1258 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1259 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1260 the function returns EFI_MEDIA_CHANGED.
1262 If the security protocol fails to complete within the Timeout period, the function
1263 shall return EFI_TIMEOUT.
1265 If the security protocol command completes without an error, the function shall
1266 return EFI_SUCCESS. If the security protocol command completes with an error, the
1267 function shall return EFI_DEVICE_ERROR.
1269 @param[in] This Indicates a pointer to the calling context.
1270 @param[in] MediaId ID of the medium to receive data from.
1271 @param[in] Timeout The timeout, in 100ns units, to use for the execution
1272 of the security protocol command. A Timeout value of 0
1273 means that this function will wait indefinitely for the
1274 security protocol command to execute. If Timeout is greater
1275 than zero, then this function will return EFI_TIMEOUT
1276 if the time required to execute the receive data command
1277 is greater than Timeout.
1278 @param[in] SecurityProtocolId The value of the "Security Protocol" parameter of
1279 the security protocol command to be sent.
1280 @param[in] SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1281 of the security protocol command to be sent.
1282 @param[in] PayloadBufferSize Size in bytes of the payload data buffer.
1283 @param[out] PayloadBuffer A pointer to a destination buffer to store the security
1284 protocol command specific payload data for the security
1285 protocol command. The caller is responsible for having
1286 either implicit or explicit ownership of the buffer.
1287 @param[out] PayloadTransferSize A pointer to a buffer to store the size in bytes of the
1288 data written to the payload data buffer.
1289 @param[in] IsRead Indicates it is a read or write operation.
1291 @retval EFI_SUCCESS The security protocol command completed successfully.
1292 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
1293 data from the device. The PayloadBuffer contains the truncated data.
1294 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1295 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1296 @retval EFI_NO_MEDIA There is no media in the device.
1297 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1298 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
1299 PayloadBufferSize is non-zero.
1300 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1301 protocol command to execute.
1306 EmmcSecurityProtocolInOut (
1307 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
1310 IN UINT8 SecurityProtocolId
,
1311 IN UINT16 SecurityProtocolSpecificData
,
1312 IN UINTN PayloadBufferSize
,
1313 OUT VOID
*PayloadBuffer
,
1314 OUT UINTN
*PayloadTransferSize
,
1319 EMMC_PARTITION
*Partition
;
1320 EMMC_DEVICE
*Device
;
1321 EFI_BLOCK_IO_MEDIA
*Media
;
1327 UINT8 PartitionConfig
;
1329 Status
= EFI_SUCCESS
;
1330 Partition
= EMMC_PARTITION_DATA_FROM_SSP (This
);
1331 Device
= Partition
->Device
;
1332 Media
= &Partition
->BlockMedia
;
1334 if (PayloadTransferSize
!= NULL
) {
1335 *PayloadTransferSize
= 0;
1338 if ((PayloadBuffer
== NULL
) && (PayloadBufferSize
!= 0)) {
1339 return EFI_INVALID_PARAMETER
;
1342 if (MediaId
!= Media
->MediaId
) {
1343 return EFI_MEDIA_CHANGED
;
1346 if (PayloadBufferSize
== 0) {
1350 BlockSize
= Media
->BlockSize
;
1351 if ((PayloadBufferSize
% BlockSize
) != 0) {
1352 return EFI_BAD_BUFFER_SIZE
;
1355 BlockNum
= PayloadBufferSize
/ BlockSize
;
1357 IoAlign
= Media
->IoAlign
;
1358 if ((IoAlign
> 0) && (((UINTN
)PayloadBuffer
& (IoAlign
- 1)) != 0)) {
1359 return EFI_INVALID_PARAMETER
;
1363 // Security protocol interface is synchronous transfer.
1364 // Waiting for async I/O list to be empty before any operation.
1366 while (!IsListEmpty (&Partition
->Queue
)) {
1370 // Check if needs to switch partition access.
1372 PartitionConfig
= Device
->ExtCsd
.PartitionConfig
;
1373 if ((PartitionConfig
& 0x7) != Partition
->PartitionType
) {
1374 PartitionConfig
&= (UINT8
) ~0x7;
1375 PartitionConfig
|= Partition
->PartitionType
;
1376 Status
= EmmcSetExtCsd (Partition
, OFFSET_OF (EMMC_EXT_CSD
, PartitionConfig
), PartitionConfig
, NULL
, FALSE
);
1377 if (EFI_ERROR (Status
)) {
1381 Device
->ExtCsd
.PartitionConfig
= PartitionConfig
;
1385 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
1387 Remaining
= BlockNum
;
1390 while (Remaining
> 0) {
1391 if (Remaining
<= MaxBlock
) {
1392 BlockNum
= Remaining
;
1394 BlockNum
= MaxBlock
;
1397 Status
= EmmcSetBlkCount (Partition
, (UINT16
)BlockNum
, NULL
, FALSE
);
1398 if (EFI_ERROR (Status
)) {
1402 PayloadBufferSize
= BlockNum
* BlockSize
;
1403 Status
= EmmcProtocolInOut (Partition
, SecurityProtocolId
, SecurityProtocolSpecificData
, PayloadBufferSize
, PayloadBuffer
, IsRead
, Timeout
, NULL
, FALSE
);
1404 if (EFI_ERROR (Status
)) {
1408 PayloadBuffer
= (UINT8
*)PayloadBuffer
+ PayloadBufferSize
;
1409 Remaining
-= BlockNum
;
1410 if (PayloadTransferSize
!= NULL
) {
1411 *PayloadTransferSize
+= PayloadBufferSize
;
1419 Send a security protocol command to a device that receives data and/or the result
1420 of one or more commands sent by SendData.
1422 The ReceiveData function sends a security protocol command to the given MediaId.
1423 The security protocol command sent is defined by SecurityProtocolId and contains
1424 the security protocol specific data SecurityProtocolSpecificData. The function
1425 returns the data from the security protocol command in PayloadBuffer.
1427 For devices supporting the SCSI command set, the security protocol command is sent
1428 using the SECURITY PROTOCOL IN command defined in SPC-4.
1430 For devices supporting the ATA command set, the security protocol command is sent
1431 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
1434 If the PayloadBufferSize is zero, the security protocol command is sent using the
1435 Trusted Non-Data command defined in ATA8-ACS.
1437 If PayloadBufferSize is too small to store the available data from the security
1438 protocol command, the function shall copy PayloadBufferSize bytes into the
1439 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1441 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1442 the function shall return EFI_INVALID_PARAMETER.
1444 If the given MediaId does not support security protocol commands, the function shall
1445 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1446 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1447 the function returns EFI_MEDIA_CHANGED.
1449 If the security protocol fails to complete within the Timeout period, the function
1450 shall return EFI_TIMEOUT.
1452 If the security protocol command completes without an error, the function shall
1453 return EFI_SUCCESS. If the security protocol command completes with an error, the
1454 function shall return EFI_DEVICE_ERROR.
1456 @param This Indicates a pointer to the calling context.
1457 @param MediaId ID of the medium to receive data from.
1458 @param Timeout The timeout, in 100ns units, to use for the execution
1459 of the security protocol command. A Timeout value of 0
1460 means that this function will wait indefinitely for the
1461 security protocol command to execute. If Timeout is greater
1462 than zero, then this function will return EFI_TIMEOUT
1463 if the time required to execute the receive data command
1464 is greater than Timeout.
1465 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1466 the security protocol command to be sent.
1467 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1468 of the security protocol command to be sent.
1469 @param PayloadBufferSize Size in bytes of the payload data buffer.
1470 @param PayloadBuffer A pointer to a destination buffer to store the security
1471 protocol command specific payload data for the security
1472 protocol command. The caller is responsible for having
1473 either implicit or explicit ownership of the buffer.
1474 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
1475 data written to the payload data buffer.
1477 @retval EFI_SUCCESS The security protocol command completed successfully.
1478 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
1479 data from the device. The PayloadBuffer contains the truncated data.
1480 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1481 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1482 @retval EFI_NO_MEDIA There is no media in the device.
1483 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1484 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
1485 PayloadBufferSize is non-zero.
1486 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1487 protocol command to execute.
1492 EmmcSecurityProtocolIn (
1493 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
1496 IN UINT8 SecurityProtocolId
,
1497 IN UINT16 SecurityProtocolSpecificData
,
1498 IN UINTN PayloadBufferSize
,
1499 OUT VOID
*PayloadBuffer
,
1500 OUT UINTN
*PayloadTransferSize
1505 if ((PayloadTransferSize
== NULL
) && (PayloadBufferSize
!= 0)) {
1506 return EFI_INVALID_PARAMETER
;
1509 Status
= EmmcSecurityProtocolInOut (
1514 SecurityProtocolSpecificData
,
1517 PayloadTransferSize
,
1525 Send a security protocol command to a device.
1527 The SendData function sends a security protocol command containing the payload
1528 PayloadBuffer to the given MediaId. The security protocol command sent is
1529 defined by SecurityProtocolId and contains the security protocol specific data
1530 SecurityProtocolSpecificData. If the underlying protocol command requires a
1531 specific padding for the command payload, the SendData function shall add padding
1532 bytes to the command payload to satisfy the padding requirements.
1534 For devices supporting the SCSI command set, the security protocol command is sent
1535 using the SECURITY PROTOCOL OUT command defined in SPC-4.
1537 For devices supporting the ATA command set, the security protocol command is sent
1538 using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
1539 is non-zero. If the PayloadBufferSize is zero, the security protocol command is
1540 sent using the Trusted Non-Data command defined in ATA8-ACS.
1542 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
1543 return EFI_INVALID_PARAMETER.
1545 If the given MediaId does not support security protocol commands, the function
1546 shall return EFI_UNSUPPORTED. If there is no media in the device, the function
1547 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
1548 device, the function returns EFI_MEDIA_CHANGED.
1550 If the security protocol fails to complete within the Timeout period, the function
1551 shall return EFI_TIMEOUT.
1553 If the security protocol command completes without an error, the function shall return
1554 EFI_SUCCESS. If the security protocol command completes with an error, the function
1555 shall return EFI_DEVICE_ERROR.
1557 @param This Indicates a pointer to the calling context.
1558 @param MediaId ID of the medium to receive data from.
1559 @param Timeout The timeout, in 100ns units, to use for the execution
1560 of the security protocol command. A Timeout value of 0
1561 means that this function will wait indefinitely for the
1562 security protocol command to execute. If Timeout is greater
1563 than zero, then this function will return EFI_TIMEOUT
1564 if the time required to execute the receive data command
1565 is greater than Timeout.
1566 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1567 the security protocol command to be sent.
1568 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1569 of the security protocol command to be sent.
1570 @param PayloadBufferSize Size in bytes of the payload data buffer.
1571 @param PayloadBuffer A pointer to a destination buffer to store the security
1572 protocol command specific payload data for the security
1575 @retval EFI_SUCCESS The security protocol command completed successfully.
1576 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1577 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1578 @retval EFI_NO_MEDIA There is no media in the device.
1579 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1580 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
1581 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1582 protocol command to execute.
1587 EmmcSecurityProtocolOut (
1588 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*This
,
1591 IN UINT8 SecurityProtocolId
,
1592 IN UINT16 SecurityProtocolSpecificData
,
1593 IN UINTN PayloadBufferSize
,
1594 IN VOID
*PayloadBuffer
1599 Status
= EmmcSecurityProtocolInOut (
1604 SecurityProtocolSpecificData
,
1615 Set the erase start address through sync or async I/O request.
1617 @param[in] Partition A pointer to the EMMC_PARTITION instance.
1618 @param[in] StartLba The starting logical block address to be erased.
1619 @param[in] Token A pointer to the token associated with the transaction.
1620 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1621 This parameter is only meaningful in async I/O request.
1623 @retval EFI_SUCCESS The request is executed successfully.
1624 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1625 @retval Others The request could not be executed successfully.
1629 EmmcEraseBlockStart (
1630 IN EMMC_PARTITION
*Partition
,
1631 IN EFI_LBA StartLba
,
1632 IN EFI_BLOCK_IO2_TOKEN
*Token
,
1637 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
1638 EMMC_DEVICE
*Device
;
1639 EMMC_REQUEST
*EraseBlockStart
;
1642 EraseBlockStart
= NULL
;
1644 Device
= Partition
->Device
;
1645 PassThru
= Device
->Private
->PassThru
;
1647 EraseBlockStart
= AllocateZeroPool (sizeof (EMMC_REQUEST
));
1648 if (EraseBlockStart
== NULL
) {
1649 Status
= EFI_OUT_OF_RESOURCES
;
1653 EraseBlockStart
->Signature
= EMMC_REQUEST_SIGNATURE
;
1654 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1655 InsertTailList (&Partition
->Queue
, &EraseBlockStart
->Link
);
1656 gBS
->RestoreTPL (OldTpl
);
1657 EraseBlockStart
->Packet
.SdMmcCmdBlk
= &EraseBlockStart
->SdMmcCmdBlk
;
1658 EraseBlockStart
->Packet
.SdMmcStatusBlk
= &EraseBlockStart
->SdMmcStatusBlk
;
1659 EraseBlockStart
->Packet
.Timeout
= EMMC_GENERIC_TIMEOUT
;
1661 EraseBlockStart
->SdMmcCmdBlk
.CommandIndex
= EMMC_ERASE_GROUP_START
;
1662 EraseBlockStart
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
1663 EraseBlockStart
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
1665 if (Device
->SectorAddressing
) {
1666 EraseBlockStart
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)StartLba
;
1668 EraseBlockStart
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)MultU64x32 (StartLba
, Partition
->BlockMedia
.BlockSize
);
1671 EraseBlockStart
->IsEnd
= IsEnd
;
1672 EraseBlockStart
->Token
= Token
;
1674 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1675 Status
= gBS
->CreateEvent (
1680 &EraseBlockStart
->Event
1682 if (EFI_ERROR (Status
)) {
1686 EraseBlockStart
->Event
= NULL
;
1689 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &EraseBlockStart
->Packet
, EraseBlockStart
->Event
);
1692 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1694 // For asynchronous operation, only free request and event in error case.
1695 // The request and event will be freed in asynchronous callback for success case.
1697 if (EFI_ERROR (Status
) && (EraseBlockStart
!= NULL
)) {
1698 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1699 RemoveEntryList (&EraseBlockStart
->Link
);
1700 gBS
->RestoreTPL (OldTpl
);
1701 if (EraseBlockStart
->Event
!= NULL
) {
1702 gBS
->CloseEvent (EraseBlockStart
->Event
);
1705 FreePool (EraseBlockStart
);
1709 // For synchronous operation, free request whatever the execution result is.
1711 if (EraseBlockStart
!= NULL
) {
1712 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1713 RemoveEntryList (&EraseBlockStart
->Link
);
1714 gBS
->RestoreTPL (OldTpl
);
1715 FreePool (EraseBlockStart
);
1723 Set the erase end address through sync or async I/O request.
1725 @param[in] Partition A pointer to the EMMC_PARTITION instance.
1726 @param[in] EndLba The ending logical block address to be erased.
1727 @param[in] Token A pointer to the token associated with the transaction.
1728 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1729 This parameter is only meaningful in async I/O request.
1731 @retval EFI_SUCCESS The request is executed successfully.
1732 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1733 @retval Others The request could not be executed successfully.
1738 IN EMMC_PARTITION
*Partition
,
1740 IN EFI_BLOCK_IO2_TOKEN
*Token
,
1745 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
1746 EMMC_DEVICE
*Device
;
1747 EMMC_REQUEST
*EraseBlockEnd
;
1750 EraseBlockEnd
= NULL
;
1752 Device
= Partition
->Device
;
1753 PassThru
= Device
->Private
->PassThru
;
1755 EraseBlockEnd
= AllocateZeroPool (sizeof (EMMC_REQUEST
));
1756 if (EraseBlockEnd
== NULL
) {
1757 Status
= EFI_OUT_OF_RESOURCES
;
1761 EraseBlockEnd
->Signature
= EMMC_REQUEST_SIGNATURE
;
1762 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1763 InsertTailList (&Partition
->Queue
, &EraseBlockEnd
->Link
);
1764 gBS
->RestoreTPL (OldTpl
);
1765 EraseBlockEnd
->Packet
.SdMmcCmdBlk
= &EraseBlockEnd
->SdMmcCmdBlk
;
1766 EraseBlockEnd
->Packet
.SdMmcStatusBlk
= &EraseBlockEnd
->SdMmcStatusBlk
;
1767 EraseBlockEnd
->Packet
.Timeout
= EMMC_GENERIC_TIMEOUT
;
1769 EraseBlockEnd
->SdMmcCmdBlk
.CommandIndex
= EMMC_ERASE_GROUP_END
;
1770 EraseBlockEnd
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
1771 EraseBlockEnd
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
1773 if (Device
->SectorAddressing
) {
1774 EraseBlockEnd
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)EndLba
;
1776 EraseBlockEnd
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)MultU64x32 (EndLba
, Partition
->BlockMedia
.BlockSize
);
1779 EraseBlockEnd
->IsEnd
= IsEnd
;
1780 EraseBlockEnd
->Token
= Token
;
1782 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1783 Status
= gBS
->CreateEvent (
1788 &EraseBlockEnd
->Event
1790 if (EFI_ERROR (Status
)) {
1794 EraseBlockEnd
->Event
= NULL
;
1797 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &EraseBlockEnd
->Packet
, EraseBlockEnd
->Event
);
1800 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1802 // For asynchronous operation, only free request and event in error case.
1803 // The request and event will be freed in asynchronous callback for success case.
1805 if (EFI_ERROR (Status
) && (EraseBlockEnd
!= NULL
)) {
1806 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1807 RemoveEntryList (&EraseBlockEnd
->Link
);
1808 gBS
->RestoreTPL (OldTpl
);
1809 if (EraseBlockEnd
->Event
!= NULL
) {
1810 gBS
->CloseEvent (EraseBlockEnd
->Event
);
1813 FreePool (EraseBlockEnd
);
1817 // For synchronous operation, free request whatever the execution result is.
1819 if (EraseBlockEnd
!= NULL
) {
1820 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1821 RemoveEntryList (&EraseBlockEnd
->Link
);
1822 gBS
->RestoreTPL (OldTpl
);
1823 FreePool (EraseBlockEnd
);
1831 Erase specified blocks through sync or async I/O request.
1833 @param[in] Partition A pointer to the EMMC_PARTITION instance.
1834 @param[in] Token A pointer to the token associated with the transaction.
1835 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1836 This parameter is only meaningful in async I/O request.
1838 @retval EFI_SUCCESS The request is executed successfully.
1839 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1840 @retval Others The request could not be executed successfully.
1845 IN EMMC_PARTITION
*Partition
,
1846 IN EFI_BLOCK_IO2_TOKEN
*Token
,
1851 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
1852 EMMC_DEVICE
*Device
;
1853 EMMC_REQUEST
*EraseBlock
;
1858 Device
= Partition
->Device
;
1859 PassThru
= Device
->Private
->PassThru
;
1861 EraseBlock
= AllocateZeroPool (sizeof (EMMC_REQUEST
));
1862 if (EraseBlock
== NULL
) {
1863 Status
= EFI_OUT_OF_RESOURCES
;
1867 EraseBlock
->Signature
= EMMC_REQUEST_SIGNATURE
;
1868 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1869 InsertTailList (&Partition
->Queue
, &EraseBlock
->Link
);
1870 gBS
->RestoreTPL (OldTpl
);
1871 EraseBlock
->Packet
.SdMmcCmdBlk
= &EraseBlock
->SdMmcCmdBlk
;
1872 EraseBlock
->Packet
.SdMmcStatusBlk
= &EraseBlock
->SdMmcStatusBlk
;
1873 EraseBlock
->Packet
.Timeout
= EMMC_GENERIC_TIMEOUT
;
1875 EraseBlock
->SdMmcCmdBlk
.CommandIndex
= EMMC_ERASE
;
1876 EraseBlock
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
1877 EraseBlock
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1b
;
1878 if ((Device
->ExtCsd
.SecFeatureSupport
& BIT4
) != 0) {
1880 // Perform a Trim operation which applies the erase operation to write blocks
1881 // instead of erase groups. (Spec JESD84-B51, eMMC Electrical Standard 5.1,
1882 // Section 6.6.10 and 6.10.4)
1884 EraseBlock
->SdMmcCmdBlk
.CommandArgument
= 1;
1887 EraseBlock
->IsEnd
= IsEnd
;
1888 EraseBlock
->Token
= Token
;
1890 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1891 Status
= gBS
->CreateEvent (
1898 if (EFI_ERROR (Status
)) {
1902 EraseBlock
->Event
= NULL
;
1905 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &EraseBlock
->Packet
, EraseBlock
->Event
);
1908 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1910 // For asynchronous operation, only free request and event in error case.
1911 // The request and event will be freed in asynchronous callback for success case.
1913 if (EFI_ERROR (Status
) && (EraseBlock
!= NULL
)) {
1914 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1915 RemoveEntryList (&EraseBlock
->Link
);
1916 gBS
->RestoreTPL (OldTpl
);
1917 if (EraseBlock
->Event
!= NULL
) {
1918 gBS
->CloseEvent (EraseBlock
->Event
);
1921 FreePool (EraseBlock
);
1925 // For synchronous operation, free request whatever the execution result is.
1927 if (EraseBlock
!= NULL
) {
1928 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1929 RemoveEntryList (&EraseBlock
->Link
);
1930 gBS
->RestoreTPL (OldTpl
);
1931 FreePool (EraseBlock
);
1939 Write zeros to specified blocks.
1941 @param[in] Partition A pointer to the EMMC_PARTITION instance.
1942 @param[in] StartLba The starting logical block address to write zeros.
1943 @param[in] Size The size in bytes to fill with zeros. This must be a multiple of
1944 the physical block size of the device.
1946 @retval EFI_SUCCESS The request is executed successfully.
1947 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1948 @retval Others The request could not be executed successfully.
1953 IN EMMC_PARTITION
*Partition
,
1954 IN EFI_LBA StartLba
,
1962 Buffer
= AllocateZeroPool (Size
);
1963 if (Buffer
== NULL
) {
1964 return EFI_OUT_OF_RESOURCES
;
1967 MediaId
= Partition
->BlockMedia
.MediaId
;
1969 Status
= EmmcReadWrite (Partition
, MediaId
, StartLba
, Buffer
, Size
, FALSE
, NULL
);
1976 Erase a specified number of device blocks.
1978 @param[in] This Indicates a pointer to the calling context.
1979 @param[in] MediaId The media ID that the erase request is for.
1980 @param[in] Lba The starting logical block address to be
1981 erased. The caller is responsible for erasing
1982 only legitimate locations.
1983 @param[in, out] Token A pointer to the token associated with the
1985 @param[in] Size The size in bytes to be erased. This must be
1986 a multiple of the physical block size of the
1989 @retval EFI_SUCCESS The erase request was queued if Event is not
1990 NULL. The data was erased correctly to the
1991 device if the Event is NULL.to the device.
1992 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1994 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1995 to perform the erase operation.
1996 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1998 @retval EFI_NO_MEDIA There is no media in the device.
1999 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
2005 IN EFI_ERASE_BLOCK_PROTOCOL
*This
,
2008 IN OUT EFI_ERASE_BLOCK_TOKEN
*Token
,
2013 EFI_BLOCK_IO_MEDIA
*Media
;
2018 EFI_LBA StartGroupLba
;
2019 EFI_LBA EndGroupLba
;
2020 UINT32 EraseGroupSize
;
2022 UINTN WriteZeroSize
;
2023 UINT8 PartitionConfig
;
2024 EMMC_PARTITION
*Partition
;
2025 EMMC_DEVICE
*Device
;
2027 Status
= EFI_SUCCESS
;
2028 Partition
= EMMC_PARTITION_DATA_FROM_ERASEBLK (This
);
2029 Device
= Partition
->Device
;
2030 Media
= &Partition
->BlockMedia
;
2032 if (MediaId
!= Media
->MediaId
) {
2033 return EFI_MEDIA_CHANGED
;
2036 if (Media
->ReadOnly
) {
2037 return EFI_WRITE_PROTECTED
;
2041 // Check parameters.
2043 BlockSize
= Media
->BlockSize
;
2044 if ((Size
% BlockSize
) != 0) {
2045 return EFI_INVALID_PARAMETER
;
2048 BlockNum
= Size
/ BlockSize
;
2049 if ((Lba
+ BlockNum
- 1) > Media
->LastBlock
) {
2050 return EFI_INVALID_PARAMETER
;
2053 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
2054 Token
->TransactionStatus
= EFI_SUCCESS
;
2058 LastLba
= Lba
+ BlockNum
- 1;
2061 // Check if needs to switch partition access.
2063 PartitionConfig
= Device
->ExtCsd
.PartitionConfig
;
2064 if ((PartitionConfig
& 0x7) != Partition
->PartitionType
) {
2065 PartitionConfig
&= (UINT8
) ~0x7;
2066 PartitionConfig
|= Partition
->PartitionType
;
2067 Status
= EmmcSetExtCsd (Partition
, OFFSET_OF (EMMC_EXT_CSD
, PartitionConfig
), PartitionConfig
, (EFI_BLOCK_IO2_TOKEN
*)Token
, FALSE
);
2068 if (EFI_ERROR (Status
)) {
2072 Device
->ExtCsd
.PartitionConfig
= PartitionConfig
;
2075 if ((Device
->ExtCsd
.SecFeatureSupport
& BIT4
) == 0) {
2077 // If the Trim operation is not supported by the device, handle the erase
2078 // of blocks that do not form a complete erase group separately.
2080 EraseGroupSize
= This
->EraseLengthGranularity
;
2082 DivU64x32Remainder (FirstLba
, EraseGroupSize
, &Remainder
);
2083 StartGroupLba
= (Remainder
== 0) ? FirstLba
: (FirstLba
+ EraseGroupSize
- Remainder
);
2085 DivU64x32Remainder (LastLba
+ 1, EraseGroupSize
, &Remainder
);
2086 EndGroupLba
= LastLba
+ 1 - Remainder
;
2089 // If the size to erase is smaller than the erase group size, the whole
2090 // erase operation is performed by writing zeros.
2092 if (BlockNum
< EraseGroupSize
) {
2093 Status
= EmmcWriteZeros (Partition
, FirstLba
, Size
);
2094 if (EFI_ERROR (Status
)) {
2100 "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
2103 (Token
!= NULL
) ? Token
->Event
: NULL
,
2107 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
2108 Token
->TransactionStatus
= EFI_SUCCESS
;
2109 gBS
->SignalEvent (Token
->Event
);
2116 // If the starting LBA to erase is not aligned with the start of an erase
2117 // group, write zeros to erase the data from starting LBA to the end of the
2118 // current erase group.
2120 if (StartGroupLba
> FirstLba
) {
2121 WriteZeroSize
= (UINTN
)(StartGroupLba
- FirstLba
) * BlockSize
;
2122 Status
= EmmcWriteZeros (Partition
, FirstLba
, WriteZeroSize
);
2123 if (EFI_ERROR (Status
)) {
2129 // If the ending LBA to erase is not aligned with the end of an erase
2130 // group, write zeros to erase the data from the start of the erase group
2131 // to the ending LBA.
2133 if (EndGroupLba
<= LastLba
) {
2134 WriteZeroSize
= (UINTN
)(LastLba
+ 1 - EndGroupLba
) * BlockSize
;
2135 Status
= EmmcWriteZeros (Partition
, EndGroupLba
, WriteZeroSize
);
2136 if (EFI_ERROR (Status
)) {
2142 // Check whether there is erase group to erase.
2144 if (EndGroupLba
<= StartGroupLba
) {
2147 "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
2150 (Token
!= NULL
) ? Token
->Event
: NULL
,
2154 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
2155 Token
->TransactionStatus
= EFI_SUCCESS
;
2156 gBS
->SignalEvent (Token
->Event
);
2162 FirstLba
= StartGroupLba
;
2163 LastLba
= EndGroupLba
- 1;
2166 Status
= EmmcEraseBlockStart (Partition
, FirstLba
, (EFI_BLOCK_IO2_TOKEN
*)Token
, FALSE
);
2167 if (EFI_ERROR (Status
)) {
2171 Status
= EmmcEraseBlockEnd (Partition
, LastLba
, (EFI_BLOCK_IO2_TOKEN
*)Token
, FALSE
);
2172 if (EFI_ERROR (Status
)) {
2176 Status
= EmmcEraseBlock (Partition
, (EFI_BLOCK_IO2_TOKEN
*)Token
, TRUE
);
2177 if (EFI_ERROR (Status
)) {
2183 "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
2186 (Token
!= NULL
) ? Token
->Event
: NULL
,