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