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