Home | History | Annotate | Download | only in NvmExpressDxe
      1 /** @file
      2   NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
      3   NVM Express specification.
      4 
      5   Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "NvmExpress.h"
     17 
     18 /**
     19   Read some sectors from the device.
     20 
     21   @param  Device                 The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
     22   @param  Buffer                 The buffer used to store the data read from the device.
     23   @param  Lba                    The start block number.
     24   @param  Blocks                 Total block number to be read.
     25 
     26   @retval EFI_SUCCESS            Datum are read from the device.
     27   @retval Others                 Fail to read all the datum.
     28 
     29 **/
     30 EFI_STATUS
     31 ReadSectors (
     32   IN NVME_DEVICE_PRIVATE_DATA           *Device,
     33   IN UINT64                             Buffer,
     34   IN UINT64                             Lba,
     35   IN UINT32                             Blocks
     36   )
     37 {
     38   NVME_CONTROLLER_PRIVATE_DATA             *Private;
     39   UINT32                                   Bytes;
     40   EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
     41   EFI_NVM_EXPRESS_COMMAND                  Command;
     42   EFI_NVM_EXPRESS_COMPLETION               Completion;
     43   EFI_STATUS                               Status;
     44   UINT32                                   BlockSize;
     45 
     46   Private    = Device->Controller;
     47   BlockSize  = Device->Media.BlockSize;
     48   Bytes      = Blocks * BlockSize;
     49 
     50   ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
     51   ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
     52   ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
     53 
     54   CommandPacket.NvmeCmd        = &Command;
     55   CommandPacket.NvmeCompletion = &Completion;
     56 
     57   CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;
     58   CommandPacket.NvmeCmd->Nsid        = Device->NamespaceId;
     59   CommandPacket.TransferBuffer       = (VOID *)(UINTN)Buffer;
     60 
     61   CommandPacket.TransferLength = Bytes;
     62   CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
     63   CommandPacket.QueueType      = NVME_IO_QUEUE;
     64 
     65   CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
     66   CommandPacket.NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
     67   CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
     68 
     69   CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
     70 
     71   Status = Private->Passthru.PassThru (
     72                                &Private->Passthru,
     73                                Device->NamespaceId,
     74                                &CommandPacket,
     75                                NULL
     76                                );
     77 
     78   return Status;
     79 }
     80 
     81 /**
     82   Write some sectors to the device.
     83 
     84   @param  Device                 The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
     85   @param  Buffer                 The buffer to be written into the device.
     86   @param  Lba                    The start block number.
     87   @param  Blocks                 Total block number to be written.
     88 
     89   @retval EFI_SUCCESS            Datum are written into the buffer.
     90   @retval Others                 Fail to write all the datum.
     91 
     92 **/
     93 EFI_STATUS
     94 WriteSectors (
     95   IN NVME_DEVICE_PRIVATE_DATA      *Device,
     96   IN UINT64                        Buffer,
     97   IN UINT64                        Lba,
     98   IN UINT32                        Blocks
     99   )
    100 {
    101   NVME_CONTROLLER_PRIVATE_DATA             *Private;
    102   EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
    103   EFI_NVM_EXPRESS_COMMAND                  Command;
    104   EFI_NVM_EXPRESS_COMPLETION               Completion;
    105   EFI_STATUS                               Status;
    106   UINT32                                   Bytes;
    107   UINT32                                   BlockSize;
    108 
    109   Private    = Device->Controller;
    110   BlockSize  = Device->Media.BlockSize;
    111   Bytes      = Blocks * BlockSize;
    112 
    113   ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
    114   ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
    115   ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
    116 
    117   CommandPacket.NvmeCmd        = &Command;
    118   CommandPacket.NvmeCompletion = &Completion;
    119 
    120   CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;
    121   CommandPacket.NvmeCmd->Nsid  = Device->NamespaceId;
    122   CommandPacket.TransferBuffer = (VOID *)(UINTN)Buffer;
    123 
    124   CommandPacket.TransferLength = Bytes;
    125   CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
    126   CommandPacket.QueueType      = NVME_IO_QUEUE;
    127 
    128   CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
    129   CommandPacket.NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
    130   //
    131   // Set Force Unit Access bit (bit 30) to use write-through behaviour
    132   //
    133   CommandPacket.NvmeCmd->Cdw12 = ((Blocks - 1) & 0xFFFF) | BIT30;
    134 
    135   CommandPacket.MetadataBuffer = NULL;
    136   CommandPacket.MetadataLength = 0;
    137 
    138   CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
    139 
    140   Status = Private->Passthru.PassThru (
    141                                &Private->Passthru,
    142                                Device->NamespaceId,
    143                                &CommandPacket,
    144                                NULL
    145                                );
    146 
    147   return Status;
    148 }
    149 
    150 /**
    151   Read some blocks from the device.
    152 
    153   @param  Device                 The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
    154   @param  Buffer                 The buffer used to store the data read from the device.
    155   @param  Lba                    The start block number.
    156   @param  Blocks                 Total block number to be read.
    157 
    158   @retval EFI_SUCCESS            Datum are read from the device.
    159   @retval Others                 Fail to read all the datum.
    160 
    161 **/
    162 EFI_STATUS
    163 NvmeRead (
    164   IN     NVME_DEVICE_PRIVATE_DATA       *Device,
    165      OUT VOID                           *Buffer,
    166   IN     UINT64                         Lba,
    167   IN     UINTN                          Blocks
    168   )
    169 {
    170   EFI_STATUS                       Status;
    171   UINT32                           BlockSize;
    172   NVME_CONTROLLER_PRIVATE_DATA     *Private;
    173   UINT32                           MaxTransferBlocks;
    174   UINTN                            OrginalBlocks;
    175   BOOLEAN                          IsEmpty;
    176   EFI_TPL                          OldTpl;
    177 
    178   //
    179   // Wait for the device's asynchronous I/O queue to become empty.
    180   //
    181   while (TRUE) {
    182     OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
    183     IsEmpty = IsListEmpty (&Device->AsyncQueue);
    184     gBS->RestoreTPL (OldTpl);
    185 
    186     if (IsEmpty) {
    187       break;
    188     }
    189 
    190     gBS->Stall (100);
    191   }
    192 
    193   Status        = EFI_SUCCESS;
    194   Private       = Device->Controller;
    195   BlockSize     = Device->Media.BlockSize;
    196   OrginalBlocks = Blocks;
    197 
    198   if (Private->ControllerData->Mdts != 0) {
    199     MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
    200   } else {
    201     MaxTransferBlocks = 1024;
    202   }
    203 
    204   while (Blocks > 0) {
    205     if (Blocks > MaxTransferBlocks) {
    206       Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);
    207 
    208       Blocks -= MaxTransferBlocks;
    209       Buffer  = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
    210       Lba    += MaxTransferBlocks;
    211     } else {
    212       Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);
    213       Blocks = 0;
    214     }
    215 
    216     if (EFI_ERROR(Status)) {
    217       break;
    218     }
    219   }
    220 
    221   DEBUG ((EFI_D_VERBOSE, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
    222     "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
    223     (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
    224 
    225   return Status;
    226 }
    227 
    228 /**
    229   Write some blocks to the device.
    230 
    231   @param  Device                 The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
    232   @param  Buffer                 The buffer to be written into the device.
    233   @param  Lba                    The start block number.
    234   @param  Blocks                 Total block number to be written.
    235 
    236   @retval EFI_SUCCESS            Datum are written into the buffer.
    237   @retval Others                 Fail to write all the datum.
    238 
    239 **/
    240 EFI_STATUS
    241 NvmeWrite (
    242   IN NVME_DEVICE_PRIVATE_DATA           *Device,
    243   IN VOID                               *Buffer,
    244   IN UINT64                             Lba,
    245   IN UINTN                              Blocks
    246   )
    247 {
    248   EFI_STATUS                       Status;
    249   UINT32                           BlockSize;
    250   NVME_CONTROLLER_PRIVATE_DATA     *Private;
    251   UINT32                           MaxTransferBlocks;
    252   UINTN                            OrginalBlocks;
    253   BOOLEAN                          IsEmpty;
    254   EFI_TPL                          OldTpl;
    255 
    256   //
    257   // Wait for the device's asynchronous I/O queue to become empty.
    258   //
    259   while (TRUE) {
    260     OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
    261     IsEmpty = IsListEmpty (&Device->AsyncQueue);
    262     gBS->RestoreTPL (OldTpl);
    263 
    264     if (IsEmpty) {
    265       break;
    266     }
    267 
    268     gBS->Stall (100);
    269   }
    270 
    271   Status        = EFI_SUCCESS;
    272   Private       = Device->Controller;
    273   BlockSize     = Device->Media.BlockSize;
    274   OrginalBlocks = Blocks;
    275 
    276   if (Private->ControllerData->Mdts != 0) {
    277     MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
    278   } else {
    279     MaxTransferBlocks = 1024;
    280   }
    281 
    282   while (Blocks > 0) {
    283     if (Blocks > MaxTransferBlocks) {
    284       Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);
    285 
    286       Blocks -= MaxTransferBlocks;
    287       Buffer  = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
    288       Lba    += MaxTransferBlocks;
    289     } else {
    290       Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);
    291       Blocks = 0;
    292     }
    293 
    294     if (EFI_ERROR(Status)) {
    295       break;
    296     }
    297   }
    298 
    299   DEBUG ((EFI_D_VERBOSE, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
    300     "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
    301     (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
    302 
    303   return Status;
    304 }
    305 
    306 /**
    307   Flushes all modified data to the device.
    308 
    309   @param  Device                 The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
    310 
    311   @retval EFI_SUCCESS            Datum are written into the buffer.
    312   @retval Others                 Fail to write all the datum.
    313 
    314 **/
    315 EFI_STATUS
    316 NvmeFlush (
    317   IN NVME_DEVICE_PRIVATE_DATA      *Device
    318   )
    319 {
    320   NVME_CONTROLLER_PRIVATE_DATA             *Private;
    321   EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
    322   EFI_NVM_EXPRESS_COMMAND                  Command;
    323   EFI_NVM_EXPRESS_COMPLETION               Completion;
    324   EFI_STATUS                               Status;
    325 
    326   Private = Device->Controller;
    327 
    328   ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
    329   ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
    330   ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
    331 
    332   CommandPacket.NvmeCmd        = &Command;
    333   CommandPacket.NvmeCompletion = &Completion;
    334 
    335   CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_FLUSH_OPC;
    336   CommandPacket.NvmeCmd->Nsid  = Device->NamespaceId;
    337   CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
    338   CommandPacket.QueueType      = NVME_IO_QUEUE;
    339 
    340   Status = Private->Passthru.PassThru (
    341                                &Private->Passthru,
    342                                Device->NamespaceId,
    343                                &CommandPacket,
    344                                NULL
    345                                );
    346 
    347   return Status;
    348 }
    349 
    350 /**
    351   Nonblocking I/O callback funtion when the event is signaled.
    352 
    353   @param[in]  Event     The Event this notify function registered to.
    354   @param[in]  Context   Pointer to the context data registered to the
    355                         Event.
    356 
    357 **/
    358 VOID
    359 EFIAPI
    360 AsyncIoCallback (
    361   IN EFI_EVENT                Event,
    362   IN VOID                     *Context
    363   )
    364 {
    365   NVME_BLKIO2_SUBTASK         *Subtask;
    366   NVME_BLKIO2_REQUEST         *Request;
    367   NVME_CQ                     *Completion;
    368   EFI_BLOCK_IO2_TOKEN         *Token;
    369 
    370   gBS->CloseEvent (Event);
    371 
    372   Subtask    = (NVME_BLKIO2_SUBTASK *) Context;
    373   Completion = (NVME_CQ *) Subtask->CommandPacket->NvmeCompletion;
    374   Request    = Subtask->BlockIo2Request;
    375   Token      = Request->Token;
    376 
    377   if (Token->TransactionStatus == EFI_SUCCESS) {
    378     //
    379     // If previous subtask already fails, do not check the result of
    380     // subsequent subtasks.
    381     //
    382     if ((Completion->Sct != 0) || (Completion->Sc != 0)) {
    383       Token->TransactionStatus = EFI_DEVICE_ERROR;
    384 
    385       //
    386       // Dump completion entry status for debugging.
    387       //
    388       DEBUG_CODE_BEGIN();
    389         NvmeDumpStatus (Completion);
    390       DEBUG_CODE_END();
    391     }
    392   }
    393 
    394   //
    395   // Remove the subtask from the BlockIo2 subtasks list.
    396   //
    397   RemoveEntryList (&Subtask->Link);
    398 
    399   if (IsListEmpty (&Request->SubtasksQueue) && Request->LastSubtaskSubmitted) {
    400     //
    401     // Remove the BlockIo2 request from the device asynchronous queue.
    402     //
    403     RemoveEntryList (&Request->Link);
    404     FreePool (Request);
    405     gBS->SignalEvent (Token->Event);
    406   }
    407 
    408   FreePool (Subtask->CommandPacket->NvmeCmd);
    409   FreePool (Subtask->CommandPacket->NvmeCompletion);
    410   FreePool (Subtask->CommandPacket);
    411   FreePool (Subtask);
    412 }
    413 
    414 /**
    415   Read some sectors from the device in an asynchronous manner.
    416 
    417   @param  Device        The pointer to the NVME_DEVICE_PRIVATE_DATA data
    418                         structure.
    419   @param  Request       The pointer to the NVME_BLKIO2_REQUEST data structure.
    420   @param  Buffer        The buffer used to store the data read from the device.
    421   @param  Lba           The start block number.
    422   @param  Blocks        Total block number to be read.
    423   @param  IsLast        The last subtask of an asynchronous read request.
    424 
    425   @retval EFI_SUCCESS   Asynchronous read request has been queued.
    426   @retval Others        Fail to send the asynchronous request.
    427 
    428 **/
    429 EFI_STATUS
    430 AsyncReadSectors (
    431   IN NVME_DEVICE_PRIVATE_DATA           *Device,
    432   IN NVME_BLKIO2_REQUEST                *Request,
    433   IN UINT64                             Buffer,
    434   IN UINT64                             Lba,
    435   IN UINT32                             Blocks,
    436   IN BOOLEAN                            IsLast
    437   )
    438 {
    439   NVME_CONTROLLER_PRIVATE_DATA             *Private;
    440   UINT32                                   Bytes;
    441   NVME_BLKIO2_SUBTASK                      *Subtask;
    442   EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *CommandPacket;
    443   EFI_NVM_EXPRESS_COMMAND                  *Command;
    444   EFI_NVM_EXPRESS_COMPLETION               *Completion;
    445   EFI_STATUS                               Status;
    446   UINT32                                   BlockSize;
    447   EFI_TPL                                  OldTpl;
    448 
    449   Private       = Device->Controller;
    450   BlockSize     = Device->Media.BlockSize;
    451   Bytes         = Blocks * BlockSize;
    452   CommandPacket = NULL;
    453   Command       = NULL;
    454   Completion    = NULL;
    455 
    456   Subtask = AllocateZeroPool (sizeof (NVME_BLKIO2_SUBTASK));
    457   if (Subtask == NULL) {
    458     Status = EFI_OUT_OF_RESOURCES;
    459     goto ErrorExit;
    460   }
    461 
    462   Subtask->Signature       = NVME_BLKIO2_SUBTASK_SIGNATURE;
    463   Subtask->IsLast          = IsLast;
    464   Subtask->NamespaceId     = Device->NamespaceId;
    465   Subtask->BlockIo2Request = Request;
    466 
    467   CommandPacket = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
    468   if (CommandPacket == NULL) {
    469     Status = EFI_OUT_OF_RESOURCES;
    470     goto ErrorExit;
    471   } else {
    472     Subtask->CommandPacket = CommandPacket;
    473   }
    474 
    475   Command = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMMAND));
    476   if (Command == NULL) {
    477     Status = EFI_OUT_OF_RESOURCES;
    478     goto ErrorExit;
    479   }
    480 
    481   Completion = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMPLETION));
    482   if (Completion == NULL) {
    483     Status = EFI_OUT_OF_RESOURCES;
    484     goto ErrorExit;
    485   }
    486 
    487   //
    488   // Create Event
    489   //
    490   Status = gBS->CreateEvent (
    491                   EVT_NOTIFY_SIGNAL,
    492                   TPL_NOTIFY,
    493                   AsyncIoCallback,
    494                   Subtask,
    495                   &Subtask->Event
    496                   );
    497   if (EFI_ERROR(Status)) {
    498     goto ErrorExit;
    499   }
    500 
    501   CommandPacket->NvmeCmd        = Command;
    502   CommandPacket->NvmeCompletion = Completion;
    503 
    504   CommandPacket->NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;
    505   CommandPacket->NvmeCmd->Nsid        = Device->NamespaceId;
    506   CommandPacket->TransferBuffer       = (VOID *)(UINTN)Buffer;
    507 
    508   CommandPacket->TransferLength = Bytes;
    509   CommandPacket->CommandTimeout = NVME_GENERIC_TIMEOUT;
    510   CommandPacket->QueueType      = NVME_IO_QUEUE;
    511 
    512   CommandPacket->NvmeCmd->Cdw10 = (UINT32)Lba;
    513   CommandPacket->NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
    514   CommandPacket->NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
    515 
    516   CommandPacket->NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
    517 
    518   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    519   InsertTailList (&Private->UnsubmittedSubtasks, &Subtask->Link);
    520   Request->UnsubmittedSubtaskNum++;
    521   gBS->RestoreTPL (OldTpl);
    522 
    523   return EFI_SUCCESS;
    524 
    525 ErrorExit:
    526   //
    527   // Resource cleanup if asynchronous read request has not been queued.
    528   //
    529   if (Completion != NULL) {
    530     FreePool (Completion);
    531   }
    532 
    533   if (Command != NULL) {
    534     FreePool (Command);
    535   }
    536 
    537   if (CommandPacket != NULL) {
    538     FreePool (CommandPacket);
    539   }
    540 
    541   if (Subtask != NULL) {
    542     if (Subtask->Event != NULL) {
    543       gBS->CloseEvent (Subtask->Event);
    544     }
    545 
    546     FreePool (Subtask);
    547   }
    548 
    549   return Status;
    550 }
    551 
    552 /**
    553   Write some sectors from the device in an asynchronous manner.
    554 
    555   @param  Device        The pointer to the NVME_DEVICE_PRIVATE_DATA data
    556                         structure.
    557   @param  Request       The pointer to the NVME_BLKIO2_REQUEST data structure.
    558   @param  Buffer        The buffer used to store the data written to the
    559                         device.
    560   @param  Lba           The start block number.
    561   @param  Blocks        Total block number to be written.
    562   @param  IsLast        The last subtask of an asynchronous write request.
    563 
    564   @retval EFI_SUCCESS   Asynchronous write request has been queued.
    565   @retval Others        Fail to send the asynchronous request.
    566 
    567 **/
    568 EFI_STATUS
    569 AsyncWriteSectors (
    570   IN NVME_DEVICE_PRIVATE_DATA           *Device,
    571   IN NVME_BLKIO2_REQUEST                *Request,
    572   IN UINT64                             Buffer,
    573   IN UINT64                             Lba,
    574   IN UINT32                             Blocks,
    575   IN BOOLEAN                            IsLast
    576   )
    577 {
    578   NVME_CONTROLLER_PRIVATE_DATA             *Private;
    579   UINT32                                   Bytes;
    580   NVME_BLKIO2_SUBTASK                      *Subtask;
    581   EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *CommandPacket;
    582   EFI_NVM_EXPRESS_COMMAND                  *Command;
    583   EFI_NVM_EXPRESS_COMPLETION               *Completion;
    584   EFI_STATUS                               Status;
    585   UINT32                                   BlockSize;
    586   EFI_TPL                                  OldTpl;
    587 
    588   Private       = Device->Controller;
    589   BlockSize     = Device->Media.BlockSize;
    590   Bytes         = Blocks * BlockSize;
    591   CommandPacket = NULL;
    592   Command       = NULL;
    593   Completion    = NULL;
    594 
    595   Subtask = AllocateZeroPool (sizeof (NVME_BLKIO2_SUBTASK));
    596   if (Subtask == NULL) {
    597     Status = EFI_OUT_OF_RESOURCES;
    598     goto ErrorExit;
    599   }
    600 
    601   Subtask->Signature       = NVME_BLKIO2_SUBTASK_SIGNATURE;
    602   Subtask->IsLast          = IsLast;
    603   Subtask->NamespaceId     = Device->NamespaceId;
    604   Subtask->BlockIo2Request = Request;
    605 
    606   CommandPacket = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
    607   if (CommandPacket == NULL) {
    608     Status = EFI_OUT_OF_RESOURCES;
    609     goto ErrorExit;
    610   } else {
    611     Subtask->CommandPacket = CommandPacket;
    612   }
    613 
    614   Command = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMMAND));
    615   if (Command == NULL) {
    616     Status = EFI_OUT_OF_RESOURCES;
    617     goto ErrorExit;
    618   }
    619 
    620   Completion = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMPLETION));
    621   if (Completion == NULL) {
    622     Status = EFI_OUT_OF_RESOURCES;
    623     goto ErrorExit;
    624   }
    625 
    626   //
    627   // Create Event
    628   //
    629   Status = gBS->CreateEvent (
    630                   EVT_NOTIFY_SIGNAL,
    631                   TPL_NOTIFY,
    632                   AsyncIoCallback,
    633                   Subtask,
    634                   &Subtask->Event
    635                   );
    636   if (EFI_ERROR(Status)) {
    637     goto ErrorExit;
    638   }
    639 
    640   CommandPacket->NvmeCmd        = Command;
    641   CommandPacket->NvmeCompletion = Completion;
    642 
    643   CommandPacket->NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;
    644   CommandPacket->NvmeCmd->Nsid        = Device->NamespaceId;
    645   CommandPacket->TransferBuffer       = (VOID *)(UINTN)Buffer;
    646 
    647   CommandPacket->TransferLength = Bytes;
    648   CommandPacket->CommandTimeout = NVME_GENERIC_TIMEOUT;
    649   CommandPacket->QueueType      = NVME_IO_QUEUE;
    650 
    651   CommandPacket->NvmeCmd->Cdw10 = (UINT32)Lba;
    652   CommandPacket->NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
    653   //
    654   // Set Force Unit Access bit (bit 30) to use write-through behaviour
    655   //
    656   CommandPacket->NvmeCmd->Cdw12 = ((Blocks - 1) & 0xFFFF) | BIT30;
    657 
    658   CommandPacket->NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
    659 
    660   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    661   InsertTailList (&Private->UnsubmittedSubtasks, &Subtask->Link);
    662   Request->UnsubmittedSubtaskNum++;
    663   gBS->RestoreTPL (OldTpl);
    664 
    665   return EFI_SUCCESS;
    666 
    667 ErrorExit:
    668   //
    669   // Resource cleanup if asynchronous read request has not been queued.
    670   //
    671   if (Completion != NULL) {
    672     FreePool (Completion);
    673   }
    674 
    675   if (Command != NULL) {
    676     FreePool (Command);
    677   }
    678 
    679   if (CommandPacket != NULL) {
    680     FreePool (CommandPacket);
    681   }
    682 
    683   if (Subtask != NULL) {
    684     if (Subtask->Event != NULL) {
    685       gBS->CloseEvent (Subtask->Event);
    686     }
    687 
    688     FreePool (Subtask);
    689   }
    690 
    691   return Status;
    692 }
    693 
    694 /**
    695   Read some blocks from the device in an asynchronous manner.
    696 
    697   @param  Device        The pointer to the NVME_DEVICE_PRIVATE_DATA data
    698                         structure.
    699   @param  Buffer        The buffer used to store the data read from the device.
    700   @param  Lba           The start block number.
    701   @param  Blocks        Total block number to be read.
    702   @param  Token         A pointer to the token associated with the transaction.
    703 
    704   @retval EFI_SUCCESS   Data are read from the device.
    705   @retval Others        Fail to read all the data.
    706 
    707 **/
    708 EFI_STATUS
    709 NvmeAsyncRead (
    710   IN     NVME_DEVICE_PRIVATE_DATA       *Device,
    711      OUT VOID                           *Buffer,
    712   IN     UINT64                         Lba,
    713   IN     UINTN                          Blocks,
    714   IN     EFI_BLOCK_IO2_TOKEN            *Token
    715   )
    716 {
    717   EFI_STATUS                       Status;
    718   UINT32                           BlockSize;
    719   NVME_CONTROLLER_PRIVATE_DATA     *Private;
    720   NVME_BLKIO2_REQUEST              *BlkIo2Req;
    721   UINT32                           MaxTransferBlocks;
    722   UINTN                            OrginalBlocks;
    723   BOOLEAN                          IsEmpty;
    724   EFI_TPL                          OldTpl;
    725 
    726   Status        = EFI_SUCCESS;
    727   Private       = Device->Controller;
    728   BlockSize     = Device->Media.BlockSize;
    729   OrginalBlocks = Blocks;
    730   BlkIo2Req     = AllocateZeroPool (sizeof (NVME_BLKIO2_REQUEST));
    731   if (BlkIo2Req == NULL) {
    732     return EFI_OUT_OF_RESOURCES;
    733   }
    734 
    735   BlkIo2Req->Signature = NVME_BLKIO2_REQUEST_SIGNATURE;
    736   BlkIo2Req->Token     = Token;
    737 
    738   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    739   InsertTailList (&Device->AsyncQueue, &BlkIo2Req->Link);
    740   gBS->RestoreTPL (OldTpl);
    741 
    742   InitializeListHead (&BlkIo2Req->SubtasksQueue);
    743 
    744   if (Private->ControllerData->Mdts != 0) {
    745     MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
    746   } else {
    747     MaxTransferBlocks = 1024;
    748   }
    749 
    750   while (Blocks > 0) {
    751     if (Blocks > MaxTransferBlocks) {
    752       Status = AsyncReadSectors (
    753                  Device,
    754                  BlkIo2Req, (UINT64)(UINTN)Buffer,
    755                  Lba,
    756                  MaxTransferBlocks,
    757                  FALSE
    758                  );
    759 
    760       Blocks -= MaxTransferBlocks;
    761       Buffer  = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
    762       Lba    += MaxTransferBlocks;
    763     } else {
    764       Status = AsyncReadSectors (
    765                  Device,
    766                  BlkIo2Req,
    767                  (UINT64)(UINTN)Buffer,
    768                  Lba,
    769                  (UINT32)Blocks,
    770                  TRUE
    771                  );
    772 
    773       Blocks = 0;
    774     }
    775 
    776     if (EFI_ERROR(Status)) {
    777       OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
    778       IsEmpty = IsListEmpty (&BlkIo2Req->SubtasksQueue) &&
    779                 (BlkIo2Req->UnsubmittedSubtaskNum == 0);
    780 
    781       if (IsEmpty) {
    782         //
    783         // Remove the BlockIo2 request from the device asynchronous queue.
    784         //
    785         RemoveEntryList (&BlkIo2Req->Link);
    786         FreePool (BlkIo2Req);
    787         Status = EFI_DEVICE_ERROR;
    788       } else {
    789         //
    790         // There are previous BlockIo2 subtasks still running, EFI_SUCCESS
    791         // should be returned to make sure that the caller does not free
    792         // resources still using by these requests.
    793         //
    794         Status = EFI_SUCCESS;
    795         Token->TransactionStatus = EFI_DEVICE_ERROR;
    796         BlkIo2Req->LastSubtaskSubmitted = TRUE;
    797       }
    798 
    799       gBS->RestoreTPL (OldTpl);
    800 
    801       break;
    802     }
    803   }
    804 
    805   DEBUG ((EFI_D_VERBOSE, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
    806     "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
    807     (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
    808 
    809   return Status;
    810 }
    811 
    812 /**
    813   Write some blocks from the device in an asynchronous manner.
    814 
    815   @param  Device        The pointer to the NVME_DEVICE_PRIVATE_DATA data
    816                         structure.
    817   @param  Buffer        The buffer used to store the data written to the
    818                         device.
    819   @param  Lba           The start block number.
    820   @param  Blocks        Total block number to be written.
    821   @param  Token         A pointer to the token associated with the transaction.
    822 
    823   @retval EFI_SUCCESS   Data are written to the device.
    824   @retval Others        Fail to write all the data.
    825 
    826 **/
    827 EFI_STATUS
    828 NvmeAsyncWrite (
    829   IN NVME_DEVICE_PRIVATE_DATA           *Device,
    830   IN VOID                               *Buffer,
    831   IN UINT64                             Lba,
    832   IN UINTN                              Blocks,
    833   IN EFI_BLOCK_IO2_TOKEN                *Token
    834   )
    835 {
    836   EFI_STATUS                       Status;
    837   UINT32                           BlockSize;
    838   NVME_CONTROLLER_PRIVATE_DATA     *Private;
    839   NVME_BLKIO2_REQUEST              *BlkIo2Req;
    840   UINT32                           MaxTransferBlocks;
    841   UINTN                            OrginalBlocks;
    842   BOOLEAN                          IsEmpty;
    843   EFI_TPL                          OldTpl;
    844 
    845   Status        = EFI_SUCCESS;
    846   Private       = Device->Controller;
    847   BlockSize     = Device->Media.BlockSize;
    848   OrginalBlocks = Blocks;
    849   BlkIo2Req     = AllocateZeroPool (sizeof (NVME_BLKIO2_REQUEST));
    850   if (BlkIo2Req == NULL) {
    851     return EFI_OUT_OF_RESOURCES;
    852   }
    853 
    854   BlkIo2Req->Signature = NVME_BLKIO2_REQUEST_SIGNATURE;
    855   BlkIo2Req->Token     = Token;
    856 
    857   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
    858   InsertTailList (&Device->AsyncQueue, &BlkIo2Req->Link);
    859   gBS->RestoreTPL (OldTpl);
    860 
    861   InitializeListHead (&BlkIo2Req->SubtasksQueue);
    862 
    863   if (Private->ControllerData->Mdts != 0) {
    864     MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
    865   } else {
    866     MaxTransferBlocks = 1024;
    867   }
    868 
    869   while (Blocks > 0) {
    870     if (Blocks > MaxTransferBlocks) {
    871       Status  = AsyncWriteSectors (
    872                   Device,
    873                   BlkIo2Req,
    874                   (UINT64)(UINTN)Buffer,
    875                   Lba,
    876                   MaxTransferBlocks,
    877                   FALSE
    878                   );
    879 
    880       Blocks -= MaxTransferBlocks;
    881       Buffer  = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
    882       Lba    += MaxTransferBlocks;
    883     } else {
    884       Status = AsyncWriteSectors (
    885                  Device,
    886                  BlkIo2Req,
    887                  (UINT64)(UINTN)Buffer,
    888                  Lba,
    889                  (UINT32)Blocks,
    890                  TRUE
    891                  );
    892 
    893       Blocks = 0;
    894     }
    895 
    896     if (EFI_ERROR(Status)) {
    897       OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
    898       IsEmpty = IsListEmpty (&BlkIo2Req->SubtasksQueue) &&
    899                 (BlkIo2Req->UnsubmittedSubtaskNum == 0);
    900 
    901       if (IsEmpty) {
    902         //
    903         // Remove the BlockIo2 request from the device asynchronous queue.
    904         //
    905         RemoveEntryList (&BlkIo2Req->Link);
    906         FreePool (BlkIo2Req);
    907         Status = EFI_DEVICE_ERROR;
    908       } else {
    909         //
    910         // There are previous BlockIo2 subtasks still running, EFI_SUCCESS
    911         // should be returned to make sure that the caller does not free
    912         // resources still using by these requests.
    913         //
    914         Status = EFI_SUCCESS;
    915         Token->TransactionStatus = EFI_DEVICE_ERROR;
    916         BlkIo2Req->LastSubtaskSubmitted = TRUE;
    917       }
    918 
    919       gBS->RestoreTPL (OldTpl);
    920 
    921       break;
    922     }
    923   }
    924 
    925   DEBUG ((EFI_D_VERBOSE, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
    926     "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
    927     (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
    928 
    929   return Status;
    930 }
    931 
    932 /**
    933   Reset the Block Device.
    934 
    935   @param  This                 Indicates a pointer to the calling context.
    936   @param  ExtendedVerification Driver may perform diagnostics on reset.
    937 
    938   @retval EFI_SUCCESS          The device was reset.
    939   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
    940                                not be reset.
    941 
    942 **/
    943 EFI_STATUS
    944 EFIAPI
    945 NvmeBlockIoReset (
    946   IN  EFI_BLOCK_IO_PROTOCOL   *This,
    947   IN  BOOLEAN                 ExtendedVerification
    948   )
    949 {
    950   EFI_TPL                         OldTpl;
    951   NVME_CONTROLLER_PRIVATE_DATA    *Private;
    952   NVME_DEVICE_PRIVATE_DATA        *Device;
    953   EFI_STATUS                      Status;
    954 
    955   if (This == NULL) {
    956     return EFI_INVALID_PARAMETER;
    957   }
    958 
    959   //
    960   // For Nvm Express subsystem, reset block device means reset controller.
    961   //
    962   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
    963 
    964   Device  = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
    965 
    966   Private = Device->Controller;
    967 
    968   Status  = NvmeControllerInit (Private);
    969 
    970   if (EFI_ERROR (Status)) {
    971     Status = EFI_DEVICE_ERROR;
    972   }
    973 
    974   gBS->RestoreTPL (OldTpl);
    975 
    976   return Status;
    977 }
    978 
    979 /**
    980   Read BufferSize bytes from Lba into Buffer.
    981 
    982   @param  This       Indicates a pointer to the calling context.
    983   @param  MediaId    Id of the media, changes every time the media is replaced.
    984   @param  Lba        The starting Logical Block Address to read from.
    985   @param  BufferSize Size of Buffer, must be a multiple of device block size.
    986   @param  Buffer     A pointer to the destination buffer for the data. The caller is
    987                      responsible for either having implicit or explicit ownership of the buffer.
    988 
    989   @retval EFI_SUCCESS           The data was read correctly from the device.
    990   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
    991   @retval EFI_NO_MEDIA          There is no media in the device.
    992   @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
    993   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    994   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
    995                                 or the buffer is not on proper alignment.
    996 
    997 **/
    998 EFI_STATUS
    999 EFIAPI
   1000 NvmeBlockIoReadBlocks (
   1001   IN  EFI_BLOCK_IO_PROTOCOL   *This,
   1002   IN  UINT32                  MediaId,
   1003   IN  EFI_LBA                 Lba,
   1004   IN  UINTN                   BufferSize,
   1005   OUT VOID                    *Buffer
   1006   )
   1007 {
   1008   NVME_DEVICE_PRIVATE_DATA          *Device;
   1009   EFI_STATUS                        Status;
   1010   EFI_BLOCK_IO_MEDIA                *Media;
   1011   UINTN                             BlockSize;
   1012   UINTN                             NumberOfBlocks;
   1013   UINTN                             IoAlign;
   1014   EFI_TPL                           OldTpl;
   1015 
   1016   //
   1017   // Check parameters.
   1018   //
   1019   if (This == NULL) {
   1020     return EFI_INVALID_PARAMETER;
   1021   }
   1022 
   1023   Media = This->Media;
   1024 
   1025   if (MediaId != Media->MediaId) {
   1026     return EFI_MEDIA_CHANGED;
   1027   }
   1028 
   1029   if (Buffer == NULL) {
   1030     return EFI_INVALID_PARAMETER;
   1031   }
   1032 
   1033   if (BufferSize == 0) {
   1034     return EFI_SUCCESS;
   1035   }
   1036 
   1037   BlockSize = Media->BlockSize;
   1038   if ((BufferSize % BlockSize) != 0) {
   1039     return EFI_BAD_BUFFER_SIZE;
   1040   }
   1041 
   1042   NumberOfBlocks  = BufferSize / BlockSize;
   1043   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
   1044     return EFI_INVALID_PARAMETER;
   1045   }
   1046 
   1047   IoAlign = Media->IoAlign;
   1048   if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
   1049     return EFI_INVALID_PARAMETER;
   1050   }
   1051 
   1052   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1053 
   1054   Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
   1055 
   1056   Status = NvmeRead (Device, Buffer, Lba, NumberOfBlocks);
   1057 
   1058   gBS->RestoreTPL (OldTpl);
   1059   return Status;
   1060 }
   1061 
   1062 /**
   1063   Write BufferSize bytes from Lba into Buffer.
   1064 
   1065   @param  This       Indicates a pointer to the calling context.
   1066   @param  MediaId    The media ID that the write request is for.
   1067   @param  Lba        The starting logical block address to be written. The caller is
   1068                      responsible for writing to only legitimate locations.
   1069   @param  BufferSize Size of Buffer, must be a multiple of device block size.
   1070   @param  Buffer     A pointer to the source buffer for the data.
   1071 
   1072   @retval EFI_SUCCESS           The data was written correctly to the device.
   1073   @retval EFI_WRITE_PROTECTED   The device can not be written to.
   1074   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
   1075   @retval EFI_NO_MEDIA          There is no media in the device.
   1076   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
   1077   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
   1078   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
   1079                                 or the buffer is not on proper alignment.
   1080 
   1081 **/
   1082 EFI_STATUS
   1083 EFIAPI
   1084 NvmeBlockIoWriteBlocks (
   1085   IN  EFI_BLOCK_IO_PROTOCOL   *This,
   1086   IN  UINT32                  MediaId,
   1087   IN  EFI_LBA                 Lba,
   1088   IN  UINTN                   BufferSize,
   1089   IN  VOID                    *Buffer
   1090   )
   1091 {
   1092   NVME_DEVICE_PRIVATE_DATA          *Device;
   1093   EFI_STATUS                        Status;
   1094   EFI_BLOCK_IO_MEDIA                *Media;
   1095   UINTN                             BlockSize;
   1096   UINTN                             NumberOfBlocks;
   1097   UINTN                             IoAlign;
   1098   EFI_TPL                           OldTpl;
   1099 
   1100   //
   1101   // Check parameters.
   1102   //
   1103   if (This == NULL) {
   1104     return EFI_INVALID_PARAMETER;
   1105   }
   1106 
   1107   Media = This->Media;
   1108 
   1109   if (MediaId != Media->MediaId) {
   1110     return EFI_MEDIA_CHANGED;
   1111   }
   1112 
   1113   if (Buffer == NULL) {
   1114     return EFI_INVALID_PARAMETER;
   1115   }
   1116 
   1117   if (BufferSize == 0) {
   1118     return EFI_SUCCESS;
   1119   }
   1120 
   1121   BlockSize = Media->BlockSize;
   1122   if ((BufferSize % BlockSize) != 0) {
   1123     return EFI_BAD_BUFFER_SIZE;
   1124   }
   1125 
   1126   NumberOfBlocks  = BufferSize / BlockSize;
   1127   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
   1128     return EFI_INVALID_PARAMETER;
   1129   }
   1130 
   1131   IoAlign = Media->IoAlign;
   1132   if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
   1133     return EFI_INVALID_PARAMETER;
   1134   }
   1135 
   1136   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1137 
   1138   Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
   1139 
   1140   Status = NvmeWrite (Device, Buffer, Lba, NumberOfBlocks);
   1141 
   1142   gBS->RestoreTPL (OldTpl);
   1143 
   1144   return Status;
   1145 }
   1146 
   1147 /**
   1148   Flush the Block Device.
   1149 
   1150   @param  This              Indicates a pointer to the calling context.
   1151 
   1152   @retval EFI_SUCCESS       All outstanding data was written to the device.
   1153   @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data.
   1154   @retval EFI_NO_MEDIA      There is no media in the device.
   1155 
   1156 **/
   1157 EFI_STATUS
   1158 EFIAPI
   1159 NvmeBlockIoFlushBlocks (
   1160   IN  EFI_BLOCK_IO_PROTOCOL   *This
   1161   )
   1162 {
   1163   NVME_DEVICE_PRIVATE_DATA          *Device;
   1164   EFI_STATUS                        Status;
   1165   EFI_TPL                           OldTpl;
   1166 
   1167   //
   1168   // Check parameters.
   1169   //
   1170   if (This == NULL) {
   1171     return EFI_INVALID_PARAMETER;
   1172   }
   1173 
   1174   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1175 
   1176   Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
   1177 
   1178   Status = NvmeFlush (Device);
   1179 
   1180   gBS->RestoreTPL (OldTpl);
   1181 
   1182   return Status;
   1183 }
   1184 
   1185 /**
   1186   Reset the block device hardware.
   1187 
   1188   @param[in]  This                 Indicates a pointer to the calling context.
   1189   @param[in]  ExtendedVerification Indicates that the driver may perform a more
   1190                                    exhausive verfication operation of the
   1191                                    device during reset.
   1192 
   1193   @retval EFI_SUCCESS          The device was reset.
   1194   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
   1195                                not be reset.
   1196 
   1197 **/
   1198 EFI_STATUS
   1199 EFIAPI
   1200 NvmeBlockIoResetEx (
   1201   IN EFI_BLOCK_IO2_PROTOCOL  *This,
   1202   IN BOOLEAN                 ExtendedVerification
   1203   )
   1204 {
   1205   EFI_STATUS                      Status;
   1206   NVME_DEVICE_PRIVATE_DATA        *Device;
   1207   NVME_CONTROLLER_PRIVATE_DATA    *Private;
   1208   BOOLEAN                         IsEmpty;
   1209   EFI_TPL                         OldTpl;
   1210 
   1211   if (This == NULL) {
   1212     return EFI_INVALID_PARAMETER;
   1213   }
   1214 
   1215   Device  = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
   1216   Private = Device->Controller;
   1217 
   1218   //
   1219   // Wait for the asynchronous PassThru queue to become empty.
   1220   //
   1221   while (TRUE) {
   1222     OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
   1223     IsEmpty = IsListEmpty (&Private->AsyncPassThruQueue) &&
   1224               IsListEmpty (&Private->UnsubmittedSubtasks);
   1225     gBS->RestoreTPL (OldTpl);
   1226 
   1227     if (IsEmpty) {
   1228       break;
   1229     }
   1230 
   1231     gBS->Stall (100);
   1232   }
   1233 
   1234   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1235 
   1236   Status  = NvmeControllerInit (Private);
   1237 
   1238   if (EFI_ERROR (Status)) {
   1239     Status = EFI_DEVICE_ERROR;
   1240   }
   1241 
   1242   gBS->RestoreTPL (OldTpl);
   1243 
   1244   return Status;
   1245 }
   1246 
   1247 /**
   1248   Read BufferSize bytes from Lba into Buffer.
   1249 
   1250   This function reads the requested number of blocks from the device. All the
   1251   blocks are read, or an error is returned.
   1252   If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
   1253   non-blocking I/O is being used, the Event associated with this request will
   1254   not be signaled.
   1255 
   1256   @param[in]       This       Indicates a pointer to the calling context.
   1257   @param[in]       MediaId    Id of the media, changes every time the media is
   1258                               replaced.
   1259   @param[in]       Lba        The starting Logical Block Address to read from.
   1260   @param[in, out]  Token      A pointer to the token associated with the
   1261                               transaction.
   1262   @param[in]       BufferSize Size of Buffer, must be a multiple of device
   1263                               block size.
   1264   @param[out]      Buffer     A pointer to the destination buffer for the data.
   1265                               The caller is responsible for either having
   1266                               implicit or explicit ownership of the buffer.
   1267 
   1268   @retval EFI_SUCCESS           The read request was queued if Token->Event is
   1269                                 not NULL.The data was read correctly from the
   1270                                 device if the Token->Event is NULL.
   1271   @retval EFI_DEVICE_ERROR      The device reported an error while performing
   1272                                 the read.
   1273   @retval EFI_NO_MEDIA          There is no media in the device.
   1274   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
   1275   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of
   1276                                 the intrinsic block size of the device.
   1277   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
   1278                                 valid, or the buffer is not on proper
   1279                                 alignment.
   1280   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
   1281                                 lack of resources.
   1282 
   1283 **/
   1284 EFI_STATUS
   1285 EFIAPI
   1286 NvmeBlockIoReadBlocksEx (
   1287   IN     EFI_BLOCK_IO2_PROTOCOL *This,
   1288   IN     UINT32                 MediaId,
   1289   IN     EFI_LBA                Lba,
   1290   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
   1291   IN     UINTN                  BufferSize,
   1292      OUT VOID                  *Buffer
   1293   )
   1294 {
   1295   NVME_DEVICE_PRIVATE_DATA        *Device;
   1296   EFI_STATUS                      Status;
   1297   EFI_BLOCK_IO_MEDIA              *Media;
   1298   UINTN                           BlockSize;
   1299   UINTN                           NumberOfBlocks;
   1300   UINTN                           IoAlign;
   1301   EFI_TPL                         OldTpl;
   1302 
   1303   //
   1304   // Check parameters.
   1305   //
   1306   if (This == NULL) {
   1307     return EFI_INVALID_PARAMETER;
   1308   }
   1309 
   1310   Media = This->Media;
   1311 
   1312   if (MediaId != Media->MediaId) {
   1313     return EFI_MEDIA_CHANGED;
   1314   }
   1315 
   1316   if (Buffer == NULL) {
   1317     return EFI_INVALID_PARAMETER;
   1318   }
   1319 
   1320   if (BufferSize == 0) {
   1321     if ((Token != NULL) && (Token->Event != NULL)) {
   1322       Token->TransactionStatus = EFI_SUCCESS;
   1323       gBS->SignalEvent (Token->Event);
   1324     }
   1325     return EFI_SUCCESS;
   1326   }
   1327 
   1328   BlockSize = Media->BlockSize;
   1329   if ((BufferSize % BlockSize) != 0) {
   1330     return EFI_BAD_BUFFER_SIZE;
   1331   }
   1332 
   1333   NumberOfBlocks  = BufferSize / BlockSize;
   1334   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
   1335     return EFI_INVALID_PARAMETER;
   1336   }
   1337 
   1338   IoAlign = Media->IoAlign;
   1339   if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
   1340     return EFI_INVALID_PARAMETER;
   1341   }
   1342 
   1343   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1344 
   1345   Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
   1346 
   1347   if ((Token != NULL) && (Token->Event != NULL)) {
   1348     Token->TransactionStatus = EFI_SUCCESS;
   1349     Status = NvmeAsyncRead (Device, Buffer, Lba, NumberOfBlocks, Token);
   1350   } else {
   1351     Status = NvmeRead (Device, Buffer, Lba, NumberOfBlocks);
   1352   }
   1353 
   1354   gBS->RestoreTPL (OldTpl);
   1355   return Status;
   1356 }
   1357 
   1358 /**
   1359   Write BufferSize bytes from Lba into Buffer.
   1360 
   1361   This function writes the requested number of blocks to the device. All blocks
   1362   are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
   1363   EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
   1364   being used, the Event associated with this request will not be signaled.
   1365 
   1366   @param[in]       This       Indicates a pointer to the calling context.
   1367   @param[in]       MediaId    The media ID that the write request is for.
   1368   @param[in]       Lba        The starting logical block address to be written.
   1369                               The caller is responsible for writing to only
   1370                               legitimate locations.
   1371   @param[in, out]  Token      A pointer to the token associated with the
   1372                               transaction.
   1373   @param[in]       BufferSize Size of Buffer, must be a multiple of device
   1374                               block size.
   1375   @param[in]       Buffer     A pointer to the source buffer for the data.
   1376 
   1377   @retval EFI_SUCCESS           The write request was queued if Event is not
   1378                                 NULL.
   1379                                 The data was written correctly to the device if
   1380                                 the Event is NULL.
   1381   @retval EFI_WRITE_PROTECTED   The device can not be written to.
   1382   @retval EFI_NO_MEDIA          There is no media in the device.
   1383   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current
   1384                                 device.
   1385   @retval EFI_DEVICE_ERROR      The device reported an error while performing
   1386                                 the write.
   1387   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size
   1388                                 of the device.
   1389   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
   1390                                 valid, or the buffer is not on proper
   1391                                 alignment.
   1392   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
   1393                                 lack of resources.
   1394 
   1395 **/
   1396 EFI_STATUS
   1397 EFIAPI
   1398 NvmeBlockIoWriteBlocksEx (
   1399   IN     EFI_BLOCK_IO2_PROTOCOL  *This,
   1400   IN     UINT32                 MediaId,
   1401   IN     EFI_LBA                Lba,
   1402   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
   1403   IN     UINTN                  BufferSize,
   1404   IN     VOID                   *Buffer
   1405   )
   1406 {
   1407   NVME_DEVICE_PRIVATE_DATA        *Device;
   1408   EFI_STATUS                      Status;
   1409   EFI_BLOCK_IO_MEDIA              *Media;
   1410   UINTN                           BlockSize;
   1411   UINTN                           NumberOfBlocks;
   1412   UINTN                           IoAlign;
   1413   EFI_TPL                         OldTpl;
   1414 
   1415   //
   1416   // Check parameters.
   1417   //
   1418   if (This == NULL) {
   1419     return EFI_INVALID_PARAMETER;
   1420   }
   1421 
   1422   Media = This->Media;
   1423 
   1424   if (MediaId != Media->MediaId) {
   1425     return EFI_MEDIA_CHANGED;
   1426   }
   1427 
   1428   if (Buffer == NULL) {
   1429     return EFI_INVALID_PARAMETER;
   1430   }
   1431 
   1432   if (BufferSize == 0) {
   1433     if ((Token != NULL) && (Token->Event != NULL)) {
   1434       Token->TransactionStatus = EFI_SUCCESS;
   1435       gBS->SignalEvent (Token->Event);
   1436     }
   1437     return EFI_SUCCESS;
   1438   }
   1439 
   1440   BlockSize = Media->BlockSize;
   1441   if ((BufferSize % BlockSize) != 0) {
   1442     return EFI_BAD_BUFFER_SIZE;
   1443   }
   1444 
   1445   NumberOfBlocks  = BufferSize / BlockSize;
   1446   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
   1447     return EFI_INVALID_PARAMETER;
   1448   }
   1449 
   1450   IoAlign = Media->IoAlign;
   1451   if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
   1452     return EFI_INVALID_PARAMETER;
   1453   }
   1454 
   1455   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1456 
   1457   Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
   1458 
   1459   if ((Token != NULL) && (Token->Event != NULL)) {
   1460     Token->TransactionStatus = EFI_SUCCESS;
   1461     Status = NvmeAsyncWrite (Device, Buffer, Lba, NumberOfBlocks, Token);
   1462   } else {
   1463     Status = NvmeWrite (Device, Buffer, Lba, NumberOfBlocks);
   1464   }
   1465 
   1466   gBS->RestoreTPL (OldTpl);
   1467   return Status;
   1468 }
   1469 
   1470 /**
   1471   Flush the Block Device.
   1472 
   1473   If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
   1474   is returned and non-blocking I/O is being used, the Event associated with
   1475   this request will not be signaled.
   1476 
   1477   @param[in]      This     Indicates a pointer to the calling context.
   1478   @param[in,out]  Token    A pointer to the token associated with the
   1479                            transaction.
   1480 
   1481   @retval EFI_SUCCESS          The flush request was queued if Event is not
   1482                                NULL.
   1483                                All outstanding data was written correctly to
   1484                                the device if the Event is NULL.
   1485   @retval EFI_DEVICE_ERROR     The device reported an error while writting back
   1486                                the data.
   1487   @retval EFI_WRITE_PROTECTED  The device cannot be written to.
   1488   @retval EFI_NO_MEDIA         There is no media in the device.
   1489   @retval EFI_MEDIA_CHANGED    The MediaId is not for the current media.
   1490   @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
   1491                                of resources.
   1492 
   1493 **/
   1494 EFI_STATUS
   1495 EFIAPI
   1496 NvmeBlockIoFlushBlocksEx (
   1497   IN     EFI_BLOCK_IO2_PROTOCOL   *This,
   1498   IN OUT EFI_BLOCK_IO2_TOKEN      *Token
   1499   )
   1500 {
   1501   NVME_DEVICE_PRIVATE_DATA        *Device;
   1502   BOOLEAN                         IsEmpty;
   1503   EFI_TPL                         OldTpl;
   1504 
   1505   //
   1506   // Check parameters.
   1507   //
   1508   if (This == NULL) {
   1509     return EFI_INVALID_PARAMETER;
   1510   }
   1511 
   1512   Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
   1513 
   1514   //
   1515   // Wait for the asynchronous I/O queue to become empty.
   1516   //
   1517   while (TRUE) {
   1518     OldTpl  = gBS->RaiseTPL (TPL_NOTIFY);
   1519     IsEmpty = IsListEmpty (&Device->AsyncQueue);
   1520     gBS->RestoreTPL (OldTpl);
   1521 
   1522     if (IsEmpty) {
   1523       break;
   1524     }
   1525 
   1526     gBS->Stall (100);
   1527   }
   1528 
   1529   //
   1530   // Signal caller event
   1531   //
   1532   if ((Token != NULL) && (Token->Event != NULL)) {
   1533     Token->TransactionStatus = EFI_SUCCESS;
   1534     gBS->SignalEvent (Token->Event);
   1535   }
   1536 
   1537   return EFI_SUCCESS;
   1538 }
   1539 
   1540 /**
   1541   Trust transfer data from/to NVMe device.
   1542 
   1543   This function performs one NVMe transaction to do a trust transfer from/to NVMe device.
   1544 
   1545   @param  Private                      The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
   1546   @param  Buffer                       The pointer to the current transaction buffer.
   1547   @param  SecurityProtocolId           The value of the "Security Protocol" parameter of
   1548                                        the security protocol command to be sent.
   1549   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
   1550                                        of the security protocol command to be sent.
   1551   @param  TransferLength               The block number or sector count of the transfer.
   1552   @param  IsTrustSend                  Indicates whether it is a trust send operation or not.
   1553   @param  Timeout                      The timeout, in 100ns units, to use for the execution
   1554                                        of the security protocol command. A Timeout value of 0
   1555                                        means that this function will wait indefinitely for the
   1556                                        security protocol command to execute. If Timeout is greater
   1557                                        than zero, then this function will return EFI_TIMEOUT
   1558                                        if the time required to execute the receive data command
   1559                                        is greater than Timeout.
   1560   @param  TransferLengthOut            A pointer to a buffer to store the size in bytes of the data
   1561                                        written to the buffer. Ignore it when IsTrustSend is TRUE.
   1562 
   1563   @retval EFI_SUCCESS       The data transfer is complete successfully.
   1564   @return others            Some error occurs when transferring data.
   1565 
   1566 **/
   1567 EFI_STATUS
   1568 TrustTransferNvmeDevice (
   1569   IN OUT NVME_CONTROLLER_PRIVATE_DATA      *Private,
   1570   IN OUT VOID                              *Buffer,
   1571   IN UINT8                                 SecurityProtocolId,
   1572   IN UINT16                                SecurityProtocolSpecificData,
   1573   IN UINTN                                 TransferLength,
   1574   IN BOOLEAN                               IsTrustSend,
   1575   IN UINT64                                Timeout,
   1576   OUT UINTN                                *TransferLengthOut
   1577   )
   1578 {
   1579   EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
   1580   EFI_NVM_EXPRESS_COMMAND                  Command;
   1581   EFI_NVM_EXPRESS_COMPLETION               Completion;
   1582   EFI_STATUS                               Status;
   1583   UINT16                                   SpecificData;
   1584 
   1585   ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
   1586   ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
   1587   ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
   1588 
   1589   CommandPacket.NvmeCmd        = &Command;
   1590   CommandPacket.NvmeCompletion = &Completion;
   1591 
   1592   //
   1593   // Change Endianness of SecurityProtocolSpecificData
   1594   //
   1595   SpecificData = (((SecurityProtocolSpecificData << 8) & 0xFF00) | (SecurityProtocolSpecificData >> 8));
   1596 
   1597   if (IsTrustSend) {
   1598     Command.Cdw0.Opcode          = NVME_ADMIN_SECURITY_SEND_CMD;
   1599     CommandPacket.TransferBuffer = Buffer;
   1600     CommandPacket.TransferLength = (UINT32)TransferLength;
   1601     CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
   1602     CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
   1603   } else {
   1604     Command.Cdw0.Opcode          = NVME_ADMIN_SECURITY_RECEIVE_CMD;
   1605     CommandPacket.TransferBuffer = Buffer;
   1606     CommandPacket.TransferLength = (UINT32)TransferLength;
   1607     CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
   1608     CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
   1609   }
   1610 
   1611   CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
   1612   CommandPacket.NvmeCmd->Nsid  = NVME_CONTROLLER_ID;
   1613   CommandPacket.CommandTimeout = Timeout;
   1614   CommandPacket.QueueType      = NVME_ADMIN_QUEUE;
   1615 
   1616   Status = Private->Passthru.PassThru (
   1617                                &Private->Passthru,
   1618                                NVME_CONTROLLER_ID,
   1619                                &CommandPacket,
   1620                                NULL
   1621                                );
   1622 
   1623   if (!IsTrustSend) {
   1624     if (EFI_ERROR (Status))  {
   1625       *TransferLengthOut = 0;
   1626     } else {
   1627       *TransferLengthOut = (UINTN) TransferLength;
   1628     }
   1629   }
   1630 
   1631   return Status;
   1632 }
   1633 
   1634 /**
   1635   Send a security protocol command to a device that receives data and/or the result
   1636   of one or more commands sent by SendData.
   1637 
   1638   The ReceiveData function sends a security protocol command to the given MediaId.
   1639   The security protocol command sent is defined by SecurityProtocolId and contains
   1640   the security protocol specific data SecurityProtocolSpecificData. The function
   1641   returns the data from the security protocol command in PayloadBuffer.
   1642 
   1643   For devices supporting the SCSI command set, the security protocol command is sent
   1644   using the SECURITY PROTOCOL IN command defined in SPC-4.
   1645 
   1646   For devices supporting the ATA command set, the security protocol command is sent
   1647   using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
   1648   is non-zero.
   1649 
   1650   If the PayloadBufferSize is zero, the security protocol command is sent using the
   1651   Trusted Non-Data command defined in ATA8-ACS.
   1652 
   1653   If PayloadBufferSize is too small to store the available data from the security
   1654   protocol command, the function shall copy PayloadBufferSize bytes into the
   1655   PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
   1656 
   1657   If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
   1658   the function shall return EFI_INVALID_PARAMETER.
   1659 
   1660   If the given MediaId does not support security protocol commands, the function shall
   1661   return EFI_UNSUPPORTED. If there is no media in the device, the function returns
   1662   EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
   1663   the function returns EFI_MEDIA_CHANGED.
   1664 
   1665   If the security protocol fails to complete within the Timeout period, the function
   1666   shall return EFI_TIMEOUT.
   1667 
   1668   If the security protocol command completes without an error, the function shall
   1669   return EFI_SUCCESS. If the security protocol command completes with an error, the
   1670   function shall return EFI_DEVICE_ERROR.
   1671 
   1672   @param  This                         Indicates a pointer to the calling context.
   1673   @param  MediaId                      ID of the medium to receive data from.
   1674   @param  Timeout                      The timeout, in 100ns units, to use for the execution
   1675                                        of the security protocol command. A Timeout value of 0
   1676                                        means that this function will wait indefinitely for the
   1677                                        security protocol command to execute. If Timeout is greater
   1678                                        than zero, then this function will return EFI_TIMEOUT
   1679                                        if the time required to execute the receive data command
   1680                                        is greater than Timeout.
   1681   @param  SecurityProtocolId           The value of the "Security Protocol" parameter of
   1682                                        the security protocol command to be sent.
   1683   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
   1684                                        of the security protocol command to be sent.
   1685   @param  PayloadBufferSize            Size in bytes of the payload data buffer.
   1686   @param  PayloadBuffer                A pointer to a destination buffer to store the security
   1687                                        protocol command specific payload data for the security
   1688                                        protocol command. The caller is responsible for having
   1689                                        either implicit or explicit ownership of the buffer.
   1690   @param  PayloadTransferSize          A pointer to a buffer to store the size in bytes of the
   1691                                        data written to the payload data buffer.
   1692 
   1693   @retval EFI_SUCCESS                  The security protocol command completed successfully.
   1694   @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to store the available
   1695                                        data from the device. The PayloadBuffer contains the truncated data.
   1696   @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.
   1697   @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.
   1698   @retval EFI_NO_MEDIA                 There is no media in the device.
   1699   @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.
   1700   @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize is NULL and
   1701                                        PayloadBufferSize is non-zero.
   1702   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security
   1703                                        protocol command to execute.
   1704 
   1705 **/
   1706 EFI_STATUS
   1707 EFIAPI
   1708 NvmeStorageSecurityReceiveData (
   1709   IN  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
   1710   IN  UINT32                                   MediaId,
   1711   IN  UINT64                                   Timeout,
   1712   IN  UINT8                                    SecurityProtocolId,
   1713   IN  UINT16                                   SecurityProtocolSpecificData,
   1714   IN  UINTN                                    PayloadBufferSize,
   1715   OUT VOID                                     *PayloadBuffer,
   1716   OUT UINTN                                    *PayloadTransferSize
   1717   )
   1718 {
   1719   EFI_STATUS                       Status;
   1720   NVME_DEVICE_PRIVATE_DATA         *Device;
   1721 
   1722   Status  = EFI_SUCCESS;
   1723 
   1724   if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {
   1725     return EFI_INVALID_PARAMETER;
   1726   }
   1727 
   1728   Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This);
   1729 
   1730   if (MediaId != Device->BlockIo.Media->MediaId) {
   1731     return EFI_MEDIA_CHANGED;
   1732   }
   1733 
   1734   if (!Device->BlockIo.Media->MediaPresent) {
   1735     return EFI_NO_MEDIA;
   1736   }
   1737 
   1738   Status = TrustTransferNvmeDevice (
   1739              Device->Controller,
   1740              PayloadBuffer,
   1741              SecurityProtocolId,
   1742              SecurityProtocolSpecificData,
   1743              PayloadBufferSize,
   1744              FALSE,
   1745              Timeout,
   1746              PayloadTransferSize
   1747              );
   1748 
   1749   return Status;
   1750 }
   1751 
   1752 /**
   1753   Send a security protocol command to a device.
   1754 
   1755   The SendData function sends a security protocol command containing the payload
   1756   PayloadBuffer to the given MediaId. The security protocol command sent is
   1757   defined by SecurityProtocolId and contains the security protocol specific data
   1758   SecurityProtocolSpecificData. If the underlying protocol command requires a
   1759   specific padding for the command payload, the SendData function shall add padding
   1760   bytes to the command payload to satisfy the padding requirements.
   1761 
   1762   For devices supporting the SCSI command set, the security protocol command is sent
   1763   using the SECURITY PROTOCOL OUT command defined in SPC-4.
   1764 
   1765   For devices supporting the ATA command set, the security protocol command is sent
   1766   using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
   1767   is non-zero. If the PayloadBufferSize is zero, the security protocol command is
   1768   sent using the Trusted Non-Data command defined in ATA8-ACS.
   1769 
   1770   If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
   1771   return EFI_INVALID_PARAMETER.
   1772 
   1773   If the given MediaId does not support security protocol commands, the function
   1774   shall return EFI_UNSUPPORTED. If there is no media in the device, the function
   1775   returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
   1776   device, the function returns EFI_MEDIA_CHANGED.
   1777 
   1778   If the security protocol fails to complete within the Timeout period, the function
   1779   shall return EFI_TIMEOUT.
   1780 
   1781   If the security protocol command completes without an error, the function shall return
   1782   EFI_SUCCESS. If the security protocol command completes with an error, the function
   1783   shall return EFI_DEVICE_ERROR.
   1784 
   1785   @param  This                         Indicates a pointer to the calling context.
   1786   @param  MediaId                      ID of the medium to receive data from.
   1787   @param  Timeout                      The timeout, in 100ns units, to use for the execution
   1788                                        of the security protocol command. A Timeout value of 0
   1789                                        means that this function will wait indefinitely for the
   1790                                        security protocol command to execute. If Timeout is greater
   1791                                        than zero, then this function will return EFI_TIMEOUT
   1792                                        if the time required to execute the send data command
   1793                                        is greater than Timeout.
   1794   @param  SecurityProtocolId           The value of the "Security Protocol" parameter of
   1795                                        the security protocol command to be sent.
   1796   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
   1797                                        of the security protocol command to be sent.
   1798   @param  PayloadBufferSize            Size in bytes of the payload data buffer.
   1799   @param  PayloadBuffer                A pointer to a destination buffer to store the security
   1800                                        protocol command specific payload data for the security
   1801                                        protocol command.
   1802 
   1803   @retval EFI_SUCCESS                  The security protocol command completed successfully.
   1804   @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.
   1805   @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.
   1806   @retval EFI_NO_MEDIA                 There is no media in the device.
   1807   @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.
   1808   @retval EFI_INVALID_PARAMETER        The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
   1809   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security
   1810                                        protocol command to execute.
   1811 
   1812 **/
   1813 EFI_STATUS
   1814 EFIAPI
   1815 NvmeStorageSecuritySendData (
   1816   IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
   1817   IN UINT32                                   MediaId,
   1818   IN UINT64                                   Timeout,
   1819   IN UINT8                                    SecurityProtocolId,
   1820   IN UINT16                                   SecurityProtocolSpecificData,
   1821   IN UINTN                                    PayloadBufferSize,
   1822   IN VOID                                     *PayloadBuffer
   1823   )
   1824 {
   1825   EFI_STATUS                       Status;
   1826   NVME_DEVICE_PRIVATE_DATA         *Device;
   1827 
   1828   Status  = EFI_SUCCESS;
   1829 
   1830   if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
   1831     return EFI_INVALID_PARAMETER;
   1832   }
   1833 
   1834   Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This);
   1835 
   1836   if (MediaId != Device->BlockIo.Media->MediaId) {
   1837     return EFI_MEDIA_CHANGED;
   1838   }
   1839 
   1840   if (!Device->BlockIo.Media->MediaPresent) {
   1841     return EFI_NO_MEDIA;
   1842   }
   1843 
   1844   Status = TrustTransferNvmeDevice (
   1845              Device->Controller,
   1846              PayloadBuffer,
   1847              SecurityProtocolId,
   1848              SecurityProtocolSpecificData,
   1849              PayloadBufferSize,
   1850              TRUE,
   1851              Timeout,
   1852              NULL
   1853              );
   1854 
   1855   return Status;
   1856 }
   1857 
   1858 
   1859 
   1860 
   1861