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   CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
    131 
    132   CommandPacket.MetadataBuffer = NULL;
    133   CommandPacket.MetadataLength = 0;
    134 
    135   CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
    136 
    137   Status = Private->Passthru.PassThru (
    138                                &Private->Passthru,
    139                                Device->NamespaceId,
    140                                &CommandPacket,
    141                                NULL
    142                                );
    143 
    144   return Status;
    145 }
    146 
    147 /**
    148   Read some blocks from the device.
    149 
    150   @param  Device                 The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
    151   @param  Buffer                 The buffer used to store the data read from the device.
    152   @param  Lba                    The start block number.
    153   @param  Blocks                 Total block number to be read.
    154 
    155   @retval EFI_SUCCESS            Datum are read from the device.
    156   @retval Others                 Fail to read all the datum.
    157 
    158 **/
    159 EFI_STATUS
    160 NvmeRead (
    161   IN     NVME_DEVICE_PRIVATE_DATA       *Device,
    162      OUT VOID                           *Buffer,
    163   IN     UINT64                         Lba,
    164   IN     UINTN                          Blocks
    165   )
    166 {
    167   EFI_STATUS                       Status;
    168   UINT32                           BlockSize;
    169   NVME_CONTROLLER_PRIVATE_DATA     *Private;
    170   UINT32                           MaxTransferBlocks;
    171   UINTN                            OrginalBlocks;
    172 
    173   Status        = EFI_SUCCESS;
    174   Private       = Device->Controller;
    175   BlockSize     = Device->Media.BlockSize;
    176   OrginalBlocks = Blocks;
    177 
    178   if (Private->ControllerData->Mdts != 0) {
    179     MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
    180   } else {
    181     MaxTransferBlocks = 1024;
    182   }
    183 
    184   while (Blocks > 0) {
    185     if (Blocks > MaxTransferBlocks) {
    186       Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);
    187 
    188       Blocks -= MaxTransferBlocks;
    189       Buffer  = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
    190       Lba    += MaxTransferBlocks;
    191     } else {
    192       Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);
    193       Blocks = 0;
    194     }
    195 
    196     if (EFI_ERROR(Status)) {
    197       break;
    198     }
    199   }
    200 
    201   DEBUG ((EFI_D_INFO, "NvmeRead()  Lba = 0x%08x, Original = 0x%08x, Remaining = 0x%08x, BlockSize = 0x%x Status = %r\n", Lba, OrginalBlocks, Blocks, BlockSize, Status));
    202 
    203   return Status;
    204 }
    205 
    206 /**
    207   Write some blocks to the device.
    208 
    209   @param  Device                 The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
    210   @param  Buffer                 The buffer to be written into the device.
    211   @param  Lba                    The start block number.
    212   @param  Blocks                 Total block number to be written.
    213 
    214   @retval EFI_SUCCESS            Datum are written into the buffer.
    215   @retval Others                 Fail to write all the datum.
    216 
    217 **/
    218 EFI_STATUS
    219 NvmeWrite (
    220   IN NVME_DEVICE_PRIVATE_DATA           *Device,
    221   IN VOID                               *Buffer,
    222   IN UINT64                             Lba,
    223   IN UINTN                              Blocks
    224   )
    225 {
    226   EFI_STATUS                       Status;
    227   UINT32                           BlockSize;
    228   NVME_CONTROLLER_PRIVATE_DATA     *Private;
    229   UINT32                           MaxTransferBlocks;
    230   UINTN                            OrginalBlocks;
    231 
    232   Status        = EFI_SUCCESS;
    233   Private       = Device->Controller;
    234   BlockSize     = Device->Media.BlockSize;
    235   OrginalBlocks = Blocks;
    236 
    237   if (Private->ControllerData->Mdts != 0) {
    238     MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
    239   } else {
    240     MaxTransferBlocks = 1024;
    241   }
    242 
    243   while (Blocks > 0) {
    244     if (Blocks > MaxTransferBlocks) {
    245       Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);
    246 
    247       Blocks -= MaxTransferBlocks;
    248       Buffer  = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
    249       Lba    += MaxTransferBlocks;
    250     } else {
    251       Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);
    252       Blocks = 0;
    253     }
    254 
    255     if (EFI_ERROR(Status)) {
    256       break;
    257     }
    258   }
    259 
    260   DEBUG ((EFI_D_INFO, "NvmeWrite() Lba = 0x%08x, Original = 0x%08x, Remaining = 0x%08x, BlockSize = 0x%x Status = %r\n", Lba, OrginalBlocks, Blocks, BlockSize, Status));
    261 
    262   return Status;
    263 }
    264 
    265 /**
    266   Flushes all modified data to the device.
    267 
    268   @param  Device                 The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
    269 
    270   @retval EFI_SUCCESS            Datum are written into the buffer.
    271   @retval Others                 Fail to write all the datum.
    272 
    273 **/
    274 EFI_STATUS
    275 NvmeFlush (
    276   IN NVME_DEVICE_PRIVATE_DATA      *Device
    277   )
    278 {
    279   NVME_CONTROLLER_PRIVATE_DATA             *Private;
    280   EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
    281   EFI_NVM_EXPRESS_COMMAND                  Command;
    282   EFI_NVM_EXPRESS_COMPLETION               Completion;
    283   EFI_STATUS                               Status;
    284 
    285   Private = Device->Controller;
    286 
    287   ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
    288   ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
    289   ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
    290 
    291   CommandPacket.NvmeCmd        = &Command;
    292   CommandPacket.NvmeCompletion = &Completion;
    293 
    294   CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_FLUSH_OPC;
    295   CommandPacket.NvmeCmd->Nsid  = Device->NamespaceId;
    296   CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
    297   CommandPacket.QueueType      = NVME_IO_QUEUE;
    298 
    299   Status = Private->Passthru.PassThru (
    300                                &Private->Passthru,
    301                                Device->NamespaceId,
    302                                &CommandPacket,
    303                                NULL
    304                                );
    305 
    306   return Status;
    307 }
    308 
    309 
    310 /**
    311   Reset the Block Device.
    312 
    313   @param  This                 Indicates a pointer to the calling context.
    314   @param  ExtendedVerification Driver may perform diagnostics on reset.
    315 
    316   @retval EFI_SUCCESS          The device was reset.
    317   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
    318                                not be reset.
    319 
    320 **/
    321 EFI_STATUS
    322 EFIAPI
    323 NvmeBlockIoReset (
    324   IN  EFI_BLOCK_IO_PROTOCOL   *This,
    325   IN  BOOLEAN                 ExtendedVerification
    326   )
    327 {
    328   EFI_TPL                         OldTpl;
    329   NVME_CONTROLLER_PRIVATE_DATA    *Private;
    330   NVME_DEVICE_PRIVATE_DATA        *Device;
    331   EFI_STATUS                      Status;
    332 
    333   if (This == NULL) {
    334     return EFI_INVALID_PARAMETER;
    335   }
    336 
    337   //
    338   // For Nvm Express subsystem, reset block device means reset controller.
    339   //
    340   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
    341 
    342   Device  = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
    343 
    344   Private = Device->Controller;
    345 
    346   Status  = NvmeControllerInit (Private);
    347 
    348   if (EFI_ERROR (Status)) {
    349     Status = EFI_DEVICE_ERROR;
    350   }
    351 
    352   gBS->RestoreTPL (OldTpl);
    353 
    354   return Status;
    355 }
    356 
    357 /**
    358   Read BufferSize bytes from Lba into Buffer.
    359 
    360   @param  This       Indicates a pointer to the calling context.
    361   @param  MediaId    Id of the media, changes every time the media is replaced.
    362   @param  Lba        The starting Logical Block Address to read from.
    363   @param  BufferSize Size of Buffer, must be a multiple of device block size.
    364   @param  Buffer     A pointer to the destination buffer for the data. The caller is
    365                      responsible for either having implicit or explicit ownership of the buffer.
    366 
    367   @retval EFI_SUCCESS           The data was read correctly from the device.
    368   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
    369   @retval EFI_NO_MEDIA          There is no media in the device.
    370   @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
    371   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    372   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
    373                                 or the buffer is not on proper alignment.
    374 
    375 **/
    376 EFI_STATUS
    377 EFIAPI
    378 NvmeBlockIoReadBlocks (
    379   IN  EFI_BLOCK_IO_PROTOCOL   *This,
    380   IN  UINT32                  MediaId,
    381   IN  EFI_LBA                 Lba,
    382   IN  UINTN                   BufferSize,
    383   OUT VOID                    *Buffer
    384   )
    385 {
    386   NVME_DEVICE_PRIVATE_DATA          *Device;
    387   EFI_STATUS                        Status;
    388   EFI_BLOCK_IO_MEDIA                *Media;
    389   UINTN                             BlockSize;
    390   UINTN                             NumberOfBlocks;
    391   UINTN                             IoAlign;
    392   EFI_TPL                           OldTpl;
    393 
    394   //
    395   // Check parameters.
    396   //
    397   if (This == NULL) {
    398     return EFI_INVALID_PARAMETER;
    399   }
    400 
    401   Media = This->Media;
    402 
    403   if (MediaId != Media->MediaId) {
    404     return EFI_MEDIA_CHANGED;
    405   }
    406 
    407   if (Buffer == NULL) {
    408     return EFI_INVALID_PARAMETER;
    409   }
    410 
    411   if (BufferSize == 0) {
    412     return EFI_SUCCESS;
    413   }
    414 
    415   BlockSize = Media->BlockSize;
    416   if ((BufferSize % BlockSize) != 0) {
    417     return EFI_BAD_BUFFER_SIZE;
    418   }
    419 
    420   NumberOfBlocks  = BufferSize / BlockSize;
    421   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
    422     return EFI_INVALID_PARAMETER;
    423   }
    424 
    425   IoAlign = Media->IoAlign;
    426   if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
    427     return EFI_INVALID_PARAMETER;
    428   }
    429 
    430   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    431 
    432   Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
    433 
    434   Status = NvmeRead (Device, Buffer, Lba, NumberOfBlocks);
    435 
    436   gBS->RestoreTPL (OldTpl);
    437   return Status;
    438 }
    439 
    440 /**
    441   Write BufferSize bytes from Lba into Buffer.
    442 
    443   @param  This       Indicates a pointer to the calling context.
    444   @param  MediaId    The media ID that the write request is for.
    445   @param  Lba        The starting logical block address to be written. The caller is
    446                      responsible for writing to only legitimate locations.
    447   @param  BufferSize Size of Buffer, must be a multiple of device block size.
    448   @param  Buffer     A pointer to the source buffer for the data.
    449 
    450   @retval EFI_SUCCESS           The data was written correctly to the device.
    451   @retval EFI_WRITE_PROTECTED   The device can not be written to.
    452   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
    453   @retval EFI_NO_MEDIA          There is no media in the device.
    454   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
    455   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    456   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
    457                                 or the buffer is not on proper alignment.
    458 
    459 **/
    460 EFI_STATUS
    461 EFIAPI
    462 NvmeBlockIoWriteBlocks (
    463   IN  EFI_BLOCK_IO_PROTOCOL   *This,
    464   IN  UINT32                  MediaId,
    465   IN  EFI_LBA                 Lba,
    466   IN  UINTN                   BufferSize,
    467   IN  VOID                    *Buffer
    468   )
    469 {
    470   NVME_DEVICE_PRIVATE_DATA          *Device;
    471   EFI_STATUS                        Status;
    472   EFI_BLOCK_IO_MEDIA                *Media;
    473   UINTN                             BlockSize;
    474   UINTN                             NumberOfBlocks;
    475   UINTN                             IoAlign;
    476   EFI_TPL                           OldTpl;
    477 
    478   //
    479   // Check parameters.
    480   //
    481   if (This == NULL) {
    482     return EFI_INVALID_PARAMETER;
    483   }
    484 
    485   Media = This->Media;
    486 
    487   if (MediaId != Media->MediaId) {
    488     return EFI_MEDIA_CHANGED;
    489   }
    490 
    491   if (Buffer == NULL) {
    492     return EFI_INVALID_PARAMETER;
    493   }
    494 
    495   if (BufferSize == 0) {
    496     return EFI_SUCCESS;
    497   }
    498 
    499   BlockSize = Media->BlockSize;
    500   if ((BufferSize % BlockSize) != 0) {
    501     return EFI_BAD_BUFFER_SIZE;
    502   }
    503 
    504   NumberOfBlocks  = BufferSize / BlockSize;
    505   if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
    506     return EFI_INVALID_PARAMETER;
    507   }
    508 
    509   IoAlign = Media->IoAlign;
    510   if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
    511     return EFI_INVALID_PARAMETER;
    512   }
    513 
    514   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    515 
    516   Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
    517 
    518   Status = NvmeWrite (Device, Buffer, Lba, NumberOfBlocks);
    519 
    520   gBS->RestoreTPL (OldTpl);
    521 
    522   return Status;
    523 }
    524 
    525 /**
    526   Flush the Block Device.
    527 
    528   @param  This              Indicates a pointer to the calling context.
    529 
    530   @retval EFI_SUCCESS       All outstanding data was written to the device.
    531   @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data.
    532   @retval EFI_NO_MEDIA      There is no media in the device.
    533 
    534 **/
    535 EFI_STATUS
    536 EFIAPI
    537 NvmeBlockIoFlushBlocks (
    538   IN  EFI_BLOCK_IO_PROTOCOL   *This
    539   )
    540 {
    541   NVME_DEVICE_PRIVATE_DATA          *Device;
    542   EFI_STATUS                        Status;
    543   EFI_TPL                           OldTpl;
    544 
    545   //
    546   // Check parameters.
    547   //
    548   if (This == NULL) {
    549     return EFI_INVALID_PARAMETER;
    550   }
    551 
    552   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    553 
    554   Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
    555 
    556   Status = NvmeFlush (Device);
    557 
    558   gBS->RestoreTPL (OldTpl);
    559 
    560   return Status;
    561 }
    562 
    563 /**
    564   Trust transfer data from/to NVMe device.
    565 
    566   This function performs one NVMe transaction to do a trust transfer from/to NVMe device.
    567 
    568   @param  Private                      The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
    569   @param  Buffer                       The pointer to the current transaction buffer.
    570   @param  SecurityProtocolId           The value of the "Security Protocol" parameter of
    571                                        the security protocol command to be sent.
    572   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
    573                                        of the security protocol command to be sent.
    574   @param  TransferLength               The block number or sector count of the transfer.
    575   @param  IsTrustSend                  Indicates whether it is a trust send operation or not.
    576   @param  Timeout                      The timeout, in 100ns units, to use for the execution
    577                                        of the security protocol command. A Timeout value of 0
    578                                        means that this function will wait indefinitely for the
    579                                        security protocol command to execute. If Timeout is greater
    580                                        than zero, then this function will return EFI_TIMEOUT
    581                                        if the time required to execute the receive data command
    582                                        is greater than Timeout.
    583   @param  TransferLengthOut            A pointer to a buffer to store the size in bytes of the data
    584                                        written to the buffer. Ignore it when IsTrustSend is TRUE.
    585 
    586   @retval EFI_SUCCESS       The data transfer is complete successfully.
    587   @return others            Some error occurs when transferring data.
    588 
    589 **/
    590 EFI_STATUS
    591 TrustTransferNvmeDevice (
    592   IN OUT NVME_CONTROLLER_PRIVATE_DATA      *Private,
    593   IN OUT VOID                              *Buffer,
    594   IN UINT8                                 SecurityProtocolId,
    595   IN UINT16                                SecurityProtocolSpecificData,
    596   IN UINTN                                 TransferLength,
    597   IN BOOLEAN                               IsTrustSend,
    598   IN UINT64                                Timeout,
    599   OUT UINTN                                *TransferLengthOut
    600   )
    601 {
    602   EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
    603   EFI_NVM_EXPRESS_COMMAND                  Command;
    604   EFI_NVM_EXPRESS_COMPLETION               Completion;
    605   EFI_STATUS                               Status;
    606   UINT16                                   SpecificData;
    607 
    608   ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
    609   ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
    610   ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
    611 
    612   CommandPacket.NvmeCmd        = &Command;
    613   CommandPacket.NvmeCompletion = &Completion;
    614 
    615   //
    616   // Change Endianness of SecurityProtocolSpecificData
    617   //
    618   SpecificData = (((SecurityProtocolSpecificData << 8) & 0xFF00) | (SecurityProtocolSpecificData >> 8));
    619 
    620   if (IsTrustSend) {
    621     Command.Cdw0.Opcode          = NVME_ADMIN_SECURITY_SEND_CMD;
    622     CommandPacket.TransferBuffer = Buffer;
    623     CommandPacket.TransferLength = (UINT32)TransferLength;
    624     CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
    625     CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
    626   } else {
    627     Command.Cdw0.Opcode          = NVME_ADMIN_SECURITY_RECEIVE_CMD;
    628     CommandPacket.TransferBuffer = Buffer;
    629     CommandPacket.TransferLength = (UINT32)TransferLength;
    630     CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
    631     CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
    632   }
    633 
    634   CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
    635   CommandPacket.NvmeCmd->Nsid  = NVME_CONTROLLER_ID;
    636   CommandPacket.CommandTimeout = Timeout;
    637   CommandPacket.QueueType      = NVME_ADMIN_QUEUE;
    638 
    639   Status = Private->Passthru.PassThru (
    640                                &Private->Passthru,
    641                                NVME_CONTROLLER_ID,
    642                                &CommandPacket,
    643                                NULL
    644                                );
    645 
    646   if (!IsTrustSend) {
    647     if (EFI_ERROR (Status))  {
    648       *TransferLengthOut = 0;
    649     } else {
    650       *TransferLengthOut = (UINTN) TransferLength;
    651     }
    652   }
    653 
    654   return Status;
    655 }
    656 
    657 /**
    658   Send a security protocol command to a device that receives data and/or the result
    659   of one or more commands sent by SendData.
    660 
    661   The ReceiveData function sends a security protocol command to the given MediaId.
    662   The security protocol command sent is defined by SecurityProtocolId and contains
    663   the security protocol specific data SecurityProtocolSpecificData. The function
    664   returns the data from the security protocol command in PayloadBuffer.
    665 
    666   For devices supporting the SCSI command set, the security protocol command is sent
    667   using the SECURITY PROTOCOL IN command defined in SPC-4.
    668 
    669   For devices supporting the ATA command set, the security protocol command is sent
    670   using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
    671   is non-zero.
    672 
    673   If the PayloadBufferSize is zero, the security protocol command is sent using the
    674   Trusted Non-Data command defined in ATA8-ACS.
    675 
    676   If PayloadBufferSize is too small to store the available data from the security
    677   protocol command, the function shall copy PayloadBufferSize bytes into the
    678   PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
    679 
    680   If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
    681   the function shall return EFI_INVALID_PARAMETER.
    682 
    683   If the given MediaId does not support security protocol commands, the function shall
    684   return EFI_UNSUPPORTED. If there is no media in the device, the function returns
    685   EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
    686   the function returns EFI_MEDIA_CHANGED.
    687 
    688   If the security protocol fails to complete within the Timeout period, the function
    689   shall return EFI_TIMEOUT.
    690 
    691   If the security protocol command completes without an error, the function shall
    692   return EFI_SUCCESS. If the security protocol command completes with an error, the
    693   function shall return EFI_DEVICE_ERROR.
    694 
    695   @param  This                         Indicates a pointer to the calling context.
    696   @param  MediaId                      ID of the medium to receive data from.
    697   @param  Timeout                      The timeout, in 100ns units, to use for the execution
    698                                        of the security protocol command. A Timeout value of 0
    699                                        means that this function will wait indefinitely for the
    700                                        security protocol command to execute. If Timeout is greater
    701                                        than zero, then this function will return EFI_TIMEOUT
    702                                        if the time required to execute the receive data command
    703                                        is greater than Timeout.
    704   @param  SecurityProtocolId           The value of the "Security Protocol" parameter of
    705                                        the security protocol command to be sent.
    706   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
    707                                        of the security protocol command to be sent.
    708   @param  PayloadBufferSize            Size in bytes of the payload data buffer.
    709   @param  PayloadBuffer                A pointer to a destination buffer to store the security
    710                                        protocol command specific payload data for the security
    711                                        protocol command. The caller is responsible for having
    712                                        either implicit or explicit ownership of the buffer.
    713   @param  PayloadTransferSize          A pointer to a buffer to store the size in bytes of the
    714                                        data written to the payload data buffer.
    715 
    716   @retval EFI_SUCCESS                  The security protocol command completed successfully.
    717   @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to store the available
    718                                        data from the device. The PayloadBuffer contains the truncated data.
    719   @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.
    720   @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.
    721   @retval EFI_NO_MEDIA                 There is no media in the device.
    722   @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.
    723   @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize is NULL and
    724                                        PayloadBufferSize is non-zero.
    725   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security
    726                                        protocol command to execute.
    727 
    728 **/
    729 EFI_STATUS
    730 EFIAPI
    731 NvmeStorageSecurityReceiveData (
    732   IN  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
    733   IN  UINT32                                   MediaId,
    734   IN  UINT64                                   Timeout,
    735   IN  UINT8                                    SecurityProtocolId,
    736   IN  UINT16                                   SecurityProtocolSpecificData,
    737   IN  UINTN                                    PayloadBufferSize,
    738   OUT VOID                                     *PayloadBuffer,
    739   OUT UINTN                                    *PayloadTransferSize
    740   )
    741 {
    742   EFI_STATUS                       Status;
    743   NVME_DEVICE_PRIVATE_DATA         *Device;
    744 
    745   Status  = EFI_SUCCESS;
    746 
    747   if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {
    748     return EFI_INVALID_PARAMETER;
    749   }
    750 
    751   Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This);
    752 
    753   if (MediaId != Device->BlockIo.Media->MediaId) {
    754     return EFI_MEDIA_CHANGED;
    755   }
    756 
    757   if (!Device->BlockIo.Media->MediaPresent) {
    758     return EFI_NO_MEDIA;
    759   }
    760 
    761   Status = TrustTransferNvmeDevice (
    762              Device->Controller,
    763              PayloadBuffer,
    764              SecurityProtocolId,
    765              SecurityProtocolSpecificData,
    766              PayloadBufferSize,
    767              FALSE,
    768              Timeout,
    769              PayloadTransferSize
    770              );
    771 
    772   return Status;
    773 }
    774 
    775 /**
    776   Send a security protocol command to a device.
    777 
    778   The SendData function sends a security protocol command containing the payload
    779   PayloadBuffer to the given MediaId. The security protocol command sent is
    780   defined by SecurityProtocolId and contains the security protocol specific data
    781   SecurityProtocolSpecificData. If the underlying protocol command requires a
    782   specific padding for the command payload, the SendData function shall add padding
    783   bytes to the command payload to satisfy the padding requirements.
    784 
    785   For devices supporting the SCSI command set, the security protocol command is sent
    786   using the SECURITY PROTOCOL OUT command defined in SPC-4.
    787 
    788   For devices supporting the ATA command set, the security protocol command is sent
    789   using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
    790   is non-zero. If the PayloadBufferSize is zero, the security protocol command is
    791   sent using the Trusted Non-Data command defined in ATA8-ACS.
    792 
    793   If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
    794   return EFI_INVALID_PARAMETER.
    795 
    796   If the given MediaId does not support security protocol commands, the function
    797   shall return EFI_UNSUPPORTED. If there is no media in the device, the function
    798   returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
    799   device, the function returns EFI_MEDIA_CHANGED.
    800 
    801   If the security protocol fails to complete within the Timeout period, the function
    802   shall return EFI_TIMEOUT.
    803 
    804   If the security protocol command completes without an error, the function shall return
    805   EFI_SUCCESS. If the security protocol command completes with an error, the function
    806   shall return EFI_DEVICE_ERROR.
    807 
    808   @param  This                         Indicates a pointer to the calling context.
    809   @param  MediaId                      ID of the medium to receive data from.
    810   @param  Timeout                      The timeout, in 100ns units, to use for the execution
    811                                        of the security protocol command. A Timeout value of 0
    812                                        means that this function will wait indefinitely for the
    813                                        security protocol command to execute. If Timeout is greater
    814                                        than zero, then this function will return EFI_TIMEOUT
    815                                        if the time required to execute the send data command
    816                                        is greater than Timeout.
    817   @param  SecurityProtocolId           The value of the "Security Protocol" parameter of
    818                                        the security protocol command to be sent.
    819   @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
    820                                        of the security protocol command to be sent.
    821   @param  PayloadBufferSize            Size in bytes of the payload data buffer.
    822   @param  PayloadBuffer                A pointer to a destination buffer to store the security
    823                                        protocol command specific payload data for the security
    824                                        protocol command.
    825 
    826   @retval EFI_SUCCESS                  The security protocol command completed successfully.
    827   @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.
    828   @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.
    829   @retval EFI_NO_MEDIA                 There is no media in the device.
    830   @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.
    831   @retval EFI_INVALID_PARAMETER        The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
    832   @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security
    833                                        protocol command to execute.
    834 
    835 **/
    836 EFI_STATUS
    837 EFIAPI
    838 NvmeStorageSecuritySendData (
    839   IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,
    840   IN UINT32                                   MediaId,
    841   IN UINT64                                   Timeout,
    842   IN UINT8                                    SecurityProtocolId,
    843   IN UINT16                                   SecurityProtocolSpecificData,
    844   IN UINTN                                    PayloadBufferSize,
    845   IN VOID                                     *PayloadBuffer
    846   )
    847 {
    848   EFI_STATUS                       Status;
    849   NVME_DEVICE_PRIVATE_DATA         *Device;
    850 
    851   Status  = EFI_SUCCESS;
    852 
    853   if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
    854     return EFI_INVALID_PARAMETER;
    855   }
    856 
    857   Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This);
    858 
    859   if (MediaId != Device->BlockIo.Media->MediaId) {
    860     return EFI_MEDIA_CHANGED;
    861   }
    862 
    863   if (!Device->BlockIo.Media->MediaPresent) {
    864     return EFI_NO_MEDIA;
    865   }
    866 
    867   Status = TrustTransferNvmeDevice (
    868              Device->Controller,
    869              PayloadBuffer,
    870              SecurityProtocolId,
    871              SecurityProtocolSpecificData,
    872              PayloadBufferSize,
    873              TRUE,
    874              Timeout,
    875              NULL
    876              );
    877 
    878   return Status;
    879 }
    880 
    881 
    882 
    883 
    884