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