Home | History | Annotate | Download | only in SdDxe
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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