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