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