1 /** @file
2   The helper functions for BlockIo and BlockIo2 protocol.
3 
4   Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "EmmcDxe.h"
10 
11 /**
12   Nonblocking I/O callback function when the event is signaled.
13 
14   @param[in]  Event     The Event this notify function registered to.
15   @param[in]  Context   Pointer to the context data registered to the
16                         Event.
17 
18 **/
19 VOID
20 EFIAPI
AsyncIoCallback(IN EFI_EVENT Event,IN VOID * Context)21 AsyncIoCallback (
22   IN EFI_EVENT                Event,
23   IN VOID                     *Context
24   )
25 {
26   EMMC_REQUEST                *Request;
27   EFI_STATUS                  Status;
28 
29   Status = gBS->CloseEvent (Event);
30   if (EFI_ERROR (Status)) {
31     return;
32   }
33 
34   Request = (EMMC_REQUEST *) Context;
35 
36   DEBUG_CODE_BEGIN ();
37     DEBUG ((EFI_D_INFO, "Emmc Async Request: CmdIndex[%d] Arg[%08x] %r\n",
38             Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,
39             Request->Packet.TransactionStatus));
40   DEBUG_CODE_END ();
41 
42   if (EFI_ERROR (Request->Packet.TransactionStatus)) {
43     Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
44   }
45 
46   RemoveEntryList (&Request->Link);
47 
48   if (Request->IsEnd) {
49     gBS->SignalEvent (Request->Token->Event);
50   }
51 
52   FreePool (Request);
53 }
54 
55 /**
56   Send command SELECT to the device to select/deselect the device.
57 
58   @param[in]  Device            A pointer to the EMMC_DEVICE instance.
59   @param[in]  Rca               The relative device address to use.
60 
61   @retval EFI_SUCCESS           The request is executed successfully.
62   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
63   @retval Others                The request could not be executed successfully.
64 
65 **/
66 EFI_STATUS
EmmcSelect(IN EMMC_DEVICE * Device,IN UINT16 Rca)67 EmmcSelect (
68   IN     EMMC_DEVICE                  *Device,
69   IN     UINT16                       Rca
70   )
71 {
72   EFI_STATUS                          Status;
73   EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;
74   EFI_SD_MMC_COMMAND_BLOCK            SdMmcCmdBlk;
75   EFI_SD_MMC_STATUS_BLOCK             SdMmcStatusBlk;
76   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
77 
78   PassThru = Device->Private->PassThru;
79 
80   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
81   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
82   ZeroMem (&Packet, sizeof (Packet));
83   Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
84   Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
85   Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
86 
87   SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
88   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
89   SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
90   SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
91 
92   Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
93 
94   return Status;
95 }
96 
97 /**
98   Send command SEND_STATUS to the device to get device status.
99 
100   @param[in]  Device            A pointer to the EMMC_DEVICE instance.
101   @param[in]  Rca               The relative device address to use.
102   @param[out] DevStatus         The buffer to store the device status.
103 
104   @retval EFI_SUCCESS           The request is executed successfully.
105   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
106   @retval Others                The request could not be executed successfully.
107 
108 **/
109 EFI_STATUS
EmmcSendStatus(IN EMMC_DEVICE * Device,IN UINT16 Rca,OUT UINT32 * DevStatus)110 EmmcSendStatus (
111   IN     EMMC_DEVICE                  *Device,
112   IN     UINT16                       Rca,
113      OUT UINT32                       *DevStatus
114   )
115 {
116   EFI_STATUS                          Status;
117   EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;
118   EFI_SD_MMC_COMMAND_BLOCK            SdMmcCmdBlk;
119   EFI_SD_MMC_STATUS_BLOCK             SdMmcStatusBlk;
120   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
121 
122   PassThru = Device->Private->PassThru;
123 
124   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
125   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
126   ZeroMem (&Packet, sizeof (Packet));
127   Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
128   Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
129   Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
130 
131   SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
132   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
133   SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
134   SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
135 
136   Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
137   if (!EFI_ERROR (Status)) {
138     CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));
139   }
140 
141   return Status;
142 }
143 
144 /**
145   Send command SEND_CSD to the device to get the CSD register data.
146 
147   @param[in]  Device            A pointer to the EMMC_DEVICE instance.
148   @param[in]  Rca               The relative device address to use.
149   @param[out] Csd               The buffer to store the EMMC_CSD register data.
150 
151   @retval EFI_SUCCESS           The request is executed successfully.
152   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
153   @retval Others                The request could not be executed successfully.
154 
155 **/
156 EFI_STATUS
EmmcGetCsd(IN EMMC_DEVICE * Device,IN UINT16 Rca,OUT EMMC_CSD * Csd)157 EmmcGetCsd (
158   IN     EMMC_DEVICE                  *Device,
159   IN     UINT16                       Rca,
160      OUT EMMC_CSD                     *Csd
161   )
162 {
163   EFI_STATUS                          Status;
164   EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;
165   EFI_SD_MMC_COMMAND_BLOCK            SdMmcCmdBlk;
166   EFI_SD_MMC_STATUS_BLOCK             SdMmcStatusBlk;
167   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
168 
169   PassThru = Device->Private->PassThru;
170 
171   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
172   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
173   ZeroMem (&Packet, sizeof (Packet));
174   ZeroMem (Csd, sizeof (EMMC_CSD));
175 
176   Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
177   Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
178   Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
179 
180   SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
181   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
182   SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
183   SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
184 
185   Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
186   if (!EFI_ERROR (Status)) {
187     //
188     // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
189     //
190     CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
191   }
192 
193   return Status;
194 }
195 
196 /**
197   Send command SEND_CID to the device to get the CID register data.
198 
199   @param[in]  Device            A pointer to the EMMC_DEVICE instance.
200   @param[in]  Rca               The relative device address to use.
201   @param[out] Cid               The buffer to store the EMMC_CID register data.
202 
203   @retval EFI_SUCCESS           The request is executed successfully.
204   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
205   @retval Others                The request could not be executed successfully.
206 
207 **/
208 EFI_STATUS
EmmcGetCid(IN EMMC_DEVICE * Device,IN UINT16 Rca,OUT EMMC_CID * Cid)209 EmmcGetCid (
210   IN     EMMC_DEVICE            *Device,
211   IN     UINT16                 Rca,
212      OUT EMMC_CID               *Cid
213   )
214 {
215   EFI_STATUS                          Status;
216   EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;
217   EFI_SD_MMC_COMMAND_BLOCK            SdMmcCmdBlk;
218   EFI_SD_MMC_STATUS_BLOCK             SdMmcStatusBlk;
219   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
220 
221   PassThru = Device->Private->PassThru;
222 
223   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
224   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
225   ZeroMem (&Packet, sizeof (Packet));
226   ZeroMem (Cid, sizeof (EMMC_CID));
227 
228   Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
229   Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
230   Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
231 
232   SdMmcCmdBlk.CommandIndex = EMMC_SEND_CID;
233   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
234   SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
235   SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
236 
237   Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
238   if (!EFI_ERROR (Status)) {
239     //
240     // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
241     //
242     CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CID) - 1);
243   }
244 
245   return Status;
246 }
247 
248 /**
249   Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.
250 
251   @param[in]  Device            A pointer to the EMMC_DEVICE instance.
252   @param[out] ExtCsd            The buffer to store the EXT_CSD register data.
253 
254   @retval EFI_SUCCESS           The request is executed successfully.
255   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
256   @retval Others                The request could not be executed successfully.
257 
258 **/
259 EFI_STATUS
EmmcGetExtCsd(IN EMMC_DEVICE * Device,OUT EMMC_EXT_CSD * ExtCsd)260 EmmcGetExtCsd (
261   IN     EMMC_DEVICE                  *Device,
262      OUT EMMC_EXT_CSD                 *ExtCsd
263   )
264 {
265   EFI_STATUS                          Status;
266   EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;
267   EFI_SD_MMC_COMMAND_BLOCK            SdMmcCmdBlk;
268   EFI_SD_MMC_STATUS_BLOCK             SdMmcStatusBlk;
269   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
270 
271   PassThru = Device->Private->PassThru;
272 
273   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
274   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
275   ZeroMem (&Packet, sizeof (Packet));
276   ZeroMem (ExtCsd, sizeof (EMMC_EXT_CSD));
277   Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
278   Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
279   Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
280 
281   SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
282   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
283   SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
284   SdMmcCmdBlk.CommandArgument = 0x00000000;
285   Packet.InDataBuffer     = ExtCsd;
286   Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
287 
288   Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
289 
290   return Status;
291 }
292 
293 /**
294   Set the specified EXT_CSD register field through sync or async I/O request.
295 
296   @param[in]  Partition         A pointer to the EMMC_PARTITION instance.
297   @param[in]  Offset            The offset of the specified field in EXT_CSD register.
298   @param[in]  Value             The byte value written to the field specified by Offset.
299   @param[in]  Token             A pointer to the token associated with the transaction.
300   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
301                                 This parameter is only meaningful in async I/O request.
302 
303   @retval EFI_SUCCESS           The request is executed successfully.
304   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
305   @retval Others                The request could not be executed successfully.
306 
307 **/
308 EFI_STATUS
EmmcSetExtCsd(IN EMMC_PARTITION * Partition,IN UINT8 Offset,IN UINT8 Value,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)309 EmmcSetExtCsd (
310   IN  EMMC_PARTITION            *Partition,
311   IN  UINT8                     Offset,
312   IN  UINT8                     Value,
313   IN  EFI_BLOCK_IO2_TOKEN       *Token,
314   IN  BOOLEAN                   IsEnd
315   )
316 {
317   EFI_STATUS                    Status;
318   EMMC_DEVICE                   *Device;
319   EMMC_REQUEST                  *SetExtCsdReq;
320   EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
321   UINT32                        CommandArgument;
322   EFI_TPL                       OldTpl;
323 
324   SetExtCsdReq = NULL;
325 
326   Device   = Partition->Device;
327   PassThru = Device->Private->PassThru;
328 
329   SetExtCsdReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
330   if (SetExtCsdReq == NULL) {
331     Status = EFI_OUT_OF_RESOURCES;
332     goto Error;
333   }
334 
335   SetExtCsdReq->Signature = EMMC_REQUEST_SIGNATURE;
336   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
337   InsertTailList (&Partition->Queue, &SetExtCsdReq->Link);
338   gBS->RestoreTPL (OldTpl);
339   SetExtCsdReq->Packet.SdMmcCmdBlk    = &SetExtCsdReq->SdMmcCmdBlk;
340   SetExtCsdReq->Packet.SdMmcStatusBlk = &SetExtCsdReq->SdMmcStatusBlk;
341   SetExtCsdReq->Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
342 
343   SetExtCsdReq->SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
344   SetExtCsdReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
345   SetExtCsdReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
346   //
347   // Write the Value to the field specified by Offset.
348   //
349   CommandArgument = (Value << 8) | (Offset << 16) | BIT24 | BIT25;
350   SetExtCsdReq->SdMmcCmdBlk.CommandArgument = CommandArgument;
351 
352   SetExtCsdReq->IsEnd = IsEnd;
353   SetExtCsdReq->Token = Token;
354 
355   if ((Token != NULL) && (Token->Event != NULL)) {
356     Status = gBS->CreateEvent (
357                     EVT_NOTIFY_SIGNAL,
358                     TPL_NOTIFY,
359                     AsyncIoCallback,
360                     SetExtCsdReq,
361                     &SetExtCsdReq->Event
362                     );
363     if (EFI_ERROR (Status)) {
364       goto Error;
365     }
366   } else {
367     SetExtCsdReq->Event = NULL;
368   }
369 
370   Status = PassThru->PassThru (PassThru, Device->Slot, &SetExtCsdReq->Packet, SetExtCsdReq->Event);
371 
372 Error:
373   if ((Token != NULL) && (Token->Event != NULL)) {
374     //
375     // For asynchronous operation, only free request and event in error case.
376     // The request and event will be freed in asynchronous callback for success case.
377     //
378     if (EFI_ERROR (Status) && (SetExtCsdReq != NULL)) {
379       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
380       RemoveEntryList (&SetExtCsdReq->Link);
381       gBS->RestoreTPL (OldTpl);
382       if (SetExtCsdReq->Event != NULL) {
383         gBS->CloseEvent (SetExtCsdReq->Event);
384       }
385       FreePool (SetExtCsdReq);
386     }
387   } else {
388     //
389     // For synchronous operation, free request whatever the execution result is.
390     //
391     if (SetExtCsdReq != NULL) {
392       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
393       RemoveEntryList (&SetExtCsdReq->Link);
394       gBS->RestoreTPL (OldTpl);
395       FreePool (SetExtCsdReq);
396     }
397   }
398 
399   return Status;
400 }
401 
402 /**
403   Set the number of blocks for a block read/write cmd through sync or async I/O request.
404 
405   @param[in]  Partition         A pointer to the EMMC_PARTITION instance.
406   @param[in]  BlockNum          The number of blocks for transfer.
407   @param[in]  Token             A pointer to the token associated with the transaction.
408   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
409                                 This parameter is only meaningful in async I/O request.
410 
411   @retval EFI_SUCCESS           The request is executed successfully.
412   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
413   @retval Others                The request could not be executed successfully.
414 
415 **/
416 EFI_STATUS
EmmcSetBlkCount(IN EMMC_PARTITION * Partition,IN UINT16 BlockNum,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)417 EmmcSetBlkCount (
418   IN  EMMC_PARTITION            *Partition,
419   IN  UINT16                    BlockNum,
420   IN  EFI_BLOCK_IO2_TOKEN       *Token,
421   IN  BOOLEAN                   IsEnd
422   )
423 {
424   EFI_STATUS                    Status;
425   EMMC_DEVICE                   *Device;
426   EMMC_REQUEST                  *SetBlkCntReq;
427   EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
428   EFI_TPL                       OldTpl;
429 
430   SetBlkCntReq = NULL;
431 
432   Device   = Partition->Device;
433   PassThru = Device->Private->PassThru;
434 
435   SetBlkCntReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
436   if (SetBlkCntReq == NULL) {
437     Status = EFI_OUT_OF_RESOURCES;
438     goto Error;
439   }
440 
441   SetBlkCntReq->Signature = EMMC_REQUEST_SIGNATURE;
442   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
443   InsertTailList (&Partition->Queue, &SetBlkCntReq->Link);
444   gBS->RestoreTPL (OldTpl);
445   SetBlkCntReq->Packet.SdMmcCmdBlk    = &SetBlkCntReq->SdMmcCmdBlk;
446   SetBlkCntReq->Packet.SdMmcStatusBlk = &SetBlkCntReq->SdMmcStatusBlk;
447   SetBlkCntReq->Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
448 
449   SetBlkCntReq->SdMmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;
450   SetBlkCntReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
451   SetBlkCntReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
452   SetBlkCntReq->SdMmcCmdBlk.CommandArgument = BlockNum;
453 
454   SetBlkCntReq->IsEnd = IsEnd;
455   SetBlkCntReq->Token = Token;
456 
457   if ((Token != NULL) && (Token->Event != NULL)) {
458     Status = gBS->CreateEvent (
459                     EVT_NOTIFY_SIGNAL,
460                     TPL_NOTIFY,
461                     AsyncIoCallback,
462                     SetBlkCntReq,
463                     &SetBlkCntReq->Event
464                     );
465     if (EFI_ERROR (Status)) {
466       goto Error;
467     }
468   } else {
469     SetBlkCntReq->Event = NULL;
470   }
471 
472   Status = PassThru->PassThru (PassThru, Device->Slot, &SetBlkCntReq->Packet, SetBlkCntReq->Event);
473 
474 Error:
475   if ((Token != NULL) && (Token->Event != NULL)) {
476     //
477     // For asynchronous operation, only free request and event in error case.
478     // The request and event will be freed in asynchronous callback for success case.
479     //
480     if (EFI_ERROR (Status) && (SetBlkCntReq != NULL)) {
481       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
482       RemoveEntryList (&SetBlkCntReq->Link);
483       gBS->RestoreTPL (OldTpl);
484       if (SetBlkCntReq->Event != NULL) {
485         gBS->CloseEvent (SetBlkCntReq->Event);
486       }
487       FreePool (SetBlkCntReq);
488     }
489   } else {
490     //
491     // For synchronous operation, free request whatever the execution result is.
492     //
493     if (SetBlkCntReq != NULL) {
494       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
495       RemoveEntryList (&SetBlkCntReq->Link);
496       gBS->RestoreTPL (OldTpl);
497       FreePool (SetBlkCntReq);
498     }
499   }
500 
501   return Status;
502 }
503 
504 /**
505   Read blocks through security protocol cmds with the way of sync or async I/O request.
506 
507   @param[in]  Partition                    A pointer to the EMMC_PARTITION instance.
508   @param[in]  SecurityProtocolId           The value of the "Security Protocol" parameter of
509                                            the security protocol command to be sent.
510   @param[in]  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
511                                            of the security protocol command to be sent.
512   @param[in]  PayloadBufferSize            Size in bytes of the payload data buffer.
513   @param[out] PayloadBuffer                A pointer to a destination buffer to store the security
514                                            protocol command specific payload data for the security
515                                            protocol command. The caller is responsible for having
516                                            either implicit or explicit ownership of the buffer.
517   @param[in]  IsRead                       Indicates it is a read or write operation.
518   @param[in]  Timeout                      The timeout value, in 100ns units.
519   @param[in]  Token                        A pointer to the token associated with the transaction.
520   @param[in]  IsEnd                        A boolean to show whether it's the last cmd in a series of cmds.
521                                            This parameter is only meaningful in async I/O request.
522 
523   @retval EFI_SUCCESS                      The request is executed successfully.
524   @retval EFI_OUT_OF_RESOURCES             The request could not be executed due to a lack of resources.
525   @retval Others                           The request could not be executed successfully.
526 
527 **/
528 EFI_STATUS
EmmcProtocolInOut(IN EMMC_PARTITION * Partition,IN UINT8 SecurityProtocol,IN UINT16 SecurityProtocolSpecificData,IN UINTN PayloadBufferSize,OUT VOID * PayloadBuffer,IN BOOLEAN IsRead,IN UINT64 Timeout,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)529 EmmcProtocolInOut (
530   IN     EMMC_PARTITION            *Partition,
531   IN     UINT8                     SecurityProtocol,
532   IN     UINT16                    SecurityProtocolSpecificData,
533   IN     UINTN                     PayloadBufferSize,
534      OUT VOID                      *PayloadBuffer,
535   IN     BOOLEAN                   IsRead,
536   IN     UINT64                    Timeout,
537   IN     EFI_BLOCK_IO2_TOKEN       *Token,
538   IN     BOOLEAN                   IsEnd
539   )
540 {
541   EFI_STATUS                    Status;
542   EMMC_DEVICE                   *Device;
543   EMMC_REQUEST                  *ProtocolReq;
544   EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
545   EFI_TPL                       OldTpl;
546 
547   ProtocolReq = NULL;
548 
549   Device   = Partition->Device;
550   PassThru = Device->Private->PassThru;
551 
552   ProtocolReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
553   if (ProtocolReq == NULL) {
554     Status = EFI_OUT_OF_RESOURCES;
555     goto Error;
556   }
557 
558   ProtocolReq->Signature = EMMC_REQUEST_SIGNATURE;
559   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
560   InsertTailList (&Partition->Queue, &ProtocolReq->Link);
561   gBS->RestoreTPL (OldTpl);
562   ProtocolReq->Packet.SdMmcCmdBlk    = &ProtocolReq->SdMmcCmdBlk;
563   ProtocolReq->Packet.SdMmcStatusBlk = &ProtocolReq->SdMmcStatusBlk;
564 
565   if (IsRead) {
566     ProtocolReq->Packet.InDataBuffer     = PayloadBuffer;
567     ProtocolReq->Packet.InTransferLength = (UINT32)PayloadBufferSize;
568 
569     ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_RD;
570     ProtocolReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
571     ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
572   } else {
573     ProtocolReq->Packet.OutDataBuffer     = PayloadBuffer;
574     ProtocolReq->Packet.OutTransferLength = (UINT32)PayloadBufferSize;
575 
576     ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_WR;
577     ProtocolReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
578     ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
579   }
580 
581   ProtocolReq->SdMmcCmdBlk.CommandArgument = (SecurityProtocol << 8) | (SecurityProtocolSpecificData << 16);
582   //
583   // Convert to 1 microsecond unit.
584   //
585   ProtocolReq->Packet.Timeout = DivU64x32 (Timeout, 10) + 1;
586 
587   ProtocolReq->IsEnd = IsEnd;
588   ProtocolReq->Token = Token;
589 
590   if ((Token != NULL) && (Token->Event != NULL)) {
591     Status = gBS->CreateEvent (
592                     EVT_NOTIFY_SIGNAL,
593                     TPL_NOTIFY,
594                     AsyncIoCallback,
595                     ProtocolReq,
596                     &ProtocolReq->Event
597                     );
598     if (EFI_ERROR (Status)) {
599       goto Error;
600     }
601   } else {
602     ProtocolReq->Event = NULL;
603   }
604 
605   Status = PassThru->PassThru (PassThru, Device->Slot, &ProtocolReq->Packet, ProtocolReq->Event);
606 
607 Error:
608   if ((Token != NULL) && (Token->Event != NULL)) {
609     //
610     // For asynchronous operation, only free request and event in error case.
611     // The request and event will be freed in asynchronous callback for success case.
612     //
613     if (EFI_ERROR (Status) && (ProtocolReq != NULL)) {
614       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
615       RemoveEntryList (&ProtocolReq->Link);
616       gBS->RestoreTPL (OldTpl);
617       if (ProtocolReq->Event != NULL) {
618         gBS->CloseEvent (ProtocolReq->Event);
619       }
620       FreePool (ProtocolReq);
621     }
622   } else {
623     //
624     // For synchronous operation, free request whatever the execution result is.
625     //
626     if (ProtocolReq != NULL) {
627       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
628       RemoveEntryList (&ProtocolReq->Link);
629       gBS->RestoreTPL (OldTpl);
630       FreePool (ProtocolReq);
631     }
632   }
633 
634   return Status;
635 }
636 
637 /**
638   Read/write multiple blocks through sync or async I/O request.
639 
640   @param[in]  Partition         A pointer to the EMMC_PARTITION instance.
641   @param[in]  Lba               The starting logical block address to be read/written.
642                                 The caller is responsible for reading/writing to only
643                                 legitimate locations.
644   @param[in]  Buffer            A pointer to the destination/source buffer for the data.
645   @param[in]  BufferSize        Size of Buffer, must be a multiple of device block size.
646   @param[in]  IsRead            Indicates it is a read or write operation.
647   @param[in]  Token             A pointer to the token associated with the transaction.
648   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
649                                 This parameter is only meaningful in async I/O request.
650 
651   @retval EFI_SUCCESS           The request is executed successfully.
652   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
653   @retval Others                The request could not be executed successfully.
654 
655 **/
656 EFI_STATUS
EmmcRwMultiBlocks(IN EMMC_PARTITION * Partition,IN EFI_LBA Lba,IN VOID * Buffer,IN UINTN BufferSize,IN BOOLEAN IsRead,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)657 EmmcRwMultiBlocks (
658   IN  EMMC_PARTITION            *Partition,
659   IN  EFI_LBA                   Lba,
660   IN  VOID                      *Buffer,
661   IN  UINTN                     BufferSize,
662   IN  BOOLEAN                   IsRead,
663   IN  EFI_BLOCK_IO2_TOKEN       *Token,
664   IN  BOOLEAN                   IsEnd
665   )
666 {
667   EFI_STATUS                    Status;
668   EMMC_DEVICE                   *Device;
669   EMMC_REQUEST                  *RwMultiBlkReq;
670   EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
671   EFI_TPL                       OldTpl;
672 
673   RwMultiBlkReq = NULL;
674 
675   Device   = Partition->Device;
676   PassThru = Device->Private->PassThru;
677 
678   RwMultiBlkReq = AllocateZeroPool (sizeof (EMMC_REQUEST));
679   if (RwMultiBlkReq == NULL) {
680     Status = EFI_OUT_OF_RESOURCES;
681     goto Error;
682   }
683 
684   RwMultiBlkReq->Signature = EMMC_REQUEST_SIGNATURE;
685   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
686   InsertTailList (&Partition->Queue, &RwMultiBlkReq->Link);
687   gBS->RestoreTPL (OldTpl);
688   RwMultiBlkReq->Packet.SdMmcCmdBlk    = &RwMultiBlkReq->SdMmcCmdBlk;
689   RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;
690   //
691   // Calculate timeout value through the below formula.
692   // Timeout = (transfer size) / (2MB/s).
693   // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest
694   // transfer speed (2.4MB/s).
695   // Refer to eMMC 5.0 spec section 6.9.1 for details.
696   //
697   RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
698 
699   if (IsRead) {
700     RwMultiBlkReq->Packet.InDataBuffer     = Buffer;
701     RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
702 
703     RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;
704     RwMultiBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
705     RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
706   } else {
707     RwMultiBlkReq->Packet.OutDataBuffer     = Buffer;
708     RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
709 
710     RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;
711     RwMultiBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
712     RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
713   }
714 
715   if (Partition->Device->SectorAddressing) {
716     RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
717   } else {
718     RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Partition->BlockMedia.BlockSize);
719   }
720 
721   RwMultiBlkReq->IsEnd = IsEnd;
722   RwMultiBlkReq->Token = Token;
723 
724   if ((Token != NULL) && (Token->Event != NULL)) {
725     Status = gBS->CreateEvent (
726                     EVT_NOTIFY_SIGNAL,
727                     TPL_NOTIFY,
728                     AsyncIoCallback,
729                     RwMultiBlkReq,
730                     &RwMultiBlkReq->Event
731                     );
732     if (EFI_ERROR (Status)) {
733       goto Error;
734     }
735   } else {
736     RwMultiBlkReq->Event = NULL;
737   }
738 
739   Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
740 
741 Error:
742   if ((Token != NULL) && (Token->Event != NULL)) {
743     //
744     // For asynchronous operation, only free request and event in error case.
745     // The request and event will be freed in asynchronous callback for success case.
746     //
747     if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
748       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
749       RemoveEntryList (&RwMultiBlkReq->Link);
750       gBS->RestoreTPL (OldTpl);
751       if (RwMultiBlkReq->Event != NULL) {
752         gBS->CloseEvent (RwMultiBlkReq->Event);
753       }
754       FreePool (RwMultiBlkReq);
755     }
756   } else {
757     //
758     // For synchronous operation, free request whatever the execution result is.
759     //
760     if (RwMultiBlkReq != NULL) {
761       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
762       RemoveEntryList (&RwMultiBlkReq->Link);
763       gBS->RestoreTPL (OldTpl);
764       FreePool (RwMultiBlkReq);
765     }
766   }
767 
768   return Status;
769 }
770 
771 /**
772   This function transfers data from/to EMMC device.
773 
774   @param[in]       Partition    A pointer to the EMMC_PARTITION instance.
775   @param[in]       MediaId      The media ID that the read/write request is for.
776   @param[in]       Lba          The starting logical block address to be read/written.
777                                 The caller is responsible for reading/writing to only
778                                 legitimate locations.
779   @param[in, out]  Buffer       A pointer to the destination/source buffer for the data.
780   @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.
781   @param[in]       IsRead       Indicates it is a read or write operation.
782   @param[in, out]  Token        A pointer to the token associated with the transaction.
783 
784   @retval EFI_SUCCESS           The data was read/written correctly to the device.
785   @retval EFI_WRITE_PROTECTED   The device can not be read/written to.
786   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read/write.
787   @retval EFI_NO_MEDIA          There is no media in the device.
788   @retval EFI_MEDIA_CHANGED     The MediaId does not match the current device.
789   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
790   @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,
791                                 or the buffer is not on proper alignment.
792 
793 **/
794 EFI_STATUS
EmmcReadWrite(IN EMMC_PARTITION * Partition,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT VOID * Buffer,IN UINTN BufferSize,IN BOOLEAN IsRead,IN OUT EFI_BLOCK_IO2_TOKEN * Token)795 EmmcReadWrite (
796   IN     EMMC_PARTITION                 *Partition,
797   IN     UINT32                         MediaId,
798   IN     EFI_LBA                        Lba,
799   IN OUT VOID                           *Buffer,
800   IN     UINTN                          BufferSize,
801   IN     BOOLEAN                        IsRead,
802   IN OUT EFI_BLOCK_IO2_TOKEN            *Token
803   )
804 {
805   EFI_STATUS                            Status;
806   EMMC_DEVICE                           *Device;
807   EFI_BLOCK_IO_MEDIA                    *Media;
808   UINTN                                 BlockSize;
809   UINTN                                 BlockNum;
810   UINTN                                 IoAlign;
811   UINT8                                 PartitionConfig;
812   UINTN                                 Remaining;
813   UINT32                                MaxBlock;
814   BOOLEAN                               LastRw;
815 
816   Status = EFI_SUCCESS;
817   Device = Partition->Device;
818   Media  = &Partition->BlockMedia;
819   LastRw = FALSE;
820 
821   if (MediaId != Media->MediaId) {
822     return EFI_MEDIA_CHANGED;
823   }
824 
825   if (!IsRead && Media->ReadOnly) {
826     return EFI_WRITE_PROTECTED;
827   }
828 
829   //
830   // Check parameters.
831   //
832   if (Buffer == NULL) {
833     return EFI_INVALID_PARAMETER;
834   }
835 
836   if (BufferSize == 0) {
837     if ((Token != NULL) && (Token->Event != NULL)) {
838       Token->TransactionStatus = EFI_SUCCESS;
839       gBS->SignalEvent (Token->Event);
840     }
841     return EFI_SUCCESS;
842   }
843 
844   BlockSize = Media->BlockSize;
845   if ((BufferSize % BlockSize) != 0) {
846     return EFI_BAD_BUFFER_SIZE;
847   }
848 
849   BlockNum  = BufferSize / BlockSize;
850   if ((Lba + BlockNum - 1) > Media->LastBlock) {
851     return EFI_INVALID_PARAMETER;
852   }
853 
854   IoAlign = Media->IoAlign;
855   if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
856     return EFI_INVALID_PARAMETER;
857   }
858 
859   if ((Token != NULL) && (Token->Event != NULL)) {
860     Token->TransactionStatus = EFI_SUCCESS;
861   }
862   //
863   // Check if needs to switch partition access.
864   //
865   PartitionConfig = Device->ExtCsd.PartitionConfig;
866   if ((PartitionConfig & 0x7) != Partition->PartitionType) {
867     PartitionConfig &= (UINT8)~0x7;
868     PartitionConfig |= Partition->PartitionType;
869     Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, Token, FALSE);
870     if (EFI_ERROR (Status)) {
871       return Status;
872     }
873     Device->ExtCsd.PartitionConfig = PartitionConfig;
874   }
875   //
876   // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
877   //
878   Remaining = BlockNum;
879   MaxBlock  = 0xFFFF;
880 
881   while (Remaining > 0) {
882     if (Remaining <= MaxBlock) {
883       BlockNum = Remaining;
884       LastRw   = TRUE;
885     } else {
886       BlockNum = MaxBlock;
887     }
888     Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, Token, FALSE);
889     if (EFI_ERROR (Status)) {
890       return Status;
891     }
892 
893     BufferSize = BlockNum * BlockSize;
894     Status = EmmcRwMultiBlocks (Partition, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
895     if (EFI_ERROR (Status)) {
896       return Status;
897     }
898     DEBUG ((DEBUG_BLKIO,
899       "Emmc%a(): Part %d Lba 0x%x BlkNo 0x%x Event %p with %r\n",
900       IsRead ? "Read " : "Write", Partition->PartitionType, Lba, BlockNum,
901       (Token != NULL) ? Token->Event : NULL, Status));
902 
903     Lba   += BlockNum;
904     Buffer = (UINT8*)Buffer + BufferSize;
905     Remaining -= BlockNum;
906   }
907 
908   return Status;
909 }
910 
911 /**
912   Reset the Block Device.
913 
914   @param  This                 Indicates a pointer to the calling context.
915   @param  ExtendedVerification Driver may perform diagnostics on reset.
916 
917   @retval EFI_SUCCESS          The device was reset.
918   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
919                                not be reset.
920 
921 **/
922 EFI_STATUS
923 EFIAPI
EmmcReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)924 EmmcReset (
925   IN  EFI_BLOCK_IO_PROTOCOL     *This,
926   IN  BOOLEAN                   ExtendedVerification
927   )
928 {
929   EFI_STATUS                    Status;
930   EMMC_PARTITION                *Partition;
931   EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
932 
933   Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
934 
935   PassThru = Partition->Device->Private->PassThru;
936   Status   = PassThru->ResetDevice (PassThru, Partition->Device->Slot);
937   if (EFI_ERROR (Status)) {
938     Status = EFI_DEVICE_ERROR;
939   }
940 
941   return Status;
942 }
943 
944 /**
945   Read BufferSize bytes from Lba into Buffer.
946 
947   @param  This       Indicates a pointer to the calling context.
948   @param  MediaId    Id of the media, changes every time the media is replaced.
949   @param  Lba        The starting Logical Block Address to read from
950   @param  BufferSize Size of Buffer, must be a multiple of device block size.
951   @param  Buffer     A pointer to the destination buffer for the data. The caller is
952                      responsible for either having implicit or explicit ownership of the buffer.
953 
954   @retval EFI_SUCCESS           The data was read correctly from the device.
955   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
956   @retval EFI_NO_MEDIA          There is no media in the device.
957   @retval EFI_MEDIA_CHANGED     The MediaId does not match the current device.
958   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
959   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
960                                 or the buffer is not on proper alignment.
961 
962 **/
963 EFI_STATUS
964 EFIAPI
EmmcReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,OUT VOID * Buffer)965 EmmcReadBlocks (
966   IN     EFI_BLOCK_IO_PROTOCOL  *This,
967   IN     UINT32                 MediaId,
968   IN     EFI_LBA                Lba,
969   IN     UINTN                  BufferSize,
970      OUT VOID                   *Buffer
971   )
972 {
973   EFI_STATUS             Status;
974   EMMC_PARTITION         *Partition;
975 
976   Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
977 
978   Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
979   return Status;
980 }
981 
982 /**
983   Write BufferSize bytes from Lba into Buffer.
984 
985   @param  This       Indicates a pointer to the calling context.
986   @param  MediaId    The media ID that the write request is for.
987   @param  Lba        The starting logical block address to be written. The caller is
988                      responsible for writing to only legitimate locations.
989   @param  BufferSize Size of Buffer, must be a multiple of device block size.
990   @param  Buffer     A pointer to the source buffer for the data.
991 
992   @retval EFI_SUCCESS           The data was written correctly to the device.
993   @retval EFI_WRITE_PROTECTED   The device can not be written to.
994   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
995   @retval EFI_NO_MEDIA          There is no media in the device.
996   @retval EFI_MEDIA_CHANGED     The MediaId does not match the current device.
997   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
998   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
999                                 or the buffer is not on proper alignment.
1000 
1001 **/
1002 EFI_STATUS
1003 EFIAPI
EmmcWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN VOID * Buffer)1004 EmmcWriteBlocks (
1005   IN  EFI_BLOCK_IO_PROTOCOL   *This,
1006   IN  UINT32                  MediaId,
1007   IN  EFI_LBA                 Lba,
1008   IN  UINTN                   BufferSize,
1009   IN  VOID                    *Buffer
1010   )
1011 {
1012   EFI_STATUS             Status;
1013   EMMC_PARTITION         *Partition;
1014 
1015   Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);
1016 
1017   Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
1018   return Status;
1019 }
1020 
1021 /**
1022   Flush the Block Device.
1023 
1024   @param  This              Indicates a pointer to the calling context.
1025 
1026   @retval EFI_SUCCESS       All outstanding data was written to the device
1027   @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data
1028   @retval EFI_NO_MEDIA      There is no media in the device.
1029 
1030 **/
1031 EFI_STATUS
1032 EFIAPI
EmmcFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)1033 EmmcFlushBlocks (
1034   IN  EFI_BLOCK_IO_PROTOCOL   *This
1035   )
1036 {
1037   //
1038   // return directly
1039   //
1040   return EFI_SUCCESS;
1041 }
1042 
1043 /**
1044   Reset the Block Device.
1045 
1046   @param[in]  This                 Indicates a pointer to the calling context.
1047   @param[in]  ExtendedVerification Driver may perform diagnostics on reset.
1048 
1049   @retval EFI_SUCCESS              The device was reset.
1050   @retval EFI_DEVICE_ERROR         The device is not functioning properly and could
1051                                    not be reset.
1052 
1053 **/
1054 EFI_STATUS
1055 EFIAPI
EmmcResetEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN BOOLEAN ExtendedVerification)1056 EmmcResetEx (
1057   IN  EFI_BLOCK_IO2_PROTOCOL  *This,
1058   IN  BOOLEAN                 ExtendedVerification
1059   )
1060 {
1061   EMMC_PARTITION              *Partition;
1062   LIST_ENTRY                  *Link;
1063   LIST_ENTRY                  *NextLink;
1064   EMMC_REQUEST                *Request;
1065   EFI_TPL                     OldTpl;
1066 
1067   Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
1068 
1069   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1070   for (Link = GetFirstNode (&Partition->Queue);
1071        !IsNull (&Partition->Queue, Link);
1072        Link = NextLink) {
1073     NextLink = GetNextNode (&Partition->Queue, Link);
1074     RemoveEntryList (Link);
1075 
1076     Request = EMMC_REQUEST_FROM_LINK (Link);
1077 
1078     gBS->CloseEvent (Request->Event);
1079     Request->Token->TransactionStatus = EFI_ABORTED;
1080 
1081     if (Request->IsEnd) {
1082       gBS->SignalEvent (Request->Token->Event);
1083     }
1084 
1085     FreePool (Request);
1086   }
1087   gBS->RestoreTPL (OldTpl);
1088 
1089   return EFI_SUCCESS;
1090 }
1091 
1092 /**
1093   Read BufferSize bytes from Lba into Buffer.
1094 
1095   @param[in]       This         Indicates a pointer to the calling context.
1096   @param[in]       MediaId      Id of the media, changes every time the media is replaced.
1097   @param[in]       Lba          The starting Logical Block Address to read from.
1098   @param[in, out]  Token        A pointer to the token associated with the transaction.
1099   @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.
1100   @param[out]      Buffer       A pointer to the destination buffer for the data. The caller is
1101                                 responsible for either having implicit or explicit ownership of the buffer.
1102 
1103   @retval EFI_SUCCESS           The read request was queued if Event is not NULL.
1104                                 The data was read correctly from the device if
1105                                 the Event is NULL.
1106   @retval EFI_DEVICE_ERROR      The device reported an error while performing
1107                                 the read.
1108   @retval EFI_NO_MEDIA          There is no media in the device.
1109   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
1110   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the
1111                                 intrinsic block size of the device.
1112   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
1113                                 or the buffer is not on proper alignment.
1114   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
1115                                 of resources.
1116 
1117 **/
1118 EFI_STATUS
1119 EFIAPI
EmmcReadBlocksEx(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)1120 EmmcReadBlocksEx (
1121   IN     EFI_BLOCK_IO2_PROTOCOL *This,
1122   IN     UINT32                 MediaId,
1123   IN     EFI_LBA                Lba,
1124   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
1125   IN     UINTN                  BufferSize,
1126      OUT VOID                   *Buffer
1127   )
1128 {
1129   EFI_STATUS             Status;
1130   EMMC_PARTITION         *Partition;
1131 
1132   Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
1133 
1134   Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
1135   return Status;
1136 }
1137 
1138 /**
1139   Write BufferSize bytes from Lba into Buffer.
1140 
1141   @param[in]       This         Indicates a pointer to the calling context.
1142   @param[in]       MediaId      The media ID that the write request is for.
1143   @param[in]       Lba          The starting logical block address to be written. The
1144                                 caller is responsible for writing to only legitimate
1145                                 locations.
1146   @param[in, out]  Token        A pointer to the token associated with the transaction.
1147   @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.
1148   @param[in]       Buffer       A pointer to the source buffer for the data.
1149 
1150   @retval EFI_SUCCESS           The data was written correctly to the device.
1151   @retval EFI_WRITE_PROTECTED   The device can not be written to.
1152   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
1153   @retval EFI_NO_MEDIA          There is no media in the device.
1154   @retval EFI_MEDIA_CHANGED     The MediaId does not match the current device.
1155   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
1156   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1157                                 or the buffer is not on proper alignment.
1158 
1159 **/
1160 EFI_STATUS
1161 EFIAPI
EmmcWriteBlocksEx(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)1162 EmmcWriteBlocksEx (
1163   IN     EFI_BLOCK_IO2_PROTOCOL *This,
1164   IN     UINT32                 MediaId,
1165   IN     EFI_LBA                Lba,
1166   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
1167   IN     UINTN                  BufferSize,
1168   IN     VOID                   *Buffer
1169   )
1170 {
1171   EFI_STATUS             Status;
1172   EMMC_PARTITION         *Partition;
1173 
1174   Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);
1175 
1176   Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
1177   return Status;
1178 }
1179 
1180 /**
1181   Flush the Block Device.
1182 
1183   @param[in]       This     Indicates a pointer to the calling context.
1184   @param[in, out]  Token    A pointer to the token associated with the transaction.
1185 
1186   @retval EFI_SUCCESS       All outstanding data was written to the device
1187   @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data
1188   @retval EFI_NO_MEDIA      There is no media in the device.
1189 
1190 **/
1191 EFI_STATUS
1192 EFIAPI
EmmcFlushBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN OUT EFI_BLOCK_IO2_TOKEN * Token)1193 EmmcFlushBlocksEx (
1194   IN     EFI_BLOCK_IO2_PROTOCOL  *This,
1195   IN OUT EFI_BLOCK_IO2_TOKEN     *Token
1196   )
1197 {
1198   //
1199   // Signal event and return directly.
1200   //
1201   if (Token != NULL && Token->Event != NULL) {
1202     Token->TransactionStatus = EFI_SUCCESS;
1203     gBS->SignalEvent (Token->Event);
1204   }
1205 
1206   return EFI_SUCCESS;
1207 }
1208 
1209 /**
1210   Send a security protocol command to a device that receives data and/or the result
1211   of one or more commands sent by SendData.
1212 
1213   The ReceiveData function sends a security protocol command to the given MediaId.
1214   The security protocol command sent is defined by SecurityProtocolId and contains
1215   the security protocol specific data SecurityProtocolSpecificData. The function
1216   returns the data from the security protocol command in PayloadBuffer.
1217 
1218   For devices supporting the SCSI command set, the security protocol command is sent
1219   using the SECURITY PROTOCOL IN command defined in SPC-4.
1220 
1221   For devices supporting the ATA command set, the security protocol command is sent
1222   using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
1223   is non-zero.
1224 
1225   If the PayloadBufferSize is zero, the security protocol command is sent using the
1226   Trusted Non-Data command defined in ATA8-ACS.
1227 
1228   If PayloadBufferSize is too small to store the available data from the security
1229   protocol command, the function shall copy PayloadBufferSize bytes into the
1230   PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1231 
1232   If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1233   the function shall return EFI_INVALID_PARAMETER.
1234 
1235   If the given MediaId does not support security protocol commands, the function shall
1236   return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1237   EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1238   the function returns EFI_MEDIA_CHANGED.
1239 
1240   If the security protocol fails to complete within the Timeout period, the function
1241   shall return EFI_TIMEOUT.
1242 
1243   If the security protocol command completes without an error, the function shall
1244   return EFI_SUCCESS. If the security protocol command completes with an error, the
1245   function shall return EFI_DEVICE_ERROR.
1246 
1247   @param[in]  This                         Indicates a pointer to the calling context.
1248   @param[in]  MediaId                      ID of the medium to receive data from.
1249   @param[in]  Timeout                      The timeout, in 100ns units, to use for the execution
1250                                            of the security protocol command. A Timeout value of 0
1251                                            means that this function will wait indefinitely for the
1252                                            security protocol command to execute. If Timeout is greater
1253                                            than zero, then this function will return EFI_TIMEOUT
1254                                            if the time required to execute the receive data command
1255                                            is greater than Timeout.
1256   @param[in]  SecurityProtocolId           The value of the "Security Protocol" parameter of
1257                                            the security protocol command to be sent.
1258   @param[in]  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1259                                            of the security protocol command to be sent.
1260   @param[in]  PayloadBufferSize            Size in bytes of the payload data buffer.
1261   @param[out] PayloadBuffer                A pointer to a destination buffer to store the security
1262                                            protocol command specific payload data for the security
1263                                            protocol command. The caller is responsible for having
1264                                            either implicit or explicit ownership of the buffer.
1265   @param[out] PayloadTransferSize          A pointer to a buffer to store the size in bytes of the
1266                                            data written to the payload data buffer.
1267   @param[in]  IsRead                       Indicates it is a read or write operation.
1268 
1269   @retval EFI_SUCCESS                  The security protocol command completed successfully.
1270   @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to store the available
1271                                        data from the device. The PayloadBuffer contains the truncated data.
1272   @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.
1273   @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.
1274   @retval EFI_NO_MEDIA                 There is no media in the device.
1275   @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.
1276   @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize is NULL and
1277                                        PayloadBufferSize is non-zero.
1278   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security
1279                                        protocol command to execute.
1280 
1281 **/
1282 EFI_STATUS
1283 EFIAPI
EmmcSecurityProtocolInOut(IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Timeout,IN UINT8 SecurityProtocolId,IN UINT16 SecurityProtocolSpecificData,IN UINTN PayloadBufferSize,OUT VOID * PayloadBuffer,OUT UINTN * PayloadTransferSize,IN BOOLEAN IsRead)1284 EmmcSecurityProtocolInOut (
1285   IN     EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
1286   IN     UINT32                                   MediaId,
1287   IN     UINT64                                   Timeout,
1288   IN     UINT8                                    SecurityProtocolId,
1289   IN     UINT16                                   SecurityProtocolSpecificData,
1290   IN     UINTN                                    PayloadBufferSize,
1291      OUT VOID                                     *PayloadBuffer,
1292      OUT UINTN                                    *PayloadTransferSize,
1293   IN     BOOLEAN                                  IsRead
1294   )
1295 {
1296   EFI_STATUS                       Status;
1297   EMMC_PARTITION                   *Partition;
1298   EMMC_DEVICE                      *Device;
1299   EFI_BLOCK_IO_MEDIA               *Media;
1300   UINTN                            BlockSize;
1301   UINTN                            BlockNum;
1302   UINTN                            IoAlign;
1303   UINTN                            Remaining;
1304   UINT32                           MaxBlock;
1305   UINT8                            PartitionConfig;
1306 
1307   Status    = EFI_SUCCESS;
1308   Partition = EMMC_PARTITION_DATA_FROM_SSP (This);
1309   Device    = Partition->Device;
1310   Media     = &Partition->BlockMedia;
1311 
1312   if (PayloadTransferSize != NULL) {
1313     *PayloadTransferSize = 0;
1314   }
1315 
1316   if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
1317     return EFI_INVALID_PARAMETER;
1318   }
1319 
1320   if (MediaId != Media->MediaId) {
1321     return EFI_MEDIA_CHANGED;
1322   }
1323 
1324   if (PayloadBufferSize == 0) {
1325     return EFI_SUCCESS;
1326   }
1327 
1328   BlockSize = Media->BlockSize;
1329   if ((PayloadBufferSize % BlockSize) != 0) {
1330     return EFI_BAD_BUFFER_SIZE;
1331   }
1332 
1333   BlockNum  = PayloadBufferSize / BlockSize;
1334 
1335   IoAlign = Media->IoAlign;
1336   if (IoAlign > 0 && (((UINTN) PayloadBuffer & (IoAlign - 1)) != 0)) {
1337     return EFI_INVALID_PARAMETER;
1338   }
1339 
1340   //
1341   // Security protocol interface is synchronous transfer.
1342   // Waiting for async I/O list to be empty before any operation.
1343   //
1344   while (!IsListEmpty (&Partition->Queue));
1345 
1346   //
1347   // Check if needs to switch partition access.
1348   //
1349   PartitionConfig = Device->ExtCsd.PartitionConfig;
1350   if ((PartitionConfig & 0x7) != Partition->PartitionType) {
1351     PartitionConfig &= (UINT8)~0x7;
1352     PartitionConfig |= Partition->PartitionType;
1353     Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, NULL, FALSE);
1354     if (EFI_ERROR (Status)) {
1355       return Status;
1356     }
1357     Device->ExtCsd.PartitionConfig = PartitionConfig;
1358   }
1359   //
1360   // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
1361   //
1362   Remaining = BlockNum;
1363   MaxBlock  = 0xFFFF;
1364 
1365   while (Remaining > 0) {
1366     if (Remaining <= MaxBlock) {
1367       BlockNum = Remaining;
1368     } else {
1369       BlockNum = MaxBlock;
1370     }
1371 
1372     Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, NULL, FALSE);
1373     if (EFI_ERROR (Status)) {
1374       return Status;
1375     }
1376 
1377     PayloadBufferSize = BlockNum * BlockSize;
1378     Status = EmmcProtocolInOut (Partition, SecurityProtocolId, SecurityProtocolSpecificData, PayloadBufferSize, PayloadBuffer, IsRead, Timeout, NULL, FALSE);
1379     if (EFI_ERROR (Status)) {
1380       return Status;
1381     }
1382 
1383     PayloadBuffer = (UINT8*)PayloadBuffer + PayloadBufferSize;
1384     Remaining    -= BlockNum;
1385     if (PayloadTransferSize != NULL) {
1386       *PayloadTransferSize += PayloadBufferSize;
1387     }
1388   }
1389 
1390   return Status;
1391 }
1392 
1393 /**
1394   Send a security protocol command to a device that receives data and/or the result
1395   of one or more commands sent by SendData.
1396 
1397   The ReceiveData function sends a security protocol command to the given MediaId.
1398   The security protocol command sent is defined by SecurityProtocolId and contains
1399   the security protocol specific data SecurityProtocolSpecificData. The function
1400   returns the data from the security protocol command in PayloadBuffer.
1401 
1402   For devices supporting the SCSI command set, the security protocol command is sent
1403   using the SECURITY PROTOCOL IN command defined in SPC-4.
1404 
1405   For devices supporting the ATA command set, the security protocol command is sent
1406   using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
1407   is non-zero.
1408 
1409   If the PayloadBufferSize is zero, the security protocol command is sent using the
1410   Trusted Non-Data command defined in ATA8-ACS.
1411 
1412   If PayloadBufferSize is too small to store the available data from the security
1413   protocol command, the function shall copy PayloadBufferSize bytes into the
1414   PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1415 
1416   If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1417   the function shall return EFI_INVALID_PARAMETER.
1418 
1419   If the given MediaId does not support security protocol commands, the function shall
1420   return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1421   EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1422   the function returns EFI_MEDIA_CHANGED.
1423 
1424   If the security protocol fails to complete within the Timeout period, the function
1425   shall return EFI_TIMEOUT.
1426 
1427   If the security protocol command completes without an error, the function shall
1428   return EFI_SUCCESS. If the security protocol command completes with an error, the
1429   function shall return EFI_DEVICE_ERROR.
1430 
1431   @param  This                         Indicates a pointer to the calling context.
1432   @param  MediaId                      ID of the medium to receive data from.
1433   @param  Timeout                      The timeout, in 100ns units, to use for the execution
1434                                        of the security protocol command. A Timeout value of 0
1435                                        means that this function will wait indefinitely for the
1436                                        security protocol command to execute. If Timeout is greater
1437                                        than zero, then this function will return EFI_TIMEOUT
1438                                        if the time required to execute the receive data command
1439                                        is greater than Timeout.
1440   @param  SecurityProtocolId           The value of the "Security Protocol" parameter of
1441                                        the security protocol command to be sent.
1442   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1443                                        of the security protocol command to be sent.
1444   @param  PayloadBufferSize            Size in bytes of the payload data buffer.
1445   @param  PayloadBuffer                A pointer to a destination buffer to store the security
1446                                        protocol command specific payload data for the security
1447                                        protocol command. The caller is responsible for having
1448                                        either implicit or explicit ownership of the buffer.
1449   @param  PayloadTransferSize          A pointer to a buffer to store the size in bytes of the
1450                                        data written to the payload data buffer.
1451 
1452   @retval EFI_SUCCESS                  The security protocol command completed successfully.
1453   @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to store the available
1454                                        data from the device. The PayloadBuffer contains the truncated data.
1455   @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.
1456   @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.
1457   @retval EFI_NO_MEDIA                 There is no media in the device.
1458   @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.
1459   @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize is NULL and
1460                                        PayloadBufferSize is non-zero.
1461   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security
1462                                        protocol command to execute.
1463 
1464 **/
1465 EFI_STATUS
1466 EFIAPI
EmmcSecurityProtocolIn(IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Timeout,IN UINT8 SecurityProtocolId,IN UINT16 SecurityProtocolSpecificData,IN UINTN PayloadBufferSize,OUT VOID * PayloadBuffer,OUT UINTN * PayloadTransferSize)1467 EmmcSecurityProtocolIn (
1468   IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
1469   IN UINT32                                   MediaId,
1470   IN UINT64                                   Timeout,
1471   IN UINT8                                    SecurityProtocolId,
1472   IN UINT16                                   SecurityProtocolSpecificData,
1473   IN UINTN                                    PayloadBufferSize,
1474   OUT VOID                                    *PayloadBuffer,
1475   OUT UINTN                                   *PayloadTransferSize
1476   )
1477 {
1478   EFI_STATUS                  Status;
1479 
1480   if ((PayloadTransferSize == NULL) && PayloadBufferSize != 0) {
1481     return EFI_INVALID_PARAMETER;
1482   }
1483 
1484   Status = EmmcSecurityProtocolInOut (
1485              This,
1486              MediaId,
1487              Timeout,
1488              SecurityProtocolId,
1489              SecurityProtocolSpecificData,
1490              PayloadBufferSize,
1491              PayloadBuffer,
1492              PayloadTransferSize,
1493              TRUE
1494              );
1495 
1496   return Status;
1497 }
1498 
1499 /**
1500   Send a security protocol command to a device.
1501 
1502   The SendData function sends a security protocol command containing the payload
1503   PayloadBuffer to the given MediaId. The security protocol command sent is
1504   defined by SecurityProtocolId and contains the security protocol specific data
1505   SecurityProtocolSpecificData. If the underlying protocol command requires a
1506   specific padding for the command payload, the SendData function shall add padding
1507   bytes to the command payload to satisfy the padding requirements.
1508 
1509   For devices supporting the SCSI command set, the security protocol command is sent
1510   using the SECURITY PROTOCOL OUT command defined in SPC-4.
1511 
1512   For devices supporting the ATA command set, the security protocol command is sent
1513   using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
1514   is non-zero. If the PayloadBufferSize is zero, the security protocol command is
1515   sent using the Trusted Non-Data command defined in ATA8-ACS.
1516 
1517   If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
1518   return EFI_INVALID_PARAMETER.
1519 
1520   If the given MediaId does not support security protocol commands, the function
1521   shall return EFI_UNSUPPORTED. If there is no media in the device, the function
1522   returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
1523   device, the function returns EFI_MEDIA_CHANGED.
1524 
1525   If the security protocol fails to complete within the Timeout period, the function
1526   shall return EFI_TIMEOUT.
1527 
1528   If the security protocol command completes without an error, the function shall return
1529   EFI_SUCCESS. If the security protocol command completes with an error, the function
1530   shall return EFI_DEVICE_ERROR.
1531 
1532   @param  This                         Indicates a pointer to the calling context.
1533   @param  MediaId                      ID of the medium to receive data from.
1534   @param  Timeout                      The timeout, in 100ns units, to use for the execution
1535                                        of the security protocol command. A Timeout value of 0
1536                                        means that this function will wait indefinitely for the
1537                                        security protocol command to execute. If Timeout is greater
1538                                        than zero, then this function will return EFI_TIMEOUT
1539                                        if the time required to execute the receive data command
1540                                        is greater than Timeout.
1541   @param  SecurityProtocolId           The value of the "Security Protocol" parameter of
1542                                        the security protocol command to be sent.
1543   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1544                                        of the security protocol command to be sent.
1545   @param  PayloadBufferSize            Size in bytes of the payload data buffer.
1546   @param  PayloadBuffer                A pointer to a destination buffer to store the security
1547                                        protocol command specific payload data for the security
1548                                        protocol command.
1549 
1550   @retval EFI_SUCCESS                  The security protocol command completed successfully.
1551   @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.
1552   @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.
1553   @retval EFI_NO_MEDIA                 There is no media in the device.
1554   @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.
1555   @retval EFI_INVALID_PARAMETER        The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
1556   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security
1557                                        protocol command to execute.
1558 
1559 **/
1560 EFI_STATUS
1561 EFIAPI
EmmcSecurityProtocolOut(IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Timeout,IN UINT8 SecurityProtocolId,IN UINT16 SecurityProtocolSpecificData,IN UINTN PayloadBufferSize,IN VOID * PayloadBuffer)1562 EmmcSecurityProtocolOut (
1563   IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
1564   IN UINT32                                   MediaId,
1565   IN UINT64                                   Timeout,
1566   IN UINT8                                    SecurityProtocolId,
1567   IN UINT16                                   SecurityProtocolSpecificData,
1568   IN UINTN                                    PayloadBufferSize,
1569   IN VOID                                     *PayloadBuffer
1570   )
1571 {
1572   EFI_STATUS          Status;
1573 
1574   Status = EmmcSecurityProtocolInOut (
1575              This,
1576              MediaId,
1577              Timeout,
1578              SecurityProtocolId,
1579              SecurityProtocolSpecificData,
1580              PayloadBufferSize,
1581              PayloadBuffer,
1582              NULL,
1583              FALSE
1584              );
1585 
1586   return Status;
1587 }
1588 
1589 /**
1590   Set the erase start address through sync or async I/O request.
1591 
1592   @param[in]  Partition         A pointer to the EMMC_PARTITION instance.
1593   @param[in]  StartLba          The starting logical block address to be erased.
1594   @param[in]  Token             A pointer to the token associated with the transaction.
1595   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
1596                                 This parameter is only meaningful in async I/O request.
1597 
1598   @retval EFI_SUCCESS           The request is executed successfully.
1599   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
1600   @retval Others                The request could not be executed successfully.
1601 
1602 **/
1603 EFI_STATUS
EmmcEraseBlockStart(IN EMMC_PARTITION * Partition,IN EFI_LBA StartLba,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)1604 EmmcEraseBlockStart (
1605   IN  EMMC_PARTITION            *Partition,
1606   IN  EFI_LBA                   StartLba,
1607   IN  EFI_BLOCK_IO2_TOKEN       *Token,
1608   IN  BOOLEAN                   IsEnd
1609   )
1610 {
1611   EFI_STATUS                           Status;
1612   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
1613   EMMC_DEVICE                          *Device;
1614   EMMC_REQUEST                         *EraseBlockStart;
1615   EFI_TPL                              OldTpl;
1616 
1617   EraseBlockStart = NULL;
1618 
1619   Device   = Partition->Device;
1620   PassThru = Device->Private->PassThru;
1621 
1622   EraseBlockStart = AllocateZeroPool (sizeof (EMMC_REQUEST));
1623   if (EraseBlockStart == NULL) {
1624     Status = EFI_OUT_OF_RESOURCES;
1625     goto Error;
1626   }
1627 
1628   EraseBlockStart->Signature = EMMC_REQUEST_SIGNATURE;
1629   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1630   InsertTailList (&Partition->Queue, &EraseBlockStart->Link);
1631   gBS->RestoreTPL (OldTpl);
1632   EraseBlockStart->Packet.SdMmcCmdBlk    = &EraseBlockStart->SdMmcCmdBlk;
1633   EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
1634   EraseBlockStart->Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
1635 
1636   EraseBlockStart->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_START;
1637   EraseBlockStart->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
1638   EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1639 
1640   if (Device->SectorAddressing) {
1641     EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
1642   } else {
1643     EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Partition->BlockMedia.BlockSize);
1644   }
1645 
1646   EraseBlockStart->IsEnd = IsEnd;
1647   EraseBlockStart->Token = Token;
1648 
1649   if ((Token != NULL) && (Token->Event != NULL)) {
1650     Status = gBS->CreateEvent (
1651                     EVT_NOTIFY_SIGNAL,
1652                     TPL_NOTIFY,
1653                     AsyncIoCallback,
1654                     EraseBlockStart,
1655                     &EraseBlockStart->Event
1656                     );
1657     if (EFI_ERROR (Status)) {
1658       goto Error;
1659     }
1660   } else {
1661     EraseBlockStart->Event = NULL;
1662   }
1663 
1664   Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
1665 
1666 Error:
1667   if ((Token != NULL) && (Token->Event != NULL)) {
1668     //
1669     // For asynchronous operation, only free request and event in error case.
1670     // The request and event will be freed in asynchronous callback for success case.
1671     //
1672     if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
1673       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1674       RemoveEntryList (&EraseBlockStart->Link);
1675       gBS->RestoreTPL (OldTpl);
1676       if (EraseBlockStart->Event != NULL) {
1677         gBS->CloseEvent (EraseBlockStart->Event);
1678       }
1679       FreePool (EraseBlockStart);
1680     }
1681   } else {
1682     //
1683     // For synchronous operation, free request whatever the execution result is.
1684     //
1685     if (EraseBlockStart != NULL) {
1686       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1687       RemoveEntryList (&EraseBlockStart->Link);
1688       gBS->RestoreTPL (OldTpl);
1689       FreePool (EraseBlockStart);
1690     }
1691   }
1692 
1693   return Status;
1694 }
1695 
1696 /**
1697   Set the erase end address through sync or async I/O request.
1698 
1699   @param[in]  Partition         A pointer to the EMMC_PARTITION instance.
1700   @param[in]  EndLba            The ending logical block address to be erased.
1701   @param[in]  Token             A pointer to the token associated with the transaction.
1702   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
1703                                 This parameter is only meaningful in async I/O request.
1704 
1705   @retval EFI_SUCCESS           The request is executed successfully.
1706   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
1707   @retval Others                The request could not be executed successfully.
1708 
1709 **/
1710 EFI_STATUS
EmmcEraseBlockEnd(IN EMMC_PARTITION * Partition,IN EFI_LBA EndLba,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)1711 EmmcEraseBlockEnd (
1712   IN  EMMC_PARTITION            *Partition,
1713   IN  EFI_LBA                   EndLba,
1714   IN  EFI_BLOCK_IO2_TOKEN       *Token,
1715   IN  BOOLEAN                   IsEnd
1716   )
1717 {
1718   EFI_STATUS                           Status;
1719   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
1720   EMMC_DEVICE                          *Device;
1721   EMMC_REQUEST                         *EraseBlockEnd;
1722   EFI_TPL                              OldTpl;
1723 
1724   EraseBlockEnd = NULL;
1725 
1726   Device   = Partition->Device;
1727   PassThru = Device->Private->PassThru;
1728 
1729   EraseBlockEnd = AllocateZeroPool (sizeof (EMMC_REQUEST));
1730   if (EraseBlockEnd == NULL) {
1731     Status = EFI_OUT_OF_RESOURCES;
1732     goto Error;
1733   }
1734 
1735   EraseBlockEnd->Signature = EMMC_REQUEST_SIGNATURE;
1736   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1737   InsertTailList (&Partition->Queue, &EraseBlockEnd->Link);
1738   gBS->RestoreTPL (OldTpl);
1739   EraseBlockEnd->Packet.SdMmcCmdBlk    = &EraseBlockEnd->SdMmcCmdBlk;
1740   EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
1741   EraseBlockEnd->Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
1742 
1743   EraseBlockEnd->SdMmcCmdBlk.CommandIndex = EMMC_ERASE_GROUP_END;
1744   EraseBlockEnd->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
1745   EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1746 
1747   if (Device->SectorAddressing) {
1748     EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
1749   } else {
1750     EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Partition->BlockMedia.BlockSize);
1751   }
1752 
1753   EraseBlockEnd->IsEnd = IsEnd;
1754   EraseBlockEnd->Token = Token;
1755 
1756   if ((Token != NULL) && (Token->Event != NULL)) {
1757     Status = gBS->CreateEvent (
1758                     EVT_NOTIFY_SIGNAL,
1759                     TPL_NOTIFY,
1760                     AsyncIoCallback,
1761                     EraseBlockEnd,
1762                     &EraseBlockEnd->Event
1763                     );
1764     if (EFI_ERROR (Status)) {
1765       goto Error;
1766     }
1767   } else {
1768     EraseBlockEnd->Event = NULL;
1769   }
1770 
1771   Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
1772 
1773 Error:
1774   if ((Token != NULL) && (Token->Event != NULL)) {
1775     //
1776     // For asynchronous operation, only free request and event in error case.
1777     // The request and event will be freed in asynchronous callback for success case.
1778     //
1779     if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
1780       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1781       RemoveEntryList (&EraseBlockEnd->Link);
1782       gBS->RestoreTPL (OldTpl);
1783       if (EraseBlockEnd->Event != NULL) {
1784         gBS->CloseEvent (EraseBlockEnd->Event);
1785       }
1786       FreePool (EraseBlockEnd);
1787     }
1788   } else {
1789     //
1790     // For synchronous operation, free request whatever the execution result is.
1791     //
1792     if (EraseBlockEnd != NULL) {
1793       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1794       RemoveEntryList (&EraseBlockEnd->Link);
1795       gBS->RestoreTPL (OldTpl);
1796       FreePool (EraseBlockEnd);
1797     }
1798   }
1799 
1800   return Status;
1801 }
1802 
1803 /**
1804   Erase specified blocks through sync or async I/O request.
1805 
1806   @param[in]  Partition         A pointer to the EMMC_PARTITION instance.
1807   @param[in]  Token             A pointer to the token associated with the transaction.
1808   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
1809                                 This parameter is only meaningful in async I/O request.
1810 
1811   @retval EFI_SUCCESS           The request is executed successfully.
1812   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
1813   @retval Others                The request could not be executed successfully.
1814 
1815 **/
1816 EFI_STATUS
EmmcEraseBlock(IN EMMC_PARTITION * Partition,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)1817 EmmcEraseBlock (
1818   IN  EMMC_PARTITION            *Partition,
1819   IN  EFI_BLOCK_IO2_TOKEN       *Token,
1820   IN  BOOLEAN                   IsEnd
1821   )
1822 {
1823   EFI_STATUS                           Status;
1824   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
1825   EMMC_DEVICE                          *Device;
1826   EMMC_REQUEST                         *EraseBlock;
1827   EFI_TPL                              OldTpl;
1828 
1829   EraseBlock = NULL;
1830 
1831   Device   = Partition->Device;
1832   PassThru = Device->Private->PassThru;
1833 
1834   EraseBlock = AllocateZeroPool (sizeof (EMMC_REQUEST));
1835   if (EraseBlock == NULL) {
1836     Status = EFI_OUT_OF_RESOURCES;
1837     goto Error;
1838   }
1839 
1840   EraseBlock->Signature = EMMC_REQUEST_SIGNATURE;
1841   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1842   InsertTailList (&Partition->Queue, &EraseBlock->Link);
1843   gBS->RestoreTPL (OldTpl);
1844   EraseBlock->Packet.SdMmcCmdBlk    = &EraseBlock->SdMmcCmdBlk;
1845   EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
1846   EraseBlock->Packet.Timeout        = EMMC_GENERIC_TIMEOUT;
1847 
1848   EraseBlock->SdMmcCmdBlk.CommandIndex = EMMC_ERASE;
1849   EraseBlock->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
1850   EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
1851   if ((Device->ExtCsd.SecFeatureSupport & BIT4) != 0) {
1852     //
1853     // Perform a Trim operation which applies the erase operation to write blocks
1854     // instead of erase groups. (Spec JESD84-B51, eMMC Electrical Standard 5.1,
1855     // Section 6.6.10 and 6.10.4)
1856     //
1857     EraseBlock->SdMmcCmdBlk.CommandArgument = 1;
1858   }
1859 
1860   EraseBlock->IsEnd = IsEnd;
1861   EraseBlock->Token = Token;
1862 
1863   if ((Token != NULL) && (Token->Event != NULL)) {
1864     Status = gBS->CreateEvent (
1865                     EVT_NOTIFY_SIGNAL,
1866                     TPL_NOTIFY,
1867                     AsyncIoCallback,
1868                     EraseBlock,
1869                     &EraseBlock->Event
1870                     );
1871     if (EFI_ERROR (Status)) {
1872       goto Error;
1873     }
1874   } else {
1875     EraseBlock->Event = NULL;
1876   }
1877 
1878   Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
1879 
1880 Error:
1881   if ((Token != NULL) && (Token->Event != NULL)) {
1882     //
1883     // For asynchronous operation, only free request and event in error case.
1884     // The request and event will be freed in asynchronous callback for success case.
1885     //
1886     if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
1887       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1888       RemoveEntryList (&EraseBlock->Link);
1889       gBS->RestoreTPL (OldTpl);
1890       if (EraseBlock->Event != NULL) {
1891         gBS->CloseEvent (EraseBlock->Event);
1892       }
1893       FreePool (EraseBlock);
1894     }
1895   } else {
1896     //
1897     // For synchronous operation, free request whatever the execution result is.
1898     //
1899     if (EraseBlock != NULL) {
1900       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1901       RemoveEntryList (&EraseBlock->Link);
1902       gBS->RestoreTPL (OldTpl);
1903       FreePool (EraseBlock);
1904     }
1905   }
1906 
1907   return Status;
1908 }
1909 
1910 /**
1911   Write zeros to specified blocks.
1912 
1913   @param[in]  Partition         A pointer to the EMMC_PARTITION instance.
1914   @param[in]  StartLba          The starting logical block address to write zeros.
1915   @param[in]  Size              The size in bytes to fill with zeros. This must be a multiple of
1916                                 the physical block size of the device.
1917 
1918   @retval EFI_SUCCESS           The request is executed successfully.
1919   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
1920   @retval Others                The request could not be executed successfully.
1921 
1922 **/
1923 EFI_STATUS
EmmcWriteZeros(IN EMMC_PARTITION * Partition,IN EFI_LBA StartLba,IN UINTN Size)1924 EmmcWriteZeros (
1925   IN  EMMC_PARTITION            *Partition,
1926   IN  EFI_LBA                   StartLba,
1927   IN  UINTN                     Size
1928   )
1929 {
1930   EFI_STATUS                           Status;
1931   UINT8                                *Buffer;
1932   UINT32                               MediaId;
1933 
1934   Buffer = AllocateZeroPool (Size);
1935   if (Buffer == NULL) {
1936     return EFI_OUT_OF_RESOURCES;
1937   }
1938 
1939   MediaId = Partition->BlockMedia.MediaId;
1940 
1941   Status = EmmcReadWrite (Partition, MediaId, StartLba, Buffer, Size, FALSE, NULL);
1942   FreePool (Buffer);
1943 
1944   return Status;
1945 }
1946 
1947 /**
1948   Erase a specified number of device blocks.
1949 
1950   @param[in]       This           Indicates a pointer to the calling context.
1951   @param[in]       MediaId        The media ID that the erase request is for.
1952   @param[in]       Lba            The starting logical block address to be
1953                                   erased. The caller is responsible for erasing
1954                                   only legitimate locations.
1955   @param[in, out]  Token          A pointer to the token associated with the
1956                                   transaction.
1957   @param[in]       Size           The size in bytes to be erased. This must be
1958                                   a multiple of the physical block size of the
1959                                   device.
1960 
1961   @retval EFI_SUCCESS             The erase request was queued if Event is not
1962                                   NULL. The data was erased correctly to the
1963                                   device if the Event is NULL.to the device.
1964   @retval EFI_WRITE_PROTECTED     The device cannot be erased due to write
1965                                   protection.
1966   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
1967                                   to perform the erase operation.
1968   @retval EFI_INVALID_PARAMETER   The erase request contains LBAs that are not
1969                                   valid.
1970   @retval EFI_NO_MEDIA            There is no media in the device.
1971   @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
1972 
1973 **/
1974 EFI_STATUS
1975 EFIAPI
EmmcEraseBlocks(IN EFI_ERASE_BLOCK_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT EFI_ERASE_BLOCK_TOKEN * Token,IN UINTN Size)1976 EmmcEraseBlocks (
1977   IN     EFI_ERASE_BLOCK_PROTOCOL      *This,
1978   IN     UINT32                        MediaId,
1979   IN     EFI_LBA                       Lba,
1980   IN OUT EFI_ERASE_BLOCK_TOKEN         *Token,
1981   IN     UINTN                         Size
1982   )
1983 {
1984   EFI_STATUS                            Status;
1985   EFI_BLOCK_IO_MEDIA                    *Media;
1986   UINTN                                 BlockSize;
1987   UINTN                                 BlockNum;
1988   EFI_LBA                               FirstLba;
1989   EFI_LBA                               LastLba;
1990   EFI_LBA                               StartGroupLba;
1991   EFI_LBA                               EndGroupLba;
1992   UINT32                                EraseGroupSize;
1993   UINT32                                Remainder;
1994   UINTN                                 WriteZeroSize;
1995   UINT8                                 PartitionConfig;
1996   EMMC_PARTITION                        *Partition;
1997   EMMC_DEVICE                           *Device;
1998 
1999   Status    = EFI_SUCCESS;
2000   Partition = EMMC_PARTITION_DATA_FROM_ERASEBLK (This);
2001   Device    = Partition->Device;
2002   Media     = &Partition->BlockMedia;
2003 
2004   if (MediaId != Media->MediaId) {
2005     return EFI_MEDIA_CHANGED;
2006   }
2007 
2008   if (Media->ReadOnly) {
2009     return EFI_WRITE_PROTECTED;
2010   }
2011 
2012   //
2013   // Check parameters.
2014   //
2015   BlockSize = Media->BlockSize;
2016   if ((Size % BlockSize) != 0) {
2017     return EFI_INVALID_PARAMETER;
2018   }
2019 
2020   BlockNum  = Size / BlockSize;
2021   if ((Lba + BlockNum - 1) > Media->LastBlock) {
2022     return EFI_INVALID_PARAMETER;
2023   }
2024 
2025   if ((Token != NULL) && (Token->Event != NULL)) {
2026     Token->TransactionStatus = EFI_SUCCESS;
2027   }
2028 
2029   FirstLba = Lba;
2030   LastLba  = Lba + BlockNum - 1;
2031 
2032   //
2033   // Check if needs to switch partition access.
2034   //
2035   PartitionConfig = Device->ExtCsd.PartitionConfig;
2036   if ((PartitionConfig & 0x7) != Partition->PartitionType) {
2037     PartitionConfig &= (UINT8)~0x7;
2038     PartitionConfig |= Partition->PartitionType;
2039     Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
2040     if (EFI_ERROR (Status)) {
2041       return Status;
2042     }
2043     Device->ExtCsd.PartitionConfig = PartitionConfig;
2044   }
2045 
2046   if ((Device->ExtCsd.SecFeatureSupport & BIT4) == 0) {
2047     //
2048     // If the Trim operation is not supported by the device, handle the erase
2049     // of blocks that do not form a complete erase group separately.
2050     //
2051     EraseGroupSize = This->EraseLengthGranularity;
2052 
2053     DivU64x32Remainder (FirstLba, EraseGroupSize, &Remainder);
2054     StartGroupLba = (Remainder == 0) ? FirstLba : (FirstLba + EraseGroupSize - Remainder);
2055 
2056     DivU64x32Remainder (LastLba + 1, EraseGroupSize, &Remainder);
2057     EndGroupLba = LastLba + 1 - Remainder;
2058 
2059     //
2060     // If the size to erase is smaller than the erase group size, the whole
2061     // erase operation is performed by writing zeros.
2062     //
2063     if (BlockNum < EraseGroupSize) {
2064       Status = EmmcWriteZeros (Partition, FirstLba, Size);
2065       if (EFI_ERROR (Status)) {
2066         return Status;
2067       }
2068 
2069       DEBUG ((
2070         DEBUG_INFO,
2071         "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
2072         Lba,
2073         BlockNum,
2074         (Token != NULL) ? Token->Event : NULL,
2075         Status
2076         ));
2077 
2078       if ((Token != NULL) && (Token->Event != NULL)) {
2079         Token->TransactionStatus = EFI_SUCCESS;
2080         gBS->SignalEvent (Token->Event);
2081       }
2082       return EFI_SUCCESS;
2083     }
2084 
2085     //
2086     // If the starting LBA to erase is not aligned with the start of an erase
2087     // group, write zeros to erase the data from starting LBA to the end of the
2088     // current erase group.
2089     //
2090     if (StartGroupLba > FirstLba) {
2091       WriteZeroSize = (UINTN)(StartGroupLba - FirstLba) * BlockSize;
2092       Status = EmmcWriteZeros (Partition, FirstLba, WriteZeroSize);
2093       if (EFI_ERROR (Status)) {
2094         return Status;
2095       }
2096     }
2097 
2098     //
2099     // If the ending LBA to erase is not aligned with the end of an erase
2100     // group, write zeros to erase the data from the start of the erase group
2101     // to the ending LBA.
2102     //
2103     if (EndGroupLba <= LastLba) {
2104       WriteZeroSize = (UINTN)(LastLba + 1 - EndGroupLba) * BlockSize;
2105       Status = EmmcWriteZeros (Partition, EndGroupLba, WriteZeroSize);
2106       if (EFI_ERROR (Status)) {
2107         return Status;
2108       }
2109     }
2110 
2111     //
2112     // Check whether there is erase group to erase.
2113     //
2114     if (EndGroupLba <= StartGroupLba) {
2115       DEBUG ((
2116         DEBUG_INFO,
2117         "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
2118         Lba,
2119         BlockNum,
2120         (Token != NULL) ? Token->Event : NULL,
2121         Status
2122         ));
2123 
2124       if ((Token != NULL) && (Token->Event != NULL)) {
2125         Token->TransactionStatus = EFI_SUCCESS;
2126         gBS->SignalEvent (Token->Event);
2127       }
2128       return EFI_SUCCESS;
2129     }
2130 
2131     FirstLba = StartGroupLba;
2132     LastLba  = EndGroupLba - 1;
2133   }
2134 
2135   Status = EmmcEraseBlockStart (Partition, FirstLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
2136   if (EFI_ERROR (Status)) {
2137     return Status;
2138   }
2139 
2140   Status = EmmcEraseBlockEnd (Partition, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
2141   if (EFI_ERROR (Status)) {
2142     return Status;
2143   }
2144 
2145   Status = EmmcEraseBlock (Partition, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
2146   if (EFI_ERROR (Status)) {
2147     return Status;
2148   }
2149 
2150   DEBUG ((
2151     DEBUG_INFO,
2152     "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
2153     Lba,
2154     BlockNum,
2155     (Token != NULL) ? Token->Event : NULL,
2156     Status
2157     ));
2158 
2159   return Status;
2160 }
2161 
2162