1 /** @file
2   The helper functions for BlockIo and BlockIo2 protocol.
3 
4   Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "SdDxe.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   SD_REQUEST                  *Request;
27 
28   gBS->CloseEvent (Event);
29 
30   Request = (SD_REQUEST *) Context;
31 
32   DEBUG_CODE_BEGIN ();
33     DEBUG ((EFI_D_INFO, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n",
34             Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,
35             Request->Packet.TransactionStatus));
36   DEBUG_CODE_END ();
37 
38   if (EFI_ERROR (Request->Packet.TransactionStatus)) {
39     Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
40   }
41 
42   RemoveEntryList (&Request->Link);
43 
44   if (Request->IsEnd) {
45     gBS->SignalEvent (Request->Token->Event);
46   }
47 
48   FreePool (Request);
49 }
50 
51 /**
52   Send command SET_RELATIVE_ADDRESS to the device to set the device address.
53 
54   @param[in]  Device            A pointer to the SD_DEVICE instance.
55   @param[out] Rca               The relative device address to assign.
56 
57   @retval EFI_SUCCESS           The request is executed successfully.
58   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
59   @retval Others                The request could not be executed successfully.
60 
61 **/
62 EFI_STATUS
SdSetRca(IN SD_DEVICE * Device,OUT UINT16 * Rca)63 SdSetRca (
64   IN     SD_DEVICE              *Device,
65      OUT UINT16                 *Rca
66   )
67 {
68   EFI_STATUS                           Status;
69   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
70   EFI_SD_MMC_COMMAND_BLOCK             SdMmcCmdBlk;
71   EFI_SD_MMC_STATUS_BLOCK              SdMmcStatusBlk;
72   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET  Packet;
73 
74   PassThru = Device->Private->PassThru;
75 
76   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
77   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
78   ZeroMem (&Packet, sizeof (Packet));
79   Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
80   Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
81   Packet.Timeout        = SD_GENERIC_TIMEOUT;
82 
83   SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
84   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;
85   SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
86 
87   Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
88   if (!EFI_ERROR (Status)) {
89     DEBUG ((EFI_D_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0));
90     *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
91   }
92 
93   return Status;
94 }
95 
96 /**
97   Send command SELECT to the device to select/deselect the device.
98 
99   @param[in]  Device            A pointer to the SD_DEVICE instance.
100   @param[in]  Rca               The relative device address to use.
101 
102   @retval EFI_SUCCESS           The request is executed successfully.
103   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
104   @retval Others                The request could not be executed successfully.
105 
106 **/
107 EFI_STATUS
SdSelect(IN SD_DEVICE * Device,IN UINT16 Rca)108 SdSelect (
109   IN     SD_DEVICE              *Device,
110   IN     UINT16                 Rca
111   )
112 {
113   EFI_STATUS                           Status;
114   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
115   EFI_SD_MMC_COMMAND_BLOCK             SdMmcCmdBlk;
116   EFI_SD_MMC_STATUS_BLOCK              SdMmcStatusBlk;
117   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET  Packet;
118 
119   PassThru = Device->Private->PassThru;
120 
121   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
122   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
123   ZeroMem (&Packet, sizeof (Packet));
124   Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
125   Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
126   Packet.Timeout        = SD_GENERIC_TIMEOUT;
127 
128   SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
129   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
130   if (Rca != 0) {
131     SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
132   }
133   SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
134 
135   Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
136 
137   return Status;
138 }
139 
140 /**
141   Send command SEND_STATUS to the device to get device status.
142 
143   @param[in]  Device            A pointer to the SD_DEVICE instance.
144   @param[in]  Rca               The relative device address to use.
145   @param[out] DevStatus         The buffer to store the device status.
146 
147   @retval EFI_SUCCESS           The request is executed successfully.
148   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
149   @retval Others                The request could not be executed successfully.
150 
151 **/
152 EFI_STATUS
SdSendStatus(IN SD_DEVICE * Device,IN UINT16 Rca,OUT UINT32 * DevStatus)153 SdSendStatus (
154   IN     SD_DEVICE              *Device,
155   IN     UINT16                 Rca,
156      OUT UINT32                 *DevStatus
157   )
158 {
159   EFI_STATUS                           Status;
160   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
161   EFI_SD_MMC_COMMAND_BLOCK             SdMmcCmdBlk;
162   EFI_SD_MMC_STATUS_BLOCK              SdMmcStatusBlk;
163   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET  Packet;
164 
165   PassThru = Device->Private->PassThru;
166 
167   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
168   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
169   ZeroMem (&Packet, sizeof (Packet));
170   Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
171   Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
172   Packet.Timeout        = SD_GENERIC_TIMEOUT;
173 
174   SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
175   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
176   SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
177   SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
178 
179   Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
180   if (!EFI_ERROR (Status)) {
181     CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));
182   }
183   return Status;
184 }
185 
186 /**
187   Send command SEND_CSD to the device to get the CSD register data.
188 
189   @param[in]  Device            A pointer to the SD_DEVICE instance.
190   @param[in]  Rca               The relative device address to use.
191   @param[out] Csd               The buffer to store the SD_CSD register data.
192 
193   @retval EFI_SUCCESS           The request is executed successfully.
194   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
195   @retval Others                The request could not be executed successfully.
196 
197 **/
198 EFI_STATUS
SdGetCsd(IN SD_DEVICE * Device,IN UINT16 Rca,OUT SD_CSD * Csd)199 SdGetCsd (
200   IN     SD_DEVICE              *Device,
201   IN     UINT16                 Rca,
202      OUT SD_CSD                 *Csd
203   )
204 {
205   EFI_STATUS                           Status;
206   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
207   EFI_SD_MMC_COMMAND_BLOCK             SdMmcCmdBlk;
208   EFI_SD_MMC_STATUS_BLOCK              SdMmcStatusBlk;
209   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET  Packet;
210 
211   PassThru = Device->Private->PassThru;
212 
213   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
214   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
215   ZeroMem (&Packet, sizeof (Packet));
216   ZeroMem (Csd, sizeof (SD_CSD));
217 
218   Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
219   Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
220   Packet.Timeout        = SD_GENERIC_TIMEOUT;
221 
222   SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;
223   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
224   SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
225   SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
226 
227   Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
228 
229   if (!EFI_ERROR (Status)) {
230     //
231     // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
232     //
233     CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);
234   }
235 
236   return Status;
237 }
238 
239 /**
240   Send command SEND_CID to the device to get the CID register data.
241 
242   @param[in]  Device            A pointer to the SD_DEVICE instance.
243   @param[in]  Rca               The relative device address to use.
244   @param[out] Cid               The buffer to store the SD_CID register data.
245 
246   @retval EFI_SUCCESS           The request is executed successfully.
247   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
248   @retval Others                The request could not be executed successfully.
249 
250 **/
251 EFI_STATUS
SdGetCid(IN SD_DEVICE * Device,IN UINT16 Rca,OUT SD_CID * Cid)252 SdGetCid (
253   IN     SD_DEVICE              *Device,
254   IN     UINT16                 Rca,
255      OUT SD_CID                 *Cid
256   )
257 {
258   EFI_STATUS                           Status;
259   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
260   EFI_SD_MMC_COMMAND_BLOCK             SdMmcCmdBlk;
261   EFI_SD_MMC_STATUS_BLOCK              SdMmcStatusBlk;
262   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET  Packet;
263 
264   PassThru = Device->Private->PassThru;
265 
266   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
267   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
268   ZeroMem (&Packet, sizeof (Packet));
269   ZeroMem (Cid, sizeof (SD_CID));
270 
271   Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
272   Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
273   Packet.Timeout        = SD_GENERIC_TIMEOUT;
274 
275   SdMmcCmdBlk.CommandIndex = SD_SEND_CID;
276   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
277   SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
278   SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
279 
280   Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
281 
282   if (!EFI_ERROR (Status)) {
283     //
284     // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
285     //
286     CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CID) - 1);
287   }
288 
289   return Status;
290 }
291 
292 /**
293   Read/write single block through sync or async I/O request.
294 
295   @param[in]  Device            A pointer to the SD_DEVICE instance.
296   @param[in]  Lba               The starting logical block address to be read/written.
297                                 The caller is responsible for reading/writing to only
298                                 legitimate locations.
299   @param[in]  Buffer            A pointer to the destination/source buffer for the data.
300   @param[in]  BufferSize        Size of Buffer, must be a multiple of device block size.
301   @param[in]  IsRead            Indicates it is a read or write operation.
302   @param[in]  Token             A pointer to the token associated with the transaction.
303   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
304                                 This parameter is only meaningful in async I/O request.
305 
306   @retval EFI_SUCCESS           The request is executed successfully.
307   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
308   @retval Others                The request could not be executed successfully.
309 
310 **/
311 EFI_STATUS
SdRwSingleBlock(IN SD_DEVICE * Device,IN EFI_LBA Lba,IN VOID * Buffer,IN UINTN BufferSize,IN BOOLEAN IsRead,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)312 SdRwSingleBlock (
313   IN  SD_DEVICE                 *Device,
314   IN  EFI_LBA                   Lba,
315   IN  VOID                      *Buffer,
316   IN  UINTN                     BufferSize,
317   IN  BOOLEAN                   IsRead,
318   IN  EFI_BLOCK_IO2_TOKEN       *Token,
319   IN  BOOLEAN                   IsEnd
320   )
321 {
322   EFI_STATUS                           Status;
323   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
324   SD_REQUEST                           *RwSingleBlkReq;
325   EFI_TPL                              OldTpl;
326 
327   RwSingleBlkReq = NULL;
328   PassThru       = Device->Private->PassThru;
329 
330   RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
331   if (RwSingleBlkReq == NULL) {
332     Status = EFI_OUT_OF_RESOURCES;
333     goto Error;
334   }
335 
336   RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;
337   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
338   InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);
339   gBS->RestoreTPL (OldTpl);
340   RwSingleBlkReq->Packet.SdMmcCmdBlk    = &RwSingleBlkReq->SdMmcCmdBlk;
341   RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk;
342   //
343   // Calculate timeout value through the below formula.
344   // Timeout = (transfer size) / (2MB/s).
345   // Taking 2MB/s as divisor as it's the lowest transfer speed
346   // above class 2.
347   // Refer to SD Physical Layer Simplified spec section 3.4 for details.
348   //
349   RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
350 
351   if (IsRead) {
352     RwSingleBlkReq->Packet.InDataBuffer     = Buffer;
353     RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
354 
355     RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;
356     RwSingleBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
357     RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
358   } else {
359     RwSingleBlkReq->Packet.OutDataBuffer     = Buffer;
360     RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
361 
362     RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;
363     RwSingleBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
364     RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
365   }
366 
367   if (Device->SectorAddressing) {
368     RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
369   } else {
370     RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
371   }
372 
373   RwSingleBlkReq->IsEnd = IsEnd;
374   RwSingleBlkReq->Token = Token;
375 
376   if ((Token != NULL) && (Token->Event != NULL)) {
377     Status = gBS->CreateEvent (
378                     EVT_NOTIFY_SIGNAL,
379                     TPL_NOTIFY,
380                     AsyncIoCallback,
381                     RwSingleBlkReq,
382                     &RwSingleBlkReq->Event
383                     );
384     if (EFI_ERROR (Status)) {
385       goto Error;
386     }
387   } else {
388     RwSingleBlkReq->Event = NULL;
389   }
390 
391   Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->Event);
392 
393 Error:
394   if ((Token != NULL) && (Token->Event != NULL)) {
395     //
396     // For asynchronous operation, only free request and event in error case.
397     // The request and event will be freed in asynchronous callback for success case.
398     //
399     if (EFI_ERROR (Status) && (RwSingleBlkReq != NULL)) {
400       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
401       RemoveEntryList (&RwSingleBlkReq->Link);
402       gBS->RestoreTPL (OldTpl);
403       if (RwSingleBlkReq->Event != NULL) {
404         gBS->CloseEvent (RwSingleBlkReq->Event);
405       }
406       FreePool (RwSingleBlkReq);
407     }
408   } else {
409     //
410     // For synchronous operation, free request whatever the execution result is.
411     //
412     if (RwSingleBlkReq != NULL) {
413       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
414       RemoveEntryList (&RwSingleBlkReq->Link);
415       gBS->RestoreTPL (OldTpl);
416       FreePool (RwSingleBlkReq);
417     }
418   }
419 
420   return Status;
421 }
422 
423 /**
424   Read/write multiple blocks through sync or async I/O request.
425 
426   @param[in]  Device            A pointer to the SD_DEVICE instance.
427   @param[in]  Lba               The starting logical block address to be read/written.
428                                 The caller is responsible for reading/writing to only
429                                 legitimate locations.
430   @param[in]  Buffer            A pointer to the destination/source buffer for the data.
431   @param[in]  BufferSize        Size of Buffer, must be a multiple of device block size.
432   @param[in]  IsRead            Indicates it is a read or write operation.
433   @param[in]  Token             A pointer to the token associated with the transaction.
434   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
435                                 This parameter is only meaningful in async I/O request.
436 
437   @retval EFI_SUCCESS           The request is executed successfully.
438   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
439   @retval Others                The request could not be executed successfully.
440 
441 **/
442 EFI_STATUS
SdRwMultiBlocks(IN SD_DEVICE * Device,IN EFI_LBA Lba,IN VOID * Buffer,IN UINTN BufferSize,IN BOOLEAN IsRead,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)443 SdRwMultiBlocks (
444   IN  SD_DEVICE                 *Device,
445   IN  EFI_LBA                   Lba,
446   IN  VOID                      *Buffer,
447   IN  UINTN                     BufferSize,
448   IN  BOOLEAN                   IsRead,
449   IN  EFI_BLOCK_IO2_TOKEN       *Token,
450   IN  BOOLEAN                   IsEnd
451   )
452 {
453   EFI_STATUS                    Status;
454   SD_REQUEST                    *RwMultiBlkReq;
455   EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
456   EFI_TPL                       OldTpl;
457 
458   RwMultiBlkReq = NULL;
459 
460   PassThru = Device->Private->PassThru;
461 
462   RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
463   if (RwMultiBlkReq == NULL) {
464     Status = EFI_OUT_OF_RESOURCES;
465     goto Error;
466   }
467 
468   RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;
469   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
470   InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);
471   gBS->RestoreTPL (OldTpl);
472   RwMultiBlkReq->Packet.SdMmcCmdBlk    = &RwMultiBlkReq->SdMmcCmdBlk;
473   RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;
474   //
475   // Calculate timeout value through the below formula.
476   // Timeout = (transfer size) / (2MB/s).
477   // Taking 2MB/s as divisor as it's the lowest transfer speed
478   // above class 2.
479   // Refer to SD Physical Layer Simplified spec section 3.4 for details.
480   //
481   RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
482 
483   if (IsRead) {
484     RwMultiBlkReq->Packet.InDataBuffer     = Buffer;
485     RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
486 
487     RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;
488     RwMultiBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
489     RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
490   } else {
491     RwMultiBlkReq->Packet.OutDataBuffer     = Buffer;
492     RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
493 
494     RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;
495     RwMultiBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
496     RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
497   }
498 
499   if (Device->SectorAddressing) {
500     RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
501   } else {
502     RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
503   }
504 
505   RwMultiBlkReq->IsEnd = IsEnd;
506   RwMultiBlkReq->Token = Token;
507 
508   if ((Token != NULL) && (Token->Event != NULL)) {
509     Status = gBS->CreateEvent (
510                     EVT_NOTIFY_SIGNAL,
511                     TPL_NOTIFY,
512                     AsyncIoCallback,
513                     RwMultiBlkReq,
514                     &RwMultiBlkReq->Event
515                     );
516     if (EFI_ERROR (Status)) {
517       goto Error;
518     }
519   } else {
520     RwMultiBlkReq->Event = NULL;
521   }
522 
523   Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
524 
525 Error:
526   if ((Token != NULL) && (Token->Event != NULL)) {
527     //
528     // For asynchronous operation, only free request and event in error case.
529     // The request and event will be freed in asynchronous callback for success case.
530     //
531     if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
532       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
533       RemoveEntryList (&RwMultiBlkReq->Link);
534       gBS->RestoreTPL (OldTpl);
535       if (RwMultiBlkReq->Event != NULL) {
536         gBS->CloseEvent (RwMultiBlkReq->Event);
537       }
538       FreePool (RwMultiBlkReq);
539     }
540   } else {
541     //
542     // For synchronous operation, free request whatever the execution result is.
543     //
544     if (RwMultiBlkReq != NULL) {
545       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
546       RemoveEntryList (&RwMultiBlkReq->Link);
547       gBS->RestoreTPL (OldTpl);
548       FreePool (RwMultiBlkReq);
549     }
550   }
551 
552   return Status;
553 }
554 
555 /**
556   This function transfers data from/to the sd memory card device.
557 
558   @param[in]       Device       A pointer to the SD_DEVICE instance.
559   @param[in]       MediaId      The media ID that the read/write request is for.
560   @param[in]       Lba          The starting logical block address to be read/written.
561                                 The caller is responsible for reading/writing to only
562                                 legitimate locations.
563   @param[in, out]  Buffer       A pointer to the destination/source buffer for the data.
564   @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.
565   @param[in]       IsRead       Indicates it is a read or write operation.
566   @param[in, out]  Token        A pointer to the token associated with the transaction.
567 
568   @retval EFI_SUCCESS           The data was read/written correctly to the device.
569   @retval EFI_WRITE_PROTECTED   The device can not be read/written to.
570   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read/write.
571   @retval EFI_NO_MEDIA          There is no media in the device.
572   @retval EFI_MEDIA_CHANGED     The MediaId does not match the current device.
573   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
574   @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,
575                                 or the buffer is not on proper alignment.
576 
577 **/
578 EFI_STATUS
SdReadWrite(IN SD_DEVICE * Device,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT VOID * Buffer,IN UINTN BufferSize,IN BOOLEAN IsRead,IN OUT EFI_BLOCK_IO2_TOKEN * Token)579 SdReadWrite (
580   IN     SD_DEVICE                      *Device,
581   IN     UINT32                         MediaId,
582   IN     EFI_LBA                        Lba,
583   IN OUT VOID                           *Buffer,
584   IN     UINTN                          BufferSize,
585   IN     BOOLEAN                        IsRead,
586   IN OUT EFI_BLOCK_IO2_TOKEN            *Token
587   )
588 {
589   EFI_STATUS                            Status;
590   EFI_BLOCK_IO_MEDIA                    *Media;
591   UINTN                                 BlockSize;
592   UINTN                                 BlockNum;
593   UINTN                                 IoAlign;
594   UINTN                                 Remaining;
595   UINT32                                MaxBlock;
596   BOOLEAN                               LastRw;
597 
598   Status = EFI_SUCCESS;
599   Media  = &Device->BlockMedia;
600   LastRw = FALSE;
601 
602   if (MediaId != Media->MediaId) {
603     return EFI_MEDIA_CHANGED;
604   }
605 
606   if (!IsRead && Media->ReadOnly) {
607     return EFI_WRITE_PROTECTED;
608   }
609 
610   //
611   // Check parameters.
612   //
613   if (Buffer == NULL) {
614     return EFI_INVALID_PARAMETER;
615   }
616 
617   if (BufferSize == 0) {
618     if ((Token != NULL) && (Token->Event != NULL)) {
619       Token->TransactionStatus = EFI_SUCCESS;
620       gBS->SignalEvent (Token->Event);
621     }
622     return EFI_SUCCESS;
623   }
624 
625   BlockSize = Media->BlockSize;
626   if ((BufferSize % BlockSize) != 0) {
627     return EFI_BAD_BUFFER_SIZE;
628   }
629 
630   BlockNum  = BufferSize / BlockSize;
631   if ((Lba + BlockNum - 1) > Media->LastBlock) {
632     return EFI_INVALID_PARAMETER;
633   }
634 
635   IoAlign = Media->IoAlign;
636   if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
637     return EFI_INVALID_PARAMETER;
638   }
639 
640   if ((Token != NULL) && (Token->Event != NULL)) {
641     Token->TransactionStatus = EFI_SUCCESS;
642   }
643 
644   //
645   // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
646   //
647   Remaining = BlockNum;
648   MaxBlock  = 0xFFFF;
649 
650   while (Remaining > 0) {
651     if (Remaining <= MaxBlock) {
652       BlockNum = Remaining;
653       LastRw   = TRUE;
654     } else {
655       BlockNum = MaxBlock;
656     }
657 
658     BufferSize = BlockNum * BlockSize;
659     if (BlockNum == 1) {
660       Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
661     } else {
662       Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
663     }
664     if (EFI_ERROR (Status)) {
665       return Status;
666     }
667     DEBUG ((DEBUG_BLKIO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
668       IsRead ? "Read" : "Write", Lba, BlockNum,
669       (Token != NULL) ? Token->Event : NULL, Status));
670     Lba   += BlockNum;
671     Buffer = (UINT8*)Buffer + BufferSize;
672     Remaining -= BlockNum;
673   }
674 
675   return Status;
676 }
677 
678 /**
679   Reset the Block Device.
680 
681   @param  This                 Indicates a pointer to the calling context.
682   @param  ExtendedVerification Driver may perform diagnostics on reset.
683 
684   @retval EFI_SUCCESS          The device was reset.
685   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
686                                not be reset.
687 
688 **/
689 EFI_STATUS
690 EFIAPI
SdReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)691 SdReset (
692   IN  EFI_BLOCK_IO_PROTOCOL     *This,
693   IN  BOOLEAN                   ExtendedVerification
694   )
695 {
696   EFI_STATUS                    Status;
697   SD_DEVICE                     *Device;
698   EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
699 
700   Device = SD_DEVICE_DATA_FROM_BLKIO (This);
701 
702   PassThru = Device->Private->PassThru;
703   Status   = PassThru->ResetDevice (PassThru, Device->Slot);
704   if (EFI_ERROR (Status)) {
705     Status = EFI_DEVICE_ERROR;
706   }
707 
708   return Status;
709 }
710 
711 /**
712   Read BufferSize bytes from Lba into Buffer.
713 
714   @param  This       Indicates a pointer to the calling context.
715   @param  MediaId    Id of the media, changes every time the media is replaced.
716   @param  Lba        The starting Logical Block Address to read from
717   @param  BufferSize Size of Buffer, must be a multiple of device block size.
718   @param  Buffer     A pointer to the destination buffer for the data. The caller is
719                      responsible for either having implicit or explicit ownership of the buffer.
720 
721   @retval EFI_SUCCESS           The data was read correctly from the device.
722   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
723   @retval EFI_NO_MEDIA          There is no media in the device.
724   @retval EFI_MEDIA_CHANGED     The MediaId does not match the current device.
725   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
726   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
727                                 or the buffer is not on proper alignment.
728 
729 **/
730 EFI_STATUS
731 EFIAPI
SdReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,OUT VOID * Buffer)732 SdReadBlocks (
733   IN     EFI_BLOCK_IO_PROTOCOL  *This,
734   IN     UINT32                 MediaId,
735   IN     EFI_LBA                Lba,
736   IN     UINTN                  BufferSize,
737      OUT VOID                   *Buffer
738   )
739 {
740   EFI_STATUS             Status;
741   SD_DEVICE              *Device;
742 
743   Device = SD_DEVICE_DATA_FROM_BLKIO (This);
744 
745   Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
746   return Status;
747 }
748 
749 /**
750   Write BufferSize bytes from Lba into Buffer.
751 
752   @param  This       Indicates a pointer to the calling context.
753   @param  MediaId    The media ID that the write request is for.
754   @param  Lba        The starting logical block address to be written. The caller is
755                      responsible for writing to only legitimate locations.
756   @param  BufferSize Size of Buffer, must be a multiple of device block size.
757   @param  Buffer     A pointer to the source buffer for the data.
758 
759   @retval EFI_SUCCESS           The data was written correctly to the device.
760   @retval EFI_WRITE_PROTECTED   The device can not be written to.
761   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
762   @retval EFI_NO_MEDIA          There is no media in the device.
763   @retval EFI_MEDIA_CHANGED     The MediaId does not match the current device.
764   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
765   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
766                                 or the buffer is not on proper alignment.
767 
768 **/
769 EFI_STATUS
770 EFIAPI
SdWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN VOID * Buffer)771 SdWriteBlocks (
772   IN  EFI_BLOCK_IO_PROTOCOL   *This,
773   IN  UINT32                  MediaId,
774   IN  EFI_LBA                 Lba,
775   IN  UINTN                   BufferSize,
776   IN  VOID                    *Buffer
777   )
778 {
779   EFI_STATUS             Status;
780   SD_DEVICE              *Device;
781 
782   Device = SD_DEVICE_DATA_FROM_BLKIO (This);
783 
784   Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
785   return Status;
786 }
787 
788 /**
789   Flush the Block Device.
790 
791   @param  This              Indicates a pointer to the calling context.
792 
793   @retval EFI_SUCCESS       All outstanding data was written to the device
794   @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data
795   @retval EFI_NO_MEDIA      There is no media in the device.
796 
797 **/
798 EFI_STATUS
799 EFIAPI
SdFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)800 SdFlushBlocks (
801   IN  EFI_BLOCK_IO_PROTOCOL   *This
802   )
803 {
804   //
805   // return directly
806   //
807   return EFI_SUCCESS;
808 }
809 
810 /**
811   Reset the Block Device.
812 
813   @param[in]  This                 Indicates a pointer to the calling context.
814   @param[in]  ExtendedVerification Driver may perform diagnostics on reset.
815 
816   @retval EFI_SUCCESS              The device was reset.
817   @retval EFI_DEVICE_ERROR         The device is not functioning properly and could
818                                    not be reset.
819 
820 **/
821 EFI_STATUS
822 EFIAPI
SdResetEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN BOOLEAN ExtendedVerification)823 SdResetEx (
824   IN  EFI_BLOCK_IO2_PROTOCOL  *This,
825   IN  BOOLEAN                 ExtendedVerification
826   )
827 {
828   SD_DEVICE                   *Device;
829   LIST_ENTRY                  *Link;
830   LIST_ENTRY                  *NextLink;
831   SD_REQUEST                  *Request;
832   EFI_TPL                     OldTpl;
833 
834   Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
835 
836   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
837   for (Link = GetFirstNode (&Device->Queue);
838        !IsNull (&Device->Queue, Link);
839        Link = NextLink) {
840     NextLink = GetNextNode (&Device->Queue, Link);
841     RemoveEntryList (Link);
842 
843     Request = SD_REQUEST_FROM_LINK (Link);
844 
845     gBS->CloseEvent (Request->Event);
846     Request->Token->TransactionStatus = EFI_ABORTED;
847 
848     if (Request->IsEnd) {
849       gBS->SignalEvent (Request->Token->Event);
850     }
851 
852     FreePool (Request);
853   }
854   gBS->RestoreTPL (OldTpl);
855 
856   return EFI_SUCCESS;
857 }
858 
859 /**
860   Read BufferSize bytes from Lba into Buffer.
861 
862   @param[in]       This         Indicates a pointer to the calling context.
863   @param[in]       MediaId      Id of the media, changes every time the media is replaced.
864   @param[in]       Lba          The starting Logical Block Address to read from.
865   @param[in, out]  Token        A pointer to the token associated with the transaction.
866   @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.
867   @param[out]      Buffer       A pointer to the destination buffer for the data. The caller is
868                                 responsible for either having implicit or explicit ownership of the buffer.
869 
870   @retval EFI_SUCCESS           The read request was queued if Event is not NULL.
871                                 The data was read correctly from the device if
872                                 the Event is NULL.
873   @retval EFI_DEVICE_ERROR      The device reported an error while performing
874                                 the read.
875   @retval EFI_NO_MEDIA          There is no media in the device.
876   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
877   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the
878                                 intrinsic block size of the device.
879   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
880                                 or the buffer is not on proper alignment.
881   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
882                                 of resources.
883 
884 **/
885 EFI_STATUS
886 EFIAPI
SdReadBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT EFI_BLOCK_IO2_TOKEN * Token,IN UINTN BufferSize,OUT VOID * Buffer)887 SdReadBlocksEx (
888   IN     EFI_BLOCK_IO2_PROTOCOL *This,
889   IN     UINT32                 MediaId,
890   IN     EFI_LBA                Lba,
891   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
892   IN     UINTN                  BufferSize,
893      OUT VOID                   *Buffer
894   )
895 {
896   EFI_STATUS             Status;
897   SD_DEVICE              *Device;
898 
899   Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
900 
901   Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
902   return Status;
903 }
904 
905 /**
906   Write BufferSize bytes from Lba into Buffer.
907 
908   @param[in]       This         Indicates a pointer to the calling context.
909   @param[in]       MediaId      The media ID that the write request is for.
910   @param[in]       Lba          The starting logical block address to be written. The
911                                 caller is responsible for writing to only legitimate
912                                 locations.
913   @param[in, out]  Token        A pointer to the token associated with the transaction.
914   @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.
915   @param[in]       Buffer       A pointer to the source buffer for the data.
916 
917   @retval EFI_SUCCESS           The data was written correctly to the device.
918   @retval EFI_WRITE_PROTECTED   The device can not be written to.
919   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
920   @retval EFI_NO_MEDIA          There is no media in the device.
921   @retval EFI_MEDIA_CHANGED     The MediaId does not match the current device.
922   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
923   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
924                                 or the buffer is not on proper alignment.
925 
926 **/
927 EFI_STATUS
928 EFIAPI
SdWriteBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT EFI_BLOCK_IO2_TOKEN * Token,IN UINTN BufferSize,IN VOID * Buffer)929 SdWriteBlocksEx (
930   IN     EFI_BLOCK_IO2_PROTOCOL *This,
931   IN     UINT32                 MediaId,
932   IN     EFI_LBA                Lba,
933   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
934   IN     UINTN                  BufferSize,
935   IN     VOID                   *Buffer
936   )
937 {
938   EFI_STATUS             Status;
939   SD_DEVICE              *Device;
940 
941   Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
942 
943   Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
944   return Status;
945 }
946 
947 /**
948   Flush the Block Device.
949 
950   @param[in]       This     Indicates a pointer to the calling context.
951   @param[in, out]  Token    A pointer to the token associated with the transaction.
952 
953   @retval EFI_SUCCESS       All outstanding data was written to the device
954   @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data
955   @retval EFI_NO_MEDIA      There is no media in the device.
956 
957 **/
958 EFI_STATUS
959 EFIAPI
SdFlushBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN OUT EFI_BLOCK_IO2_TOKEN * Token)960 SdFlushBlocksEx (
961   IN     EFI_BLOCK_IO2_PROTOCOL  *This,
962   IN OUT EFI_BLOCK_IO2_TOKEN     *Token
963   )
964 {
965   //
966   // Signal event and return directly.
967   //
968   if (Token != NULL && Token->Event != NULL) {
969     Token->TransactionStatus = EFI_SUCCESS;
970     gBS->SignalEvent (Token->Event);
971   }
972 
973   return EFI_SUCCESS;
974 }
975 
976 /**
977   Set the erase start address through sync or async I/O request.
978 
979   @param[in]  Device            A pointer to the SD_DEVICE instance.
980   @param[in]  StartLba          The starting logical block address to be erased.
981   @param[in]  Token             A pointer to the token associated with the transaction.
982   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
983                                 This parameter is only meaningful in async I/O request.
984 
985   @retval EFI_SUCCESS           The request is executed successfully.
986   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
987   @retval Others                The request could not be executed successfully.
988 
989 **/
990 EFI_STATUS
SdEraseBlockStart(IN SD_DEVICE * Device,IN EFI_LBA StartLba,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)991 SdEraseBlockStart (
992   IN  SD_DEVICE                 *Device,
993   IN  EFI_LBA                   StartLba,
994   IN  EFI_BLOCK_IO2_TOKEN       *Token,
995   IN  BOOLEAN                   IsEnd
996   )
997 {
998   EFI_STATUS                           Status;
999   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
1000   SD_REQUEST                           *EraseBlockStart;
1001   EFI_TPL                              OldTpl;
1002 
1003   EraseBlockStart = NULL;
1004   PassThru        = Device->Private->PassThru;
1005 
1006   EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));
1007   if (EraseBlockStart == NULL) {
1008     Status = EFI_OUT_OF_RESOURCES;
1009     goto Error;
1010   }
1011 
1012   EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;
1013   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1014   InsertTailList (&Device->Queue, &EraseBlockStart->Link);
1015   gBS->RestoreTPL (OldTpl);
1016   EraseBlockStart->Packet.SdMmcCmdBlk    = &EraseBlockStart->SdMmcCmdBlk;
1017   EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
1018   EraseBlockStart->Packet.Timeout        = SD_GENERIC_TIMEOUT;
1019 
1020   EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;
1021   EraseBlockStart->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
1022   EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1023 
1024   if (Device->SectorAddressing) {
1025     EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
1026   } else {
1027     EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->BlockMedia.BlockSize);
1028   }
1029 
1030   EraseBlockStart->IsEnd = IsEnd;
1031   EraseBlockStart->Token = Token;
1032 
1033   if ((Token != NULL) && (Token->Event != NULL)) {
1034     Status = gBS->CreateEvent (
1035                     EVT_NOTIFY_SIGNAL,
1036                     TPL_NOTIFY,
1037                     AsyncIoCallback,
1038                     EraseBlockStart,
1039                     &EraseBlockStart->Event
1040                     );
1041     if (EFI_ERROR (Status)) {
1042       goto Error;
1043     }
1044   } else {
1045     EraseBlockStart->Event = NULL;
1046   }
1047 
1048   Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
1049 
1050 Error:
1051   if ((Token != NULL) && (Token->Event != NULL)) {
1052     //
1053     // For asynchronous operation, only free request and event in error case.
1054     // The request and event will be freed in asynchronous callback for success case.
1055     //
1056     if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
1057       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1058       RemoveEntryList (&EraseBlockStart->Link);
1059       gBS->RestoreTPL (OldTpl);
1060       if (EraseBlockStart->Event != NULL) {
1061         gBS->CloseEvent (EraseBlockStart->Event);
1062       }
1063       FreePool (EraseBlockStart);
1064     }
1065   } else {
1066     //
1067     // For synchronous operation, free request whatever the execution result is.
1068     //
1069     if (EraseBlockStart != NULL) {
1070       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1071       RemoveEntryList (&EraseBlockStart->Link);
1072       gBS->RestoreTPL (OldTpl);
1073       FreePool (EraseBlockStart);
1074     }
1075   }
1076 
1077   return Status;
1078 }
1079 
1080 /**
1081   Set the erase end address through sync or async I/O request.
1082 
1083   @param[in]  Device            A pointer to the SD_DEVICE instance.
1084   @param[in]  EndLba            The ending logical block address to be erased.
1085   @param[in]  Token             A pointer to the token associated with the transaction.
1086   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
1087                                 This parameter is only meaningful in async I/O request.
1088 
1089   @retval EFI_SUCCESS           The request is executed successfully.
1090   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
1091   @retval Others                The request could not be executed successfully.
1092 
1093 **/
1094 EFI_STATUS
SdEraseBlockEnd(IN SD_DEVICE * Device,IN EFI_LBA EndLba,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)1095 SdEraseBlockEnd (
1096   IN  SD_DEVICE                 *Device,
1097   IN  EFI_LBA                   EndLba,
1098   IN  EFI_BLOCK_IO2_TOKEN       *Token,
1099   IN  BOOLEAN                   IsEnd
1100   )
1101 {
1102   EFI_STATUS                           Status;
1103   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
1104   SD_REQUEST                           *EraseBlockEnd;
1105   EFI_TPL                              OldTpl;
1106 
1107   EraseBlockEnd = NULL;
1108   PassThru      = Device->Private->PassThru;
1109 
1110   EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));
1111   if (EraseBlockEnd == NULL) {
1112     Status = EFI_OUT_OF_RESOURCES;
1113     goto Error;
1114   }
1115 
1116   EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;
1117   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1118   InsertTailList (&Device->Queue, &EraseBlockEnd->Link);
1119   gBS->RestoreTPL (OldTpl);
1120   EraseBlockEnd->Packet.SdMmcCmdBlk    = &EraseBlockEnd->SdMmcCmdBlk;
1121   EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
1122   EraseBlockEnd->Packet.Timeout        = SD_GENERIC_TIMEOUT;
1123 
1124   EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;
1125   EraseBlockEnd->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
1126   EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1127 
1128   if (Device->SectorAddressing) {
1129     EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
1130   } else {
1131     EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->BlockMedia.BlockSize);
1132   }
1133 
1134   EraseBlockEnd->IsEnd = IsEnd;
1135   EraseBlockEnd->Token = Token;
1136 
1137   if ((Token != NULL) && (Token->Event != NULL)) {
1138     Status = gBS->CreateEvent (
1139                     EVT_NOTIFY_SIGNAL,
1140                     TPL_NOTIFY,
1141                     AsyncIoCallback,
1142                     EraseBlockEnd,
1143                     &EraseBlockEnd->Event
1144                     );
1145     if (EFI_ERROR (Status)) {
1146       goto Error;
1147     }
1148   } else {
1149     EraseBlockEnd->Event = NULL;
1150   }
1151 
1152   Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
1153 
1154 Error:
1155   if ((Token != NULL) && (Token->Event != NULL)) {
1156     //
1157     // For asynchronous operation, only free request and event in error case.
1158     // The request and event will be freed in asynchronous callback for success case.
1159     //
1160     if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
1161       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1162       RemoveEntryList (&EraseBlockEnd->Link);
1163       gBS->RestoreTPL (OldTpl);
1164       if (EraseBlockEnd->Event != NULL) {
1165         gBS->CloseEvent (EraseBlockEnd->Event);
1166       }
1167       FreePool (EraseBlockEnd);
1168     }
1169   } else {
1170     //
1171     // For synchronous operation, free request whatever the execution result is.
1172     //
1173     if (EraseBlockEnd != NULL) {
1174       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1175       RemoveEntryList (&EraseBlockEnd->Link);
1176       gBS->RestoreTPL (OldTpl);
1177       FreePool (EraseBlockEnd);
1178     }
1179   }
1180 
1181   return Status;
1182 }
1183 
1184 /**
1185   Erase specified blocks through sync or async I/O request.
1186 
1187   @param[in]  Device            A pointer to the SD_DEVICE instance.
1188   @param[in]  Token             A pointer to the token associated with the transaction.
1189   @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.
1190                                 This parameter is only meaningful in async I/O request.
1191 
1192   @retval EFI_SUCCESS           The request is executed successfully.
1193   @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.
1194   @retval Others                The request could not be executed successfully.
1195 
1196 **/
1197 EFI_STATUS
SdEraseBlock(IN SD_DEVICE * Device,IN EFI_BLOCK_IO2_TOKEN * Token,IN BOOLEAN IsEnd)1198 SdEraseBlock (
1199   IN  SD_DEVICE                 *Device,
1200   IN  EFI_BLOCK_IO2_TOKEN       *Token,
1201   IN  BOOLEAN                   IsEnd
1202   )
1203 {
1204   EFI_STATUS                           Status;
1205   EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;
1206   SD_REQUEST                           *EraseBlock;
1207   EFI_TPL                              OldTpl;
1208 
1209   EraseBlock = NULL;
1210   PassThru   = Device->Private->PassThru;
1211 
1212   EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));
1213   if (EraseBlock == NULL) {
1214     Status = EFI_OUT_OF_RESOURCES;
1215     goto Error;
1216   }
1217 
1218   EraseBlock->Signature = SD_REQUEST_SIGNATURE;
1219   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1220   InsertTailList (&Device->Queue, &EraseBlock->Link);
1221   gBS->RestoreTPL (OldTpl);
1222   EraseBlock->Packet.SdMmcCmdBlk    = &EraseBlock->SdMmcCmdBlk;
1223   EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
1224   EraseBlock->Packet.Timeout        = SD_GENERIC_TIMEOUT;
1225 
1226   EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;
1227   EraseBlock->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
1228   EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
1229 
1230   EraseBlock->IsEnd = IsEnd;
1231   EraseBlock->Token = Token;
1232 
1233   if ((Token != NULL) && (Token->Event != NULL)) {
1234     Status = gBS->CreateEvent (
1235                     EVT_NOTIFY_SIGNAL,
1236                     TPL_NOTIFY,
1237                     AsyncIoCallback,
1238                     EraseBlock,
1239                     &EraseBlock->Event
1240                     );
1241     if (EFI_ERROR (Status)) {
1242       goto Error;
1243     }
1244   } else {
1245     EraseBlock->Event = NULL;
1246   }
1247 
1248   Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
1249 
1250 Error:
1251   if ((Token != NULL) && (Token->Event != NULL)) {
1252     //
1253     // For asynchronous operation, only free request and event in error case.
1254     // The request and event will be freed in asynchronous callback for success case.
1255     //
1256     if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
1257       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1258       RemoveEntryList (&EraseBlock->Link);
1259       gBS->RestoreTPL (OldTpl);
1260       if (EraseBlock->Event != NULL) {
1261         gBS->CloseEvent (EraseBlock->Event);
1262       }
1263       FreePool (EraseBlock);
1264     }
1265   } else {
1266     //
1267     // For synchronous operation, free request whatever the execution result is.
1268     //
1269     if (EraseBlock != NULL) {
1270       OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1271       RemoveEntryList (&EraseBlock->Link);
1272       gBS->RestoreTPL (OldTpl);
1273       FreePool (EraseBlock);
1274     }
1275   }
1276 
1277   return Status;
1278 }
1279 
1280 /**
1281   Erase a specified number of device blocks.
1282 
1283   @param[in]       This           Indicates a pointer to the calling context.
1284   @param[in]       MediaId        The media ID that the erase request is for.
1285   @param[in]       Lba            The starting logical block address to be
1286                                   erased. The caller is responsible for erasing
1287                                   only legitimate locations.
1288   @param[in, out]  Token          A pointer to the token associated with the
1289                                   transaction.
1290   @param[in]       Size           The size in bytes to be erased. This must be
1291                                   a multiple of the physical block size of the
1292                                   device.
1293 
1294   @retval EFI_SUCCESS             The erase request was queued if Event is not
1295                                   NULL. The data was erased correctly to the
1296                                   device if the Event is NULL.to the device.
1297   @retval EFI_WRITE_PROTECTED     The device cannot be erased due to write
1298                                   protection.
1299   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
1300                                   to perform the erase operation.
1301   @retval EFI_INVALID_PARAMETER   The erase request contains LBAs that are not
1302                                   valid.
1303   @retval EFI_NO_MEDIA            There is no media in the device.
1304   @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
1305 
1306 **/
1307 EFI_STATUS
1308 EFIAPI
SdEraseBlocks(IN EFI_ERASE_BLOCK_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT EFI_ERASE_BLOCK_TOKEN * Token,IN UINTN Size)1309 SdEraseBlocks (
1310   IN     EFI_ERASE_BLOCK_PROTOCOL      *This,
1311   IN     UINT32                        MediaId,
1312   IN     EFI_LBA                       Lba,
1313   IN OUT EFI_ERASE_BLOCK_TOKEN         *Token,
1314   IN     UINTN                         Size
1315   )
1316 {
1317   EFI_STATUS                            Status;
1318   EFI_BLOCK_IO_MEDIA                    *Media;
1319   UINTN                                 BlockSize;
1320   UINTN                                 BlockNum;
1321   EFI_LBA                               LastLba;
1322   SD_DEVICE                             *Device;
1323 
1324   Status = EFI_SUCCESS;
1325   Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);
1326   Media  = &Device->BlockMedia;
1327 
1328   if (MediaId != Media->MediaId) {
1329     return EFI_MEDIA_CHANGED;
1330   }
1331 
1332   if (Media->ReadOnly) {
1333     return EFI_WRITE_PROTECTED;
1334   }
1335 
1336   //
1337   // Check parameters.
1338   //
1339   BlockSize = Media->BlockSize;
1340   if ((Size % BlockSize) != 0) {
1341     return EFI_INVALID_PARAMETER;
1342   }
1343 
1344   BlockNum  = Size / BlockSize;
1345   if ((Lba + BlockNum - 1) > Media->LastBlock) {
1346     return EFI_INVALID_PARAMETER;
1347   }
1348 
1349   if ((Token != NULL) && (Token->Event != NULL)) {
1350     Token->TransactionStatus = EFI_SUCCESS;
1351   }
1352 
1353   LastLba = Lba + BlockNum - 1;
1354 
1355   Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
1356   if (EFI_ERROR (Status)) {
1357     return Status;
1358   }
1359 
1360   Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
1361   if (EFI_ERROR (Status)) {
1362     return Status;
1363   }
1364 
1365   Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
1366   if (EFI_ERROR (Status)) {
1367     return Status;
1368   }
1369 
1370   DEBUG ((
1371     DEBUG_INFO,
1372     "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
1373     Lba,
1374     BlockNum,
1375     (Token != NULL) ? Token->Event : NULL,
1376     Status
1377     ));
1378 
1379   return Status;
1380 }
1381 
1382