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
ReadSectors(IN NVME_DEVICE_PRIVATE_DATA * Device,IN UINT64 Buffer,IN UINT64 Lba,IN UINT32 Blocks)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
WriteSectors(IN NVME_DEVICE_PRIVATE_DATA * Device,IN UINT64 Buffer,IN UINT64 Lba,IN UINT32 Blocks)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
NvmeRead(IN NVME_DEVICE_PRIVATE_DATA * Device,OUT VOID * Buffer,IN UINT64 Lba,IN UINTN Blocks)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
NvmeWrite(IN NVME_DEVICE_PRIVATE_DATA * Device,IN VOID * Buffer,IN UINT64 Lba,IN UINTN Blocks)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
NvmeFlush(IN NVME_DEVICE_PRIVATE_DATA * Device)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
NvmeBlockIoReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)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
NvmeBlockIoReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,OUT VOID * Buffer)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
NvmeBlockIoWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN VOID * Buffer)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
NvmeBlockIoFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)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
TrustTransferNvmeDevice(IN OUT NVME_CONTROLLER_PRIVATE_DATA * Private,IN OUT VOID * Buffer,IN UINT8 SecurityProtocolId,IN UINT16 SecurityProtocolSpecificData,IN UINTN TransferLength,IN BOOLEAN IsTrustSend,IN UINT64 Timeout,OUT UINTN * TransferLengthOut)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
NvmeStorageSecurityReceiveData(IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Timeout,IN UINT8 SecurityProtocolId,IN UINT16 SecurityProtocolSpecificData,IN UINTN PayloadBufferSize,OUT VOID * PayloadBuffer,OUT UINTN * PayloadTransferSize)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
NvmeStorageSecuritySendData(IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL * This,IN UINT32 MediaId,IN UINT64 Timeout,IN UINT8 SecurityProtocolId,IN UINT16 SecurityProtocolSpecificData,IN UINTN PayloadBufferSize,IN VOID * PayloadBuffer)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