]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressDxe / NvmExpressPassthru.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
35f910f0 5 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
748cd9a6 6 Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
eb290d02
FT
8\r
9**/\r
10\r
11#include "NvmExpress.h"\r
12\r
eb290d02
FT
13/**\r
14 Dump the execution status from a given completion queue entry.\r
15\r
16 @param[in] Cq A pointer to the NVME_CQ item.\r
17\r
18**/\r
19VOID\r
20NvmeDumpStatus (\r
1436aea4 21 IN NVME_CQ *Cq\r
eb290d02
FT
22 )\r
23{\r
87000d77 24 DEBUG ((DEBUG_VERBOSE, "Dump NVMe Completion Entry Status from [0x%x]:\n", Cq));\r
eb290d02 25\r
87000d77 26 DEBUG ((DEBUG_VERBOSE, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid));\r
eb290d02 27\r
87000d77 28 DEBUG ((DEBUG_VERBOSE, " NVMe Cmd Execution Result - "));\r
eb290d02
FT
29\r
30 switch (Cq->Sct) {\r
31 case 0x0:\r
32 switch (Cq->Sc) {\r
33 case 0x0:\r
87000d77 34 DEBUG ((DEBUG_VERBOSE, "Successful Completion\n"));\r
eb290d02
FT
35 break;\r
36 case 0x1:\r
87000d77 37 DEBUG ((DEBUG_VERBOSE, "Invalid Command Opcode\n"));\r
eb290d02
FT
38 break;\r
39 case 0x2:\r
87000d77 40 DEBUG ((DEBUG_VERBOSE, "Invalid Field in Command\n"));\r
eb290d02
FT
41 break;\r
42 case 0x3:\r
87000d77 43 DEBUG ((DEBUG_VERBOSE, "Command ID Conflict\n"));\r
eb290d02
FT
44 break;\r
45 case 0x4:\r
87000d77 46 DEBUG ((DEBUG_VERBOSE, "Data Transfer Error\n"));\r
eb290d02
FT
47 break;\r
48 case 0x5:\r
87000d77 49 DEBUG ((DEBUG_VERBOSE, "Commands Aborted due to Power Loss Notification\n"));\r
eb290d02
FT
50 break;\r
51 case 0x6:\r
87000d77 52 DEBUG ((DEBUG_VERBOSE, "Internal Device Error\n"));\r
eb290d02
FT
53 break;\r
54 case 0x7:\r
87000d77 55 DEBUG ((DEBUG_VERBOSE, "Command Abort Requested\n"));\r
eb290d02
FT
56 break;\r
57 case 0x8:\r
87000d77 58 DEBUG ((DEBUG_VERBOSE, "Command Aborted due to SQ Deletion\n"));\r
eb290d02
FT
59 break;\r
60 case 0x9:\r
87000d77 61 DEBUG ((DEBUG_VERBOSE, "Command Aborted due to Failed Fused Command\n"));\r
eb290d02
FT
62 break;\r
63 case 0xA:\r
87000d77 64 DEBUG ((DEBUG_VERBOSE, "Command Aborted due to Missing Fused Command\n"));\r
eb290d02
FT
65 break;\r
66 case 0xB:\r
87000d77 67 DEBUG ((DEBUG_VERBOSE, "Invalid Namespace or Format\n"));\r
eb290d02
FT
68 break;\r
69 case 0xC:\r
87000d77 70 DEBUG ((DEBUG_VERBOSE, "Command Sequence Error\n"));\r
eb290d02
FT
71 break;\r
72 case 0xD:\r
87000d77 73 DEBUG ((DEBUG_VERBOSE, "Invalid SGL Last Segment Descriptor\n"));\r
eb290d02
FT
74 break;\r
75 case 0xE:\r
87000d77 76 DEBUG ((DEBUG_VERBOSE, "Invalid Number of SGL Descriptors\n"));\r
eb290d02
FT
77 break;\r
78 case 0xF:\r
87000d77 79 DEBUG ((DEBUG_VERBOSE, "Data SGL Length Invalid\n"));\r
eb290d02
FT
80 break;\r
81 case 0x10:\r
87000d77 82 DEBUG ((DEBUG_VERBOSE, "Metadata SGL Length Invalid\n"));\r
eb290d02
FT
83 break;\r
84 case 0x11:\r
87000d77 85 DEBUG ((DEBUG_VERBOSE, "SGL Descriptor Type Invalid\n"));\r
eb290d02
FT
86 break;\r
87 case 0x80:\r
87000d77 88 DEBUG ((DEBUG_VERBOSE, "LBA Out of Range\n"));\r
eb290d02
FT
89 break;\r
90 case 0x81:\r
87000d77 91 DEBUG ((DEBUG_VERBOSE, "Capacity Exceeded\n"));\r
eb290d02
FT
92 break;\r
93 case 0x82:\r
87000d77 94 DEBUG ((DEBUG_VERBOSE, "Namespace Not Ready\n"));\r
eb290d02
FT
95 break;\r
96 case 0x83:\r
87000d77 97 DEBUG ((DEBUG_VERBOSE, "Reservation Conflict\n"));\r
eb290d02
FT
98 break;\r
99 }\r
1436aea4 100\r
eb290d02
FT
101 break;\r
102\r
103 case 0x1:\r
104 switch (Cq->Sc) {\r
105 case 0x0:\r
87000d77 106 DEBUG ((DEBUG_VERBOSE, "Completion Queue Invalid\n"));\r
eb290d02
FT
107 break;\r
108 case 0x1:\r
87000d77 109 DEBUG ((DEBUG_VERBOSE, "Invalid Queue Identifier\n"));\r
eb290d02
FT
110 break;\r
111 case 0x2:\r
87000d77 112 DEBUG ((DEBUG_VERBOSE, "Maximum Queue Size Exceeded\n"));\r
eb290d02
FT
113 break;\r
114 case 0x3:\r
87000d77 115 DEBUG ((DEBUG_VERBOSE, "Abort Command Limit Exceeded\n"));\r
eb290d02
FT
116 break;\r
117 case 0x5:\r
87000d77 118 DEBUG ((DEBUG_VERBOSE, "Asynchronous Event Request Limit Exceeded\n"));\r
eb290d02
FT
119 break;\r
120 case 0x6:\r
87000d77 121 DEBUG ((DEBUG_VERBOSE, "Invalid Firmware Slot\n"));\r
eb290d02
FT
122 break;\r
123 case 0x7:\r
87000d77 124 DEBUG ((DEBUG_VERBOSE, "Invalid Firmware Image\n"));\r
eb290d02
FT
125 break;\r
126 case 0x8:\r
87000d77 127 DEBUG ((DEBUG_VERBOSE, "Invalid Interrupt Vector\n"));\r
eb290d02
FT
128 break;\r
129 case 0x9:\r
87000d77 130 DEBUG ((DEBUG_VERBOSE, "Invalid Log Page\n"));\r
eb290d02
FT
131 break;\r
132 case 0xA:\r
87000d77 133 DEBUG ((DEBUG_VERBOSE, "Invalid Format\n"));\r
eb290d02
FT
134 break;\r
135 case 0xB:\r
87000d77 136 DEBUG ((DEBUG_VERBOSE, "Firmware Application Requires Conventional Reset\n"));\r
eb290d02
FT
137 break;\r
138 case 0xC:\r
87000d77 139 DEBUG ((DEBUG_VERBOSE, "Invalid Queue Deletion\n"));\r
eb290d02
FT
140 break;\r
141 case 0xD:\r
87000d77 142 DEBUG ((DEBUG_VERBOSE, "Feature Identifier Not Saveable\n"));\r
eb290d02
FT
143 break;\r
144 case 0xE:\r
87000d77 145 DEBUG ((DEBUG_VERBOSE, "Feature Not Changeable\n"));\r
eb290d02
FT
146 break;\r
147 case 0xF:\r
87000d77 148 DEBUG ((DEBUG_VERBOSE, "Feature Not Namespace Specific\n"));\r
eb290d02
FT
149 break;\r
150 case 0x10:\r
87000d77 151 DEBUG ((DEBUG_VERBOSE, "Firmware Application Requires NVM Subsystem Reset\n"));\r
eb290d02
FT
152 break;\r
153 case 0x80:\r
87000d77 154 DEBUG ((DEBUG_VERBOSE, "Conflicting Attributes\n"));\r
eb290d02
FT
155 break;\r
156 case 0x81:\r
87000d77 157 DEBUG ((DEBUG_VERBOSE, "Invalid Protection Information\n"));\r
eb290d02
FT
158 break;\r
159 case 0x82:\r
87000d77 160 DEBUG ((DEBUG_VERBOSE, "Attempted Write to Read Only Range\n"));\r
eb290d02
FT
161 break;\r
162 }\r
1436aea4 163\r
eb290d02
FT
164 break;\r
165\r
166 case 0x2:\r
167 switch (Cq->Sc) {\r
168 case 0x80:\r
87000d77 169 DEBUG ((DEBUG_VERBOSE, "Write Fault\n"));\r
eb290d02
FT
170 break;\r
171 case 0x81:\r
87000d77 172 DEBUG ((DEBUG_VERBOSE, "Unrecovered Read Error\n"));\r
eb290d02
FT
173 break;\r
174 case 0x82:\r
87000d77 175 DEBUG ((DEBUG_VERBOSE, "End-to-end Guard Check Error\n"));\r
eb290d02
FT
176 break;\r
177 case 0x83:\r
87000d77 178 DEBUG ((DEBUG_VERBOSE, "End-to-end Application Tag Check Error\n"));\r
eb290d02
FT
179 break;\r
180 case 0x84:\r
87000d77 181 DEBUG ((DEBUG_VERBOSE, "End-to-end Reference Tag Check Error\n"));\r
eb290d02
FT
182 break;\r
183 case 0x85:\r
87000d77 184 DEBUG ((DEBUG_VERBOSE, "Compare Failure\n"));\r
eb290d02
FT
185 break;\r
186 case 0x86:\r
87000d77 187 DEBUG ((DEBUG_VERBOSE, "Access Denied\n"));\r
eb290d02
FT
188 break;\r
189 }\r
1436aea4 190\r
eb290d02
FT
191 break;\r
192\r
193 default:\r
194 break;\r
195 }\r
196}\r
197\r
198/**\r
199 Create PRP lists for data transfer which is larger than 2 memory pages.\r
200 Note here we calcuate the number of required PRP lists and allocate them at one time.\r
201\r
202 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
203 @param[in] PhysicalAddr The physical base address of data buffer.\r
204 @param[in] Pages The number of pages to be transfered.\r
205 @param[out] PrpListHost The host base address of PRP lists.\r
206 @param[in,out] PrpListNo The number of PRP List.\r
207 @param[out] Mapping The mapping value returned from PciIo.Map().\r
208\r
209 @retval The pointer to the first PRP List of the PRP lists.\r
210\r
211**/\r
1436aea4 212VOID *\r
eb290d02 213NvmeCreatePrpList (\r
1436aea4
MK
214 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
215 IN EFI_PHYSICAL_ADDRESS PhysicalAddr,\r
216 IN UINTN Pages,\r
217 OUT VOID **PrpListHost,\r
218 IN OUT UINTN *PrpListNo,\r
219 OUT VOID **Mapping\r
eb290d02
FT
220 )\r
221{\r
1436aea4
MK
222 UINTN PrpEntryNo;\r
223 UINT64 PrpListBase;\r
224 UINTN PrpListIndex;\r
225 UINTN PrpEntryIndex;\r
226 UINT64 Remainder;\r
227 EFI_PHYSICAL_ADDRESS PrpListPhyAddr;\r
228 UINTN Bytes;\r
229 EFI_STATUS Status;\r
eb290d02
FT
230\r
231 //\r
232 // The number of Prp Entry in a memory page.\r
233 //\r
234 PrpEntryNo = EFI_PAGE_SIZE / sizeof (UINT64);\r
235\r
236 //\r
237 // Calculate total PrpList number.\r
238 //\r
769402ef
FT
239 *PrpListNo = (UINTN)DivU64x64Remainder ((UINT64)Pages, (UINT64)PrpEntryNo - 1, &Remainder);\r
240 if (*PrpListNo == 0) {\r
241 *PrpListNo = 1;\r
a9ec6d65 242 } else if ((Remainder != 0) && (Remainder != 1)) {\r
eb290d02 243 *PrpListNo += 1;\r
769402ef
FT
244 } else if (Remainder == 1) {\r
245 Remainder = PrpEntryNo;\r
246 } else if (Remainder == 0) {\r
247 Remainder = PrpEntryNo - 1;\r
eb290d02
FT
248 }\r
249\r
250 Status = PciIo->AllocateBuffer (\r
251 PciIo,\r
252 AllocateAnyPages,\r
253 EfiBootServicesData,\r
254 *PrpListNo,\r
255 PrpListHost,\r
256 0\r
257 );\r
258\r
259 if (EFI_ERROR (Status)) {\r
260 return NULL;\r
261 }\r
262\r
1436aea4 263 Bytes = EFI_PAGES_TO_SIZE (*PrpListNo);\r
eb290d02
FT
264 Status = PciIo->Map (\r
265 PciIo,\r
266 EfiPciIoOperationBusMasterCommonBuffer,\r
267 *PrpListHost,\r
268 &Bytes,\r
269 &PrpListPhyAddr,\r
270 Mapping\r
271 );\r
272\r
273 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (*PrpListNo))) {\r
87000d77 274 DEBUG ((DEBUG_ERROR, "NvmeCreatePrpList: create PrpList failure!\n"));\r
eb290d02
FT
275 goto EXIT;\r
276 }\r
1436aea4 277\r
eb290d02
FT
278 //\r
279 // Fill all PRP lists except of last one.\r
280 //\r
281 ZeroMem (*PrpListHost, Bytes);\r
282 for (PrpListIndex = 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex) {\r
1436aea4 283 PrpListBase = *(UINT64 *)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;\r
eb290d02
FT
284\r
285 for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) {\r
286 if (PrpEntryIndex != PrpEntryNo - 1) {\r
287 //\r
288 // Fill all PRP entries except of last one.\r
289 //\r
1436aea4
MK
290 *((UINT64 *)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;\r
291 PhysicalAddr += EFI_PAGE_SIZE;\r
eb290d02
FT
292 } else {\r
293 //\r
294 // Fill last PRP entries with next PRP List pointer.\r
295 //\r
1436aea4 296 *((UINT64 *)(UINTN)PrpListBase + PrpEntryIndex) = PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE;\r
eb290d02
FT
297 }\r
298 }\r
299 }\r
1436aea4 300\r
eb290d02
FT
301 //\r
302 // Fill last PRP list.\r
303 //\r
1436aea4 304 PrpListBase = *(UINT64 *)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;\r
769402ef 305 for (PrpEntryIndex = 0; PrpEntryIndex < Remainder; ++PrpEntryIndex) {\r
1436aea4
MK
306 *((UINT64 *)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;\r
307 PhysicalAddr += EFI_PAGE_SIZE;\r
eb290d02
FT
308 }\r
309\r
1436aea4 310 return (VOID *)(UINTN)PrpListPhyAddr;\r
eb290d02
FT
311\r
312EXIT:\r
313 PciIo->FreeBuffer (PciIo, *PrpListNo, *PrpListHost);\r
314 return NULL;\r
315}\r
316\r
5f5bba14
HW
317/**\r
318 Aborts the asynchronous PassThru requests.\r
319\r
320 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA\r
321 data structure.\r
322\r
323 @retval EFI_SUCCESS The asynchronous PassThru requests have been aborted.\r
324 @return EFI_DEVICE_ERROR Fail to abort all the asynchronous PassThru requests.\r
325\r
326**/\r
327EFI_STATUS\r
328AbortAsyncPassThruTasks (\r
1436aea4 329 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
5f5bba14
HW
330 )\r
331{\r
1436aea4
MK
332 EFI_PCI_IO_PROTOCOL *PciIo;\r
333 LIST_ENTRY *Link;\r
334 LIST_ENTRY *NextLink;\r
335 NVME_BLKIO2_SUBTASK *Subtask;\r
336 NVME_BLKIO2_REQUEST *BlkIo2Request;\r
337 NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;\r
338 EFI_BLOCK_IO2_TOKEN *Token;\r
339 EFI_TPL OldTpl;\r
340 EFI_STATUS Status;\r
5f5bba14
HW
341\r
342 PciIo = Private->PciIo;\r
343 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
344\r
345 //\r
346 // Cancel the unsubmitted subtasks.\r
347 //\r
348 for (Link = GetFirstNode (&Private->UnsubmittedSubtasks);\r
349 !IsNull (&Private->UnsubmittedSubtasks, Link);\r
1436aea4
MK
350 Link = NextLink)\r
351 {\r
5f5bba14
HW
352 NextLink = GetNextNode (&Private->UnsubmittedSubtasks, Link);\r
353 Subtask = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);\r
354 BlkIo2Request = Subtask->BlockIo2Request;\r
355 Token = BlkIo2Request->Token;\r
356\r
357 BlkIo2Request->UnsubmittedSubtaskNum--;\r
358 if (Subtask->IsLast) {\r
359 BlkIo2Request->LastSubtaskSubmitted = TRUE;\r
360 }\r
1436aea4 361\r
5f5bba14
HW
362 Token->TransactionStatus = EFI_ABORTED;\r
363\r
364 RemoveEntryList (Link);\r
365 InsertTailList (&BlkIo2Request->SubtasksQueue, Link);\r
366 gBS->SignalEvent (Subtask->Event);\r
367 }\r
368\r
369 //\r
370 // Cleanup the resources for the asynchronous PassThru requests.\r
371 //\r
372 for (Link = GetFirstNode (&Private->AsyncPassThruQueue);\r
373 !IsNull (&Private->AsyncPassThruQueue, Link);\r
1436aea4
MK
374 Link = NextLink)\r
375 {\r
376 NextLink = GetNextNode (&Private->AsyncPassThruQueue, Link);\r
5f5bba14
HW
377 AsyncRequest = NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link);\r
378\r
379 if (AsyncRequest->MapData != NULL) {\r
380 PciIo->Unmap (PciIo, AsyncRequest->MapData);\r
381 }\r
1436aea4 382\r
5f5bba14
HW
383 if (AsyncRequest->MapMeta != NULL) {\r
384 PciIo->Unmap (PciIo, AsyncRequest->MapMeta);\r
385 }\r
1436aea4 386\r
5f5bba14
HW
387 if (AsyncRequest->MapPrpList != NULL) {\r
388 PciIo->Unmap (PciIo, AsyncRequest->MapPrpList);\r
389 }\r
1436aea4 390\r
5f5bba14
HW
391 if (AsyncRequest->PrpListHost != NULL) {\r
392 PciIo->FreeBuffer (\r
393 PciIo,\r
394 AsyncRequest->PrpListNo,\r
395 AsyncRequest->PrpListHost\r
396 );\r
397 }\r
398\r
399 RemoveEntryList (Link);\r
400 gBS->SignalEvent (AsyncRequest->CallerEvent);\r
401 FreePool (AsyncRequest);\r
402 }\r
403\r
404 if (IsListEmpty (&Private->AsyncPassThruQueue) &&\r
1436aea4
MK
405 IsListEmpty (&Private->UnsubmittedSubtasks))\r
406 {\r
5f5bba14
HW
407 Status = EFI_SUCCESS;\r
408 } else {\r
409 Status = EFI_DEVICE_ERROR;\r
410 }\r
411\r
412 gBS->RestoreTPL (OldTpl);\r
413\r
414 return Status;\r
415}\r
416\r
eb290d02
FT
417/**\r
418 Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports\r
d6c55989 419 both blocking I/O and non-blocking I/O. The blocking I/O functionality is required, and the non-blocking\r
eb290d02
FT
420 I/O functionality is optional.\r
421\r
d6c55989
FT
422\r
423 @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
424 @param[in] NamespaceId A 32 bit namespace ID as defined in the NVMe specification to which the NVM Express Command\r
425 Packet will be sent. A value of 0 denotes the NVM Express controller, a value of all 0xFF's\r
426 (all bytes are 0xFF) in the namespace ID specifies that the command packet should be sent to\r
427 all valid namespaces.\r
428 @param[in,out] Packet A pointer to the NVM Express Command Packet.\r
429 @param[in] Event If non-blocking I/O is not supported then Event is ignored, and blocking I/O is performed.\r
430 If Event is NULL, then blocking I/O is performed. If Event is not NULL and non-blocking I/O\r
431 is supported, then non-blocking I/O is performed, and Event will be signaled when the NVM\r
eb290d02
FT
432 Express Command Packet completes.\r
433\r
434 @retval EFI_SUCCESS The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred\r
435 to, or from DataBuffer.\r
436 @retval EFI_BAD_BUFFER_SIZE The NVM Express Command Packet was not executed. The number of bytes that could be transferred\r
437 is returned in TransferLength.\r
438 @retval EFI_NOT_READY The NVM Express Command Packet could not be sent because the controller is not ready. The caller\r
439 may retry again later.\r
440 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the NVM Express Command Packet.\r
d6c55989 441 @retval EFI_INVALID_PARAMETER NamespaceId or the contents of EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM\r
eb290d02 442 Express Command Packet was not sent, so no additional status information is available.\r
d6c55989
FT
443 @retval EFI_UNSUPPORTED The command described by the NVM Express Command Packet is not supported by the NVM Express\r
444 controller. The NVM Express Command Packet was not sent so no additional status information\r
445 is available.\r
eb290d02
FT
446 @retval EFI_TIMEOUT A timeout occurred while waiting for the NVM Express Command Packet to execute.\r
447\r
448**/\r
449EFI_STATUS\r
450EFIAPI\r
451NvmExpressPassThru (\r
1436aea4
MK
452 IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
453 IN UINT32 NamespaceId,\r
454 IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet,\r
455 IN EFI_EVENT Event OPTIONAL\r
eb290d02
FT
456 )\r
457{\r
3c52deaf
HW
458 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
459 EFI_STATUS Status;\r
9a77210b 460 EFI_STATUS PreviousStatus;\r
3c52deaf
HW
461 EFI_PCI_IO_PROTOCOL *PciIo;\r
462 NVME_SQ *Sq;\r
463 NVME_CQ *Cq;\r
464 UINT16 QueueId;\r
76071741 465 UINT16 QueueSize;\r
3c52deaf
HW
466 UINT32 Bytes;\r
467 UINT16 Offset;\r
468 EFI_EVENT TimerEvent;\r
469 EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
470 EFI_PHYSICAL_ADDRESS PhyAddr;\r
471 VOID *MapData;\r
472 VOID *MapMeta;\r
473 VOID *MapPrpList;\r
474 UINTN MapLength;\r
475 UINT64 *Prp;\r
476 VOID *PrpListHost;\r
477 UINTN PrpListNo;\r
491f6026 478 UINT32 Attributes;\r
3c52deaf 479 UINT32 IoAlign;\r
b7f82a3a 480 UINT32 MaxTransLen;\r
3c52deaf
HW
481 UINT32 Data;\r
482 NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;\r
483 EFI_TPL OldTpl;\r
eb290d02
FT
484\r
485 //\r
486 // check the data fields in Packet parameter.\r
487 //\r
488 if ((This == NULL) || (Packet == NULL)) {\r
489 return EFI_INVALID_PARAMETER;\r
490 }\r
491\r
d6c55989 492 if ((Packet->NvmeCmd == NULL) || (Packet->NvmeCompletion == NULL)) {\r
eb290d02
FT
493 return EFI_INVALID_PARAMETER;\r
494 }\r
495\r
1436aea4 496 if ((Packet->QueueType != NVME_ADMIN_QUEUE) && (Packet->QueueType != NVME_IO_QUEUE)) {\r
eb290d02
FT
497 return EFI_INVALID_PARAMETER;\r
498 }\r
499\r
491f6026
HW
500 //\r
501 // 'Attributes' with neither EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL nor\r
502 // EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL set is an illegal\r
503 // configuration.\r
504 //\r
1436aea4 505 Attributes = This->Mode->Attributes;\r
491f6026 506 if ((Attributes & (EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
1436aea4
MK
507 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL)) == 0)\r
508 {\r
491f6026
HW
509 return EFI_INVALID_PARAMETER;\r
510 }\r
511\r
3c52deaf
HW
512 //\r
513 // Buffer alignment check for TransferBuffer & MetadataBuffer.\r
514 //\r
1436aea4
MK
515 IoAlign = This->Mode->IoAlign;\r
516 if ((IoAlign > 0) && (((UINTN)Packet->TransferBuffer & (IoAlign - 1)) != 0)) {\r
3c52deaf
HW
517 return EFI_INVALID_PARAMETER;\r
518 }\r
519\r
1436aea4 520 if ((IoAlign > 0) && (((UINTN)Packet->MetadataBuffer & (IoAlign - 1)) != 0)) {\r
3c52deaf
HW
521 return EFI_INVALID_PARAMETER;\r
522 }\r
523\r
1436aea4 524 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);\r
b7f82a3a
HW
525\r
526 //\r
80b405a6
HW
527 // Check NamespaceId is valid or not.\r
528 //\r
529 if ((NamespaceId > Private->ControllerData->Nn) &&\r
1436aea4
MK
530 (NamespaceId != (UINT32)-1))\r
531 {\r
80b405a6
HW
532 return EFI_INVALID_PARAMETER;\r
533 }\r
534\r
535 //\r
b7f82a3a
HW
536 // Check whether TransferLength exceeds the maximum data transfer size.\r
537 //\r
538 if (Private->ControllerData->Mdts != 0) {\r
539 MaxTransLen = (1 << (Private->ControllerData->Mdts)) *\r
540 (1 << (Private->Cap.Mpsmin + 12));\r
541 if (Packet->TransferLength > MaxTransLen) {\r
542 Packet->TransferLength = MaxTransLen;\r
543 return EFI_BAD_BUFFER_SIZE;\r
544 }\r
545 }\r
546\r
eb290d02
FT
547 PciIo = Private->PciIo;\r
548 MapData = NULL;\r
549 MapMeta = NULL;\r
550 MapPrpList = NULL;\r
551 PrpListHost = NULL;\r
552 PrpListNo = 0;\r
553 Prp = NULL;\r
554 TimerEvent = NULL;\r
555 Status = EFI_SUCCESS;\r
76071741 556 QueueSize = MIN (NVME_ASYNC_CSQ_SIZE, Private->Cap.Mqes) + 1;\r
eb290d02 557\r
758ea946
HW
558 if (Packet->QueueType == NVME_ADMIN_QUEUE) {\r
559 QueueId = 0;\r
560 } else {\r
561 if (Event == NULL) {\r
562 QueueId = 1;\r
563 } else {\r
564 QueueId = 2;\r
565\r
566 //\r
567 // Submission queue full check.\r
568 //\r
76071741 569 if ((Private->SqTdbl[QueueId].Sqt + 1) % QueueSize ==\r
1436aea4
MK
570 Private->AsyncSqHead)\r
571 {\r
758ea946
HW
572 return EFI_NOT_READY;\r
573 }\r
574 }\r
575 }\r
1436aea4
MK
576\r
577 Sq = Private->SqBuffer[QueueId] + Private->SqTdbl[QueueId].Sqt;\r
578 Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;\r
eb290d02
FT
579\r
580 if (Packet->NvmeCmd->Nsid != NamespaceId) {\r
581 return EFI_INVALID_PARAMETER;\r
582 }\r
583\r
584 ZeroMem (Sq, sizeof (NVME_SQ));\r
d6c55989
FT
585 Sq->Opc = (UINT8)Packet->NvmeCmd->Cdw0.Opcode;\r
586 Sq->Fuse = (UINT8)Packet->NvmeCmd->Cdw0.FusedOperation;\r
758ea946 587 Sq->Cid = Private->Cid[QueueId]++;\r
eb290d02
FT
588 Sq->Nsid = Packet->NvmeCmd->Nsid;\r
589\r
590 //\r
591 // Currently we only support PRP for data transfer, SGL is NOT supported.\r
592 //\r
7b8883c6
FT
593 ASSERT (Sq->Psdt == 0);\r
594 if (Sq->Psdt != 0) {\r
87000d77 595 DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: doesn't support SGL mechanism\n"));\r
eb290d02
FT
596 return EFI_UNSUPPORTED;\r
597 }\r
598\r
599 Sq->Prp[0] = (UINT64)(UINTN)Packet->TransferBuffer;\r
8411c9d5 600 if ((Packet->QueueType == NVME_ADMIN_QUEUE) &&\r
1436aea4
MK
601 ((Sq->Opc == NVME_ADMIN_CRIOCQ_CMD) || (Sq->Opc == NVME_ADMIN_CRIOSQ_CMD)))\r
602 {\r
8411c9d5
HW
603 //\r
604 // Currently, we only use the IO Completion/Submission queues created internally\r
605 // by this driver during controller initialization. Any other IO queues created\r
606 // will not be consumed here. The value is little to accept external IO queue\r
607 // creation requests, so here we will return EFI_UNSUPPORTED for external IO\r
608 // queue creation request.\r
609 //\r
610 if (!Private->CreateIoQueue) {\r
611 DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: Does not support external IO queues creation request.\n"));\r
612 return EFI_UNSUPPORTED;\r
613 }\r
614 } else if ((Sq->Opc & (BIT0 | BIT1)) != 0) {\r
615 //\r
616 // If the NVMe cmd has data in or out, then mapping the user buffer to the PCI controller specific addresses.\r
617 //\r
ebb6c763 618 if (((Packet->TransferLength != 0) && (Packet->TransferBuffer == NULL)) ||\r
1436aea4
MK
619 ((Packet->TransferLength == 0) && (Packet->TransferBuffer != NULL)))\r
620 {\r
b7f82a3a
HW
621 return EFI_INVALID_PARAMETER;\r
622 }\r
623\r
eb290d02
FT
624 if ((Sq->Opc & BIT0) != 0) {\r
625 Flag = EfiPciIoOperationBusMasterRead;\r
626 } else {\r
627 Flag = EfiPciIoOperationBusMasterWrite;\r
628 }\r
629\r
ebb6c763
HW
630 if ((Packet->TransferLength != 0) && (Packet->TransferBuffer != NULL)) {\r
631 MapLength = Packet->TransferLength;\r
1436aea4
MK
632 Status = PciIo->Map (\r
633 PciIo,\r
634 Flag,\r
635 Packet->TransferBuffer,\r
636 &MapLength,\r
637 &PhyAddr,\r
638 &MapData\r
639 );\r
ebb6c763
HW
640 if (EFI_ERROR (Status) || (Packet->TransferLength != MapLength)) {\r
641 return EFI_OUT_OF_RESOURCES;\r
642 }\r
eb290d02 643\r
ebb6c763
HW
644 Sq->Prp[0] = PhyAddr;\r
645 Sq->Prp[1] = 0;\r
646 }\r
eb290d02 647\r
1436aea4 648 if ((Packet->MetadataLength != 0) && (Packet->MetadataBuffer != NULL)) {\r
eb290d02 649 MapLength = Packet->MetadataLength;\r
1436aea4
MK
650 Status = PciIo->Map (\r
651 PciIo,\r
652 Flag,\r
653 Packet->MetadataBuffer,\r
654 &MapLength,\r
655 &PhyAddr,\r
656 &MapMeta\r
657 );\r
eb290d02
FT
658 if (EFI_ERROR (Status) || (Packet->MetadataLength != MapLength)) {\r
659 PciIo->Unmap (\r
660 PciIo,\r
661 MapData\r
662 );\r
663\r
664 return EFI_OUT_OF_RESOURCES;\r
665 }\r
1436aea4 666\r
eb290d02
FT
667 Sq->Mptr = PhyAddr;\r
668 }\r
669 }\r
1436aea4 670\r
eb290d02
FT
671 //\r
672 // If the buffer size spans more than two memory pages (page size as defined in CC.Mps),\r
673 // then build a PRP list in the second PRP submission queue entry.\r
674 //\r
675 Offset = ((UINT16)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1);\r
676 Bytes = Packet->TransferLength;\r
677\r
678 if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) {\r
679 //\r
680 // Create PrpList for remaining data buffer.\r
681 //\r
682 PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);\r
1436aea4 683 Prp = NvmeCreatePrpList (PciIo, PhyAddr, EFI_SIZE_TO_PAGES (Offset + Bytes) - 1, &PrpListHost, &PrpListNo, &MapPrpList);\r
eb290d02 684 if (Prp == NULL) {\r
67d3e63c 685 Status = EFI_OUT_OF_RESOURCES;\r
eb290d02
FT
686 goto EXIT;\r
687 }\r
688\r
689 Sq->Prp[1] = (UINT64)(UINTN)Prp;\r
690 } else if ((Offset + Bytes) > EFI_PAGE_SIZE) {\r
691 Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);\r
692 }\r
693\r
1436aea4 694 if (Packet->NvmeCmd->Flags & CDW2_VALID) {\r
d6c55989
FT
695 Sq->Rsvd2 = (UINT64)Packet->NvmeCmd->Cdw2;\r
696 }\r
1436aea4
MK
697\r
698 if (Packet->NvmeCmd->Flags & CDW3_VALID) {\r
d6c55989
FT
699 Sq->Rsvd2 |= LShiftU64 ((UINT64)Packet->NvmeCmd->Cdw3, 32);\r
700 }\r
1436aea4
MK
701\r
702 if (Packet->NvmeCmd->Flags & CDW10_VALID) {\r
eb290d02
FT
703 Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10;\r
704 }\r
1436aea4
MK
705\r
706 if (Packet->NvmeCmd->Flags & CDW11_VALID) {\r
eb290d02
FT
707 Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11;\r
708 }\r
1436aea4
MK
709\r
710 if (Packet->NvmeCmd->Flags & CDW12_VALID) {\r
eb290d02
FT
711 Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12;\r
712 }\r
1436aea4
MK
713\r
714 if (Packet->NvmeCmd->Flags & CDW13_VALID) {\r
eb290d02
FT
715 Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13;\r
716 }\r
1436aea4
MK
717\r
718 if (Packet->NvmeCmd->Flags & CDW14_VALID) {\r
eb290d02
FT
719 Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14;\r
720 }\r
1436aea4
MK
721\r
722 if (Packet->NvmeCmd->Flags & CDW15_VALID) {\r
eb290d02
FT
723 Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;\r
724 }\r
725\r
726 //\r
727 // Ring the submission queue doorbell.\r
728 //\r
aec53afb 729 if ((Event != NULL) && (QueueId != 0)) {\r
758ea946 730 Private->SqTdbl[QueueId].Sqt =\r
76071741 731 (Private->SqTdbl[QueueId].Sqt + 1) % QueueSize;\r
758ea946
HW
732 } else {\r
733 Private->SqTdbl[QueueId].Sqt ^= 1;\r
734 }\r
1436aea4
MK
735\r
736 Data = ReadUnaligned32 ((UINT32 *)&Private->SqTdbl[QueueId]);\r
f6b139bd 737 Status = PciIo->Mem.Write (\r
1436aea4
MK
738 PciIo,\r
739 EfiPciIoWidthUint32,\r
740 NVME_BAR,\r
741 NVME_SQTDBL_OFFSET (QueueId, Private->Cap.Dstrd),\r
742 1,\r
743 &Data\r
744 );\r
eb290d02 745\r
f6b139bd
SP
746 if (EFI_ERROR (Status)) {\r
747 goto EXIT;\r
748 }\r
749\r
758ea946
HW
750 //\r
751 // For non-blocking requests, return directly if the command is placed\r
752 // in the submission queue.\r
753 //\r
aec53afb 754 if ((Event != NULL) && (QueueId != 0)) {\r
758ea946
HW
755 AsyncRequest = AllocateZeroPool (sizeof (NVME_PASS_THRU_ASYNC_REQ));\r
756 if (AsyncRequest == NULL) {\r
757 Status = EFI_DEVICE_ERROR;\r
758 goto EXIT;\r
759 }\r
760\r
1436aea4
MK
761 AsyncRequest->Signature = NVME_PASS_THRU_ASYNC_REQ_SIG;\r
762 AsyncRequest->Packet = Packet;\r
763 AsyncRequest->CommandId = Sq->Cid;\r
764 AsyncRequest->CallerEvent = Event;\r
765 AsyncRequest->MapData = MapData;\r
766 AsyncRequest->MapMeta = MapMeta;\r
767 AsyncRequest->MapPrpList = MapPrpList;\r
768 AsyncRequest->PrpListNo = PrpListNo;\r
769 AsyncRequest->PrpListHost = PrpListHost;\r
758ea946
HW
770\r
771 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
772 InsertTailList (&Private->AsyncPassThruQueue, &AsyncRequest->Link);\r
773 gBS->RestoreTPL (OldTpl);\r
774\r
775 return EFI_SUCCESS;\r
776 }\r
777\r
eb290d02
FT
778 Status = gBS->CreateEvent (\r
779 EVT_TIMER,\r
780 TPL_CALLBACK,\r
781 NULL,\r
782 NULL,\r
783 &TimerEvent\r
784 );\r
785 if (EFI_ERROR (Status)) {\r
786 goto EXIT;\r
787 }\r
788\r
1436aea4 789 Status = gBS->SetTimer (TimerEvent, TimerRelative, Packet->CommandTimeout);\r
eb290d02 790\r
1436aea4 791 if (EFI_ERROR (Status)) {\r
eb290d02
FT
792 goto EXIT;\r
793 }\r
794\r
795 //\r
796 // Wait for completion queue to get filled in.\r
797 //\r
798 Status = EFI_TIMEOUT;\r
eb290d02 799 while (EFI_ERROR (gBS->CheckEvent (TimerEvent))) {\r
758ea946 800 if (Cq->Pt != Private->Pt[QueueId]) {\r
eb290d02 801 Status = EFI_SUCCESS;\r
eb290d02
FT
802 break;\r
803 }\r
804 }\r
805\r
eb290d02 806 //\r
754b489b 807 // Check the NVMe cmd execution result\r
eb290d02 808 //\r
754b489b
TF
809 if (Status != EFI_TIMEOUT) {\r
810 if ((Cq->Sct == 0) && (Cq->Sc == 0)) {\r
811 Status = EFI_SUCCESS;\r
812 } else {\r
813 Status = EFI_DEVICE_ERROR;\r
754b489b
TF
814 //\r
815 // Dump every completion entry status for debugging.\r
816 //\r
1436aea4
MK
817 DEBUG_CODE_BEGIN ();\r
818 NvmeDumpStatus (Cq);\r
819 DEBUG_CODE_END ();\r
754b489b 820 }\r
1436aea4 821\r
5687ae57
HW
822 //\r
823 // Copy the Respose Queue entry for this command to the callers response buffer\r
824 //\r
1436aea4 825 CopyMem (Packet->NvmeCompletion, Cq, sizeof (EFI_NVM_EXPRESS_COMPLETION));\r
5f5bba14
HW
826 } else {\r
827 //\r
828 // Timeout occurs for an NVMe command. Reset the controller to abort the\r
829 // outstanding commands.\r
830 //\r
831 DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: Timeout occurs for an NVMe command.\n"));\r
832\r
833 //\r
834 // Disable the timer to trigger the process of async transfers temporarily.\r
835 //\r
836 Status = gBS->SetTimer (Private->TimerEvent, TimerCancel, 0);\r
837 if (EFI_ERROR (Status)) {\r
838 goto EXIT;\r
839 }\r
840\r
841 //\r
842 // Reset the NVMe controller.\r
843 //\r
844 Status = NvmeControllerInit (Private);\r
845 if (!EFI_ERROR (Status)) {\r
846 Status = AbortAsyncPassThruTasks (Private);\r
847 if (!EFI_ERROR (Status)) {\r
848 //\r
849 // Re-enable the timer to trigger the process of async transfers.\r
850 //\r
851 Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, NVME_HC_ASYNC_TIMER);\r
852 if (!EFI_ERROR (Status)) {\r
853 //\r
854 // Return EFI_TIMEOUT to indicate a timeout occurs for NVMe PassThru command.\r
855 //\r
856 Status = EFI_TIMEOUT;\r
857 }\r
858 }\r
859 } else {\r
860 Status = EFI_DEVICE_ERROR;\r
861 }\r
862\r
863 goto EXIT;\r
754b489b 864 }\r
eb290d02 865\r
758ea946
HW
866 if ((Private->CqHdbl[QueueId].Cqh ^= 1) == 0) {\r
867 Private->Pt[QueueId] ^= 1;\r
754b489b 868 }\r
eb290d02 869\r
1436aea4 870 Data = ReadUnaligned32 ((UINT32 *)&Private->CqHdbl[QueueId]);\r
9a77210b 871 PreviousStatus = Status;\r
1436aea4
MK
872 Status = PciIo->Mem.Write (\r
873 PciIo,\r
874 EfiPciIoWidthUint32,\r
875 NVME_BAR,\r
876 NVME_CQHDBL_OFFSET (QueueId, Private->Cap.Dstrd),\r
877 1,\r
878 &Data\r
879 );\r
9a77210b
HG
880 // The return status of PciIo->Mem.Write should not override\r
881 // previous status if previous status contains error.\r
882 Status = EFI_ERROR (PreviousStatus) ? PreviousStatus : Status;\r
eb290d02 883\r
aec53afb
HW
884 //\r
885 // For now, the code does not support the non-blocking feature for admin queue.\r
886 // If Event is not NULL for admin queue, signal the caller's event here.\r
887 //\r
888 if (Event != NULL) {\r
889 ASSERT (QueueId == 0);\r
890 gBS->SignalEvent (Event);\r
891 }\r
892\r
eb290d02
FT
893EXIT:\r
894 if (MapData != NULL) {\r
895 PciIo->Unmap (\r
896 PciIo,\r
897 MapData\r
898 );\r
899 }\r
900\r
901 if (MapMeta != NULL) {\r
902 PciIo->Unmap (\r
903 PciIo,\r
904 MapMeta\r
905 );\r
906 }\r
907\r
908 if (MapPrpList != NULL) {\r
909 PciIo->Unmap (\r
910 PciIo,\r
911 MapPrpList\r
912 );\r
913 }\r
914\r
915 if (Prp != NULL) {\r
916 PciIo->FreeBuffer (PciIo, PrpListNo, PrpListHost);\r
917 }\r
918\r
919 if (TimerEvent != NULL) {\r
920 gBS->CloseEvent (TimerEvent);\r
921 }\r
1436aea4 922\r
eb290d02
FT
923 return Status;\r
924}\r
925\r
926/**\r
d6c55989 927 Used to retrieve the next namespace ID for this NVM Express controller.\r
eb290d02 928\r
d6c55989
FT
929 The EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNextNamespace() function retrieves the next valid\r
930 namespace ID on this NVM Express controller.\r
eb290d02 931\r
d6c55989
FT
932 If on input the value pointed to by NamespaceId is 0xFFFFFFFF, then the first valid namespace\r
933 ID defined on the NVM Express controller is returned in the location pointed to by NamespaceId\r
934 and a status of EFI_SUCCESS is returned.\r
eb290d02 935\r
d6c55989
FT
936 If on input the value pointed to by NamespaceId is an invalid namespace ID other than 0xFFFFFFFF,\r
937 then EFI_INVALID_PARAMETER is returned.\r
eb290d02 938\r
d6c55989
FT
939 If on input the value pointed to by NamespaceId is a valid namespace ID, then the next valid\r
940 namespace ID on the NVM Express controller is returned in the location pointed to by NamespaceId,\r
941 and EFI_SUCCESS is returned.\r
eb290d02 942\r
d6c55989
FT
943 If the value pointed to by NamespaceId is the namespace ID of the last namespace on the NVM\r
944 Express controller, then EFI_NOT_FOUND is returned.\r
945\r
946 @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
eb290d02
FT
947 @param[in,out] NamespaceId On input, a pointer to a legal NamespaceId for an NVM Express\r
948 namespace present on the NVM Express controller. On output, a\r
949 pointer to the next NamespaceId of an NVM Express namespace on\r
950 an NVM Express controller. An input value of 0xFFFFFFFF retrieves\r
951 the first NamespaceId for an NVM Express namespace present on an\r
952 NVM Express controller.\r
eb290d02 953\r
d6c55989 954 @retval EFI_SUCCESS The Namespace ID of the next Namespace was returned.\r
eb290d02 955 @retval EFI_NOT_FOUND There are no more namespaces defined on this controller.\r
d6c55989 956 @retval EFI_INVALID_PARAMETER NamespaceId is an invalid value other than 0xFFFFFFFF.\r
eb290d02
FT
957\r
958**/\r
959EFI_STATUS\r
960EFIAPI\r
961NvmExpressGetNextNamespace (\r
1436aea4
MK
962 IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
963 IN OUT UINT32 *NamespaceId\r
eb290d02
FT
964 )\r
965{\r
1436aea4
MK
966 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
967 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
968 UINT32 NextNamespaceId;\r
969 EFI_STATUS Status;\r
eb290d02
FT
970\r
971 if ((This == NULL) || (NamespaceId == NULL)) {\r
972 return EFI_INVALID_PARAMETER;\r
973 }\r
974\r
975 NamespaceData = NULL;\r
976 Status = EFI_NOT_FOUND;\r
977\r
978 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);\r
979 //\r
980 // If the NamespaceId input value is 0xFFFFFFFF, then get the first valid namespace ID\r
981 //\r
982 if (*NamespaceId == 0xFFFFFFFF) {\r
983 //\r
984 // Start with the first namespace ID\r
985 //\r
986 NextNamespaceId = 1;\r
987 //\r
988 // Allocate buffer for Identify Namespace data.\r
989 //\r
990 NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
991\r
992 if (NamespaceData == NULL) {\r
993 return EFI_NOT_FOUND;\r
994 }\r
995\r
996 Status = NvmeIdentifyNamespace (Private, NextNamespaceId, NamespaceData);\r
1436aea4 997 if (EFI_ERROR (Status)) {\r
eb290d02
FT
998 goto Done;\r
999 }\r
1000\r
1001 *NamespaceId = NextNamespaceId;\r
eb290d02 1002 } else {\r
114358ea 1003 if (*NamespaceId > Private->ControllerData->Nn) {\r
eb290d02
FT
1004 return EFI_INVALID_PARAMETER;\r
1005 }\r
1006\r
1007 NextNamespaceId = *NamespaceId + 1;\r
114358ea
HW
1008 if (NextNamespaceId > Private->ControllerData->Nn) {\r
1009 return EFI_NOT_FOUND;\r
1010 }\r
1011\r
eb290d02
FT
1012 //\r
1013 // Allocate buffer for Identify Namespace data.\r
1014 //\r
1015 NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
1016 if (NamespaceData == NULL) {\r
1017 return EFI_NOT_FOUND;\r
1018 }\r
1019\r
1020 Status = NvmeIdentifyNamespace (Private, NextNamespaceId, NamespaceData);\r
1436aea4 1021 if (EFI_ERROR (Status)) {\r
eb290d02
FT
1022 goto Done;\r
1023 }\r
1024\r
1025 *NamespaceId = NextNamespaceId;\r
eb290d02
FT
1026 }\r
1027\r
1028Done:\r
1029 if (NamespaceData != NULL) {\r
1436aea4 1030 FreePool (NamespaceData);\r
eb290d02
FT
1031 }\r
1032\r
1033 return Status;\r
1034}\r
1035\r
1036/**\r
d6c55989
FT
1037 Used to translate a device path node to a namespace ID.\r
1038\r
1039 The EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNamespace() function determines the namespace ID associated with the\r
1040 namespace described by DevicePath.\r
eb290d02 1041\r
d6c55989
FT
1042 If DevicePath is a device path node type that the NVM Express Pass Thru driver supports, then the NVM Express\r
1043 Pass Thru driver will attempt to translate the contents DevicePath into a namespace ID.\r
eb290d02 1044\r
d6c55989
FT
1045 If this translation is successful, then that namespace ID is returned in NamespaceId, and EFI_SUCCESS is returned\r
1046\r
1047 @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
eb290d02
FT
1048 @param[in] DevicePath A pointer to the device path node that describes an NVM Express namespace on\r
1049 the NVM Express controller.\r
1050 @param[out] NamespaceId The NVM Express namespace ID contained in the device path node.\r
eb290d02 1051\r
d6c55989
FT
1052 @retval EFI_SUCCESS DevicePath was successfully translated to NamespaceId.\r
1053 @retval EFI_INVALID_PARAMETER If DevicePath or NamespaceId are NULL, then EFI_INVALID_PARAMETER is returned.\r
eb290d02
FT
1054 @retval EFI_UNSUPPORTED If DevicePath is not a device path node type that the NVM Express Pass Thru driver\r
1055 supports, then EFI_UNSUPPORTED is returned.\r
d6c55989
FT
1056 @retval EFI_NOT_FOUND If DevicePath is a device path node type that the NVM Express Pass Thru driver\r
1057 supports, but there is not a valid translation from DevicePath to a namespace ID,\r
1058 then EFI_NOT_FOUND is returned.\r
eb290d02
FT
1059**/\r
1060EFI_STATUS\r
1061EFIAPI\r
1062NvmExpressGetNamespace (\r
1436aea4
MK
1063 IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
1064 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1065 OUT UINT32 *NamespaceId\r
eb290d02
FT
1066 )\r
1067{\r
1436aea4
MK
1068 NVME_NAMESPACE_DEVICE_PATH *Node;\r
1069 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
eb290d02 1070\r
d6c55989 1071 if ((This == NULL) || (DevicePath == NULL) || (NamespaceId == NULL)) {\r
eb290d02
FT
1072 return EFI_INVALID_PARAMETER;\r
1073 }\r
1074\r
1075 if (DevicePath->Type != MESSAGING_DEVICE_PATH) {\r
1076 return EFI_UNSUPPORTED;\r
1077 }\r
1078\r
284dc9bf
HW
1079 Node = (NVME_NAMESPACE_DEVICE_PATH *)DevicePath;\r
1080 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);\r
eb290d02
FT
1081\r
1082 if (DevicePath->SubType == MSG_NVME_NAMESPACE_DP) {\r
1436aea4 1083 if (DevicePathNodeLength (DevicePath) != sizeof (NVME_NAMESPACE_DEVICE_PATH)) {\r
eb290d02
FT
1084 return EFI_NOT_FOUND;\r
1085 }\r
1086\r
284dc9bf
HW
1087 //\r
1088 // Check NamespaceId in the device path node is valid or not.\r
1089 //\r
1090 if ((Node->NamespaceId == 0) ||\r
1436aea4
MK
1091 (Node->NamespaceId > Private->ControllerData->Nn))\r
1092 {\r
284dc9bf
HW
1093 return EFI_NOT_FOUND;\r
1094 }\r
1095\r
d6c55989 1096 *NamespaceId = Node->NamespaceId;\r
eb290d02
FT
1097\r
1098 return EFI_SUCCESS;\r
1099 } else {\r
1100 return EFI_UNSUPPORTED;\r
1101 }\r
1102}\r
1103\r
1104/**\r
1105 Used to allocate and build a device path node for an NVM Express namespace on an NVM Express controller.\r
1106\r
d6c55989 1107 The EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL.BuildDevicePath() function allocates and builds a single device\r
eb290d02
FT
1108 path node for the NVM Express namespace specified by NamespaceId.\r
1109\r
d6c55989 1110 If the NamespaceId is not valid, then EFI_NOT_FOUND is returned.\r
eb290d02
FT
1111\r
1112 If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.\r
1113\r
1114 If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.\r
1115\r
1116 Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of DevicePath are\r
1117 initialized to describe the NVM Express namespace specified by NamespaceId, and EFI_SUCCESS is returned.\r
1118\r
d6c55989 1119 @param[in] This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
eb290d02
FT
1120 @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be\r
1121 allocated and built. Caller must set the NamespaceId to zero if the\r
1122 device path node will contain a valid UUID.\r
eb290d02
FT
1123 @param[in,out] DevicePath A pointer to a single device path node that describes the NVM Express\r
1124 namespace specified by NamespaceId. This function is responsible for\r
1125 allocating the buffer DevicePath with the boot service AllocatePool().\r
1126 It is the caller's responsibility to free DevicePath when the caller\r
1127 is finished with DevicePath.\r
1128 @retval EFI_SUCCESS The device path node that describes the NVM Express namespace specified\r
1129 by NamespaceId was allocated and returned in DevicePath.\r
d6c55989 1130 @retval EFI_NOT_FOUND The NamespaceId is not valid.\r
eb290d02
FT
1131 @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
1132 @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate the DevicePath node.\r
1133\r
1134**/\r
1135EFI_STATUS\r
1136EFIAPI\r
1137NvmExpressBuildDevicePath (\r
1436aea4
MK
1138 IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
1139 IN UINT32 NamespaceId,\r
1140 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
eb290d02
FT
1141 )\r
1142{\r
1436aea4
MK
1143 NVME_NAMESPACE_DEVICE_PATH *Node;\r
1144 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
1145 EFI_STATUS Status;\r
1146 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
eb290d02
FT
1147\r
1148 //\r
1149 // Validate parameters\r
1150 //\r
1151 if ((This == NULL) || (DevicePath == NULL)) {\r
1152 return EFI_INVALID_PARAMETER;\r
1153 }\r
1154\r
d6c55989
FT
1155 Status = EFI_SUCCESS;\r
1156 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);\r
eb290d02 1157\r
946f48eb
HW
1158 //\r
1159 // Check NamespaceId is valid or not.\r
1160 //\r
1161 if ((NamespaceId == 0) ||\r
1436aea4
MK
1162 (NamespaceId > Private->ControllerData->Nn))\r
1163 {\r
946f48eb
HW
1164 return EFI_NOT_FOUND;\r
1165 }\r
1166\r
d6c55989 1167 Node = (NVME_NAMESPACE_DEVICE_PATH *)AllocateZeroPool (sizeof (NVME_NAMESPACE_DEVICE_PATH));\r
eb290d02
FT
1168 if (Node == NULL) {\r
1169 return EFI_OUT_OF_RESOURCES;\r
1170 }\r
1171\r
1172 Node->Header.Type = MESSAGING_DEVICE_PATH;\r
1173 Node->Header.SubType = MSG_NVME_NAMESPACE_DP;\r
1174 SetDevicePathNodeLength (&Node->Header, sizeof (NVME_NAMESPACE_DEVICE_PATH));\r
1436aea4 1175 Node->NamespaceId = NamespaceId;\r
d6c55989
FT
1176\r
1177 //\r
1178 // Allocate a buffer for Identify Namespace data.\r
1179 //\r
1180 NamespaceData = NULL;\r
1436aea4
MK
1181 NamespaceData = AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
1182 if (NamespaceData == NULL) {\r
d6c55989
FT
1183 Status = EFI_OUT_OF_RESOURCES;\r
1184 goto Exit;\r
1185 }\r
1186\r
1187 //\r
1188 // Get UUID from specified Identify Namespace data.\r
1189 //\r
1190 Status = NvmeIdentifyNamespace (\r
1191 Private,\r
1192 NamespaceId,\r
1193 (VOID *)NamespaceData\r
1194 );\r
1195\r
1436aea4 1196 if (EFI_ERROR (Status)) {\r
d6c55989
FT
1197 goto Exit;\r
1198 }\r
1199\r
1200 Node->NamespaceUuid = NamespaceData->Eui64;\r
eb290d02
FT
1201\r
1202 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Node;\r
d6c55989
FT
1203\r
1204Exit:\r
1436aea4 1205 if (NamespaceData != NULL) {\r
d6c55989
FT
1206 FreePool (NamespaceData);\r
1207 }\r
1208\r
1209 if (EFI_ERROR (Status)) {\r
1210 FreePool (Node);\r
1211 }\r
1212\r
1213 return Status;\r
eb290d02 1214}\r