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