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