]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
MdeModulePkg/NvmExpressDxe: Notify NVME HW when system reset happens
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressDxe / NvmExpress.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
7111e46f 5 Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>\r
eb290d02
FT
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php.\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "NvmExpress.h"\r
17\r
18//\r
19// NVM Express Driver Binding Protocol Instance\r
20//\r
21EFI_DRIVER_BINDING_PROTOCOL gNvmExpressDriverBinding = {\r
22 NvmExpressDriverBindingSupported,\r
23 NvmExpressDriverBindingStart,\r
24 NvmExpressDriverBindingStop,\r
25 0x10,\r
26 NULL,\r
27 NULL\r
28};\r
29\r
30//\r
31// NVM Express EFI Driver Supported EFI Version Protocol Instance\r
32//\r
33EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiVersion = {\r
34 sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), // Size of Protocol structure.\r
35 0 // Version number to be filled at start up.\r
36};\r
37\r
d6c55989
FT
38//\r
39// Template for NVM Express Pass Thru Mode data structure.\r
40//\r
41GLOBAL_REMOVE_IF_UNREFERENCED EFI_NVM_EXPRESS_PASS_THRU_MODE gEfiNvmExpressPassThruMode = {\r
29be6160
HW
42 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
43 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL |\r
44 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_NONBLOCKIO |\r
45 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM,\r
d6c55989
FT
46 sizeof (UINTN),\r
47 0x10100\r
48};\r
49\r
eb290d02
FT
50/**\r
51 Check if the specified Nvm Express device namespace is active, and create child handles\r
52 for them with BlockIo and DiskInfo protocol instances.\r
53\r
54 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
55 @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be\r
56 allocated and built. Caller must set the NamespaceId to zero if the\r
57 device path node will contain a valid UUID.\r
eb290d02
FT
58\r
59 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
60 @return Others Some error occurs when enumerating the namespaces.\r
61\r
62**/\r
63EFI_STATUS\r
64EnumerateNvmeDevNamespace (\r
65 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
d6c55989 66 UINT32 NamespaceId\r
eb290d02
FT
67 )\r
68{\r
69 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
70 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;\r
71 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
72 EFI_HANDLE DeviceHandle;\r
73 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
74 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
75 NVME_DEVICE_PRIVATE_DATA *Device;\r
76 EFI_STATUS Status;\r
77 UINT32 Lbads;\r
78 UINT32 Flbas;\r
79 UINT32 LbaFmtIdx;\r
da7c7274
FT
80 UINT8 Sn[21];\r
81 UINT8 Mn[41];\r
6fe39780 82 VOID *DummyInterface;\r
eb290d02
FT
83\r
84 NewDevicePathNode = NULL;\r
85 DevicePath = NULL;\r
86 Device = NULL;\r
87\r
88 //\r
89 // Allocate a buffer for Identify Namespace data\r
90 //\r
91 NamespaceData = AllocateZeroPool(sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
92 if(NamespaceData == NULL) {\r
93 return EFI_OUT_OF_RESOURCES;\r
94 }\r
95\r
96 ParentDevicePath = Private->ParentDevicePath;\r
97 //\r
98 // Identify Namespace\r
99 //\r
100 Status = NvmeIdentifyNamespace (\r
101 Private,\r
102 NamespaceId,\r
103 (VOID *)NamespaceData\r
104 );\r
105 if (EFI_ERROR(Status)) {\r
106 goto Exit;\r
107 }\r
108 //\r
109 // Validate Namespace\r
110 //\r
111 if (NamespaceData->Ncap == 0) {\r
112 Status = EFI_DEVICE_ERROR;\r
113 } else {\r
114 //\r
115 // allocate device private data for each discovered namespace\r
116 //\r
117 Device = AllocateZeroPool(sizeof(NVME_DEVICE_PRIVATE_DATA));\r
118 if (Device == NULL) {\r
6a54db85 119 Status = EFI_OUT_OF_RESOURCES;\r
eb290d02
FT
120 goto Exit;\r
121 }\r
122\r
123 //\r
124 // Initialize SSD namespace instance data\r
125 //\r
126 Device->Signature = NVME_DEVICE_PRIVATE_DATA_SIGNATURE;\r
127 Device->NamespaceId = NamespaceId;\r
128 Device->NamespaceUuid = NamespaceData->Eui64;\r
129\r
130 Device->ControllerHandle = Private->ControllerHandle;\r
131 Device->DriverBindingHandle = Private->DriverBindingHandle;\r
132 Device->Controller = Private;\r
133\r
134 //\r
135 // Build BlockIo media structure\r
136 //\r
137 Device->Media.MediaId = 0;\r
138 Device->Media.RemovableMedia = FALSE;\r
139 Device->Media.MediaPresent = TRUE;\r
140 Device->Media.LogicalPartition = FALSE;\r
141 Device->Media.ReadOnly = FALSE;\r
142 Device->Media.WriteCaching = FALSE;\r
9cc0168a 143 Device->Media.IoAlign = Private->PassThruMode.IoAlign;\r
eb290d02
FT
144\r
145 Flbas = NamespaceData->Flbas;\r
2f34e065 146 LbaFmtIdx = Flbas & 0xF;\r
eb290d02
FT
147 Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;\r
148 Device->Media.BlockSize = (UINT32)1 << Lbads;\r
149\r
150 Device->Media.LastBlock = NamespaceData->Nsze - 1;\r
151 Device->Media.LogicalBlocksPerPhysicalBlock = 1;\r
152 Device->Media.LowestAlignedLba = 1;\r
153\r
154 //\r
155 // Create BlockIo Protocol instance\r
156 //\r
157 Device->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
158 Device->BlockIo.Media = &Device->Media;\r
159 Device->BlockIo.Reset = NvmeBlockIoReset;\r
160 Device->BlockIo.ReadBlocks = NvmeBlockIoReadBlocks;\r
161 Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks;\r
162 Device->BlockIo.FlushBlocks = NvmeBlockIoFlushBlocks;\r
163\r
758ea946
HW
164 //\r
165 // Create BlockIo2 Protocol instance\r
166 //\r
167 Device->BlockIo2.Media = &Device->Media;\r
168 Device->BlockIo2.Reset = NvmeBlockIoResetEx;\r
169 Device->BlockIo2.ReadBlocksEx = NvmeBlockIoReadBlocksEx;\r
170 Device->BlockIo2.WriteBlocksEx = NvmeBlockIoWriteBlocksEx;\r
171 Device->BlockIo2.FlushBlocksEx = NvmeBlockIoFlushBlocksEx;\r
172 InitializeListHead (&Device->AsyncQueue);\r
173\r
754b489b
TF
174 //\r
175 // Create StorageSecurityProtocol Instance\r
176 //\r
177 Device->StorageSecurity.ReceiveData = NvmeStorageSecurityReceiveData;\r
178 Device->StorageSecurity.SendData = NvmeStorageSecuritySendData;\r
179\r
eb290d02
FT
180 //\r
181 // Create DiskInfo Protocol instance\r
182 //\r
d2a2678b 183 CopyMem (&Device->NamespaceData, NamespaceData, sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
eb290d02
FT
184 InitializeDiskInfo (Device);\r
185\r
186 //\r
187 // Create a Nvm Express Namespace Device Path Node\r
188 //\r
189 Status = Private->Passthru.BuildDevicePath (\r
190 &Private->Passthru,\r
191 Device->NamespaceId,\r
eb290d02
FT
192 &NewDevicePathNode\r
193 );\r
194\r
195 if (EFI_ERROR(Status)) {\r
196 goto Exit;\r
197 }\r
198\r
199 //\r
200 // Append the SSD node to the controller's device path\r
201 //\r
202 DevicePath = AppendDevicePathNode (ParentDevicePath, NewDevicePathNode);\r
203 if (DevicePath == NULL) {\r
204 Status = EFI_OUT_OF_RESOURCES;\r
205 goto Exit;\r
206 }\r
207\r
208 DeviceHandle = NULL;\r
209 RemainingDevicePath = DevicePath;\r
210 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
211 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
212 Status = EFI_ALREADY_STARTED;\r
213 FreePool (DevicePath);\r
214 goto Exit;\r
215 }\r
216\r
217 Device->DevicePath = DevicePath;\r
218\r
219 //\r
220 // Make sure the handle is NULL so we create a new handle\r
221 //\r
222 Device->DeviceHandle = NULL;\r
223\r
224 Status = gBS->InstallMultipleProtocolInterfaces (\r
225 &Device->DeviceHandle,\r
226 &gEfiDevicePathProtocolGuid,\r
227 Device->DevicePath,\r
228 &gEfiBlockIoProtocolGuid,\r
229 &Device->BlockIo,\r
758ea946
HW
230 &gEfiBlockIo2ProtocolGuid,\r
231 &Device->BlockIo2,\r
eb290d02
FT
232 &gEfiDiskInfoProtocolGuid,\r
233 &Device->DiskInfo,\r
234 NULL\r
235 );\r
236\r
237 if(EFI_ERROR(Status)) {\r
238 goto Exit;\r
239 }\r
754b489b
TF
240\r
241 //\r
242 // Check if the NVMe controller supports the Security Send and Security Receive commands\r
243 //\r
244 if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {\r
245 Status = gBS->InstallProtocolInterface (\r
246 &Device->DeviceHandle,\r
247 &gEfiStorageSecurityCommandProtocolGuid,\r
248 EFI_NATIVE_INTERFACE,\r
249 &Device->StorageSecurity\r
250 );\r
251 if(EFI_ERROR(Status)) {\r
252 gBS->UninstallMultipleProtocolInterfaces (\r
253 &Device->DeviceHandle,\r
254 &gEfiDevicePathProtocolGuid,\r
255 Device->DevicePath,\r
256 &gEfiBlockIoProtocolGuid,\r
257 &Device->BlockIo,\r
758ea946
HW
258 &gEfiBlockIo2ProtocolGuid,\r
259 &Device->BlockIo2,\r
754b489b
TF
260 &gEfiDiskInfoProtocolGuid,\r
261 &Device->DiskInfo,\r
262 NULL\r
263 );\r
264 goto Exit;\r
265 }\r
266 }\r
267\r
eb290d02
FT
268 gBS->OpenProtocol (\r
269 Private->ControllerHandle,\r
beeeb22c 270 &gEfiNvmExpressPassThruProtocolGuid,\r
6fe39780 271 (VOID **) &DummyInterface,\r
eb290d02
FT
272 Private->DriverBindingHandle,\r
273 Device->DeviceHandle,\r
274 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
275 );\r
276\r
7b8883c6
FT
277 //\r
278 // Dump NvmExpress Identify Namespace Data\r
279 //\r
280 DEBUG ((EFI_D_INFO, " == NVME IDENTIFY NAMESPACE [%d] DATA ==\n", NamespaceId));\r
281 DEBUG ((EFI_D_INFO, " NSZE : 0x%x\n", NamespaceData->Nsze));\r
282 DEBUG ((EFI_D_INFO, " NCAP : 0x%x\n", NamespaceData->Ncap));\r
283 DEBUG ((EFI_D_INFO, " NUSE : 0x%x\n", NamespaceData->Nuse));\r
284 DEBUG ((EFI_D_INFO, " LBAF0.LBADS : 0x%x\n", (NamespaceData->LbaFormat[0].Lbads)));\r
285\r
eb290d02
FT
286 //\r
287 // Build controller name for Component Name (2) protocol.\r
288 //\r
da7c7274
FT
289 CopyMem (Sn, Private->ControllerData->Sn, sizeof (Private->ControllerData->Sn));\r
290 Sn[20] = 0;\r
291 CopyMem (Mn, Private->ControllerData->Mn, sizeof (Private->ControllerData->Mn));\r
292 Mn[40] = 0;\r
293 UnicodeSPrintAsciiFormat (Device->ModelName, sizeof (Device->ModelName), "%a-%a-%x", Sn, Mn, NamespaceData->Eui64);\r
eb290d02
FT
294\r
295 AddUnicodeString2 (\r
296 "eng",\r
297 gNvmExpressComponentName.SupportedLanguages,\r
298 &Device->ControllerNameTable,\r
299 Device->ModelName,\r
300 TRUE\r
301 );\r
302\r
303 AddUnicodeString2 (\r
304 "en",\r
305 gNvmExpressComponentName2.SupportedLanguages,\r
306 &Device->ControllerNameTable,\r
307 Device->ModelName,\r
308 FALSE\r
309 );\r
310 }\r
311\r
312Exit:\r
313 if(NamespaceData != NULL) {\r
314 FreePool (NamespaceData);\r
315 }\r
316\r
6a54db85
FT
317 if (NewDevicePathNode != NULL) {\r
318 FreePool (NewDevicePathNode);\r
319 }\r
320\r
eb290d02
FT
321 if(EFI_ERROR(Status) && (Device != NULL) && (Device->DevicePath != NULL)) {\r
322 FreePool (Device->DevicePath);\r
323 }\r
324 if(EFI_ERROR(Status) && (Device != NULL)) {\r
325 FreePool (Device);\r
326 }\r
327 return Status;\r
328}\r
329\r
330/**\r
331 Discover all Nvm Express device namespaces, and create child handles for them with BlockIo\r
332 and DiskInfo protocol instances.\r
333\r
334 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
335\r
336 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
337 @return Others Some error occurs when enumerating the namespaces.\r
338\r
339**/\r
340EFI_STATUS\r
341DiscoverAllNamespaces (\r
342 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
343 )\r
344{\r
345 EFI_STATUS Status;\r
346 UINT32 NamespaceId;\r
d6c55989 347 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *Passthru;\r
eb290d02
FT
348\r
349 NamespaceId = 0xFFFFFFFF;\r
eb290d02
FT
350 Passthru = &Private->Passthru;\r
351\r
352 while (TRUE) {\r
353 Status = Passthru->GetNextNamespace (\r
354 Passthru,\r
d6c55989 355 (UINT32 *)&NamespaceId\r
eb290d02
FT
356 );\r
357\r
358 if (EFI_ERROR (Status)) {\r
359 break;\r
360 }\r
361\r
362 Status = EnumerateNvmeDevNamespace (\r
363 Private,\r
d6c55989 364 NamespaceId\r
eb290d02
FT
365 );\r
366\r
367 if (EFI_ERROR(Status)) {\r
368 continue;\r
369 }\r
370 }\r
371\r
372 return EFI_SUCCESS;\r
373}\r
374\r
375/**\r
376 Unregisters a Nvm Express device namespace.\r
377\r
378 This function removes the protocols installed on the controller handle and\r
379 frees the resources allocated for the namespace.\r
380\r
381 @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.\r
382 @param Controller The controller handle of the namespace.\r
383 @param Handle The child handle.\r
384\r
385 @retval EFI_SUCCESS The namespace is successfully unregistered.\r
386 @return Others Some error occurs when unregistering the namespace.\r
387\r
388**/\r
389EFI_STATUS\r
390UnregisterNvmeNamespace (\r
391 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
392 IN EFI_HANDLE Controller,\r
393 IN EFI_HANDLE Handle\r
394 )\r
395{\r
396 EFI_STATUS Status;\r
eb290d02
FT
397 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
398 NVME_DEVICE_PRIVATE_DATA *Device;\r
754b489b 399 EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;\r
758ea946
HW
400 BOOLEAN IsEmpty;\r
401 EFI_TPL OldTpl;\r
6fe39780 402 VOID *DummyInterface;\r
eb290d02
FT
403\r
404 BlockIo = NULL;\r
405\r
406 Status = gBS->OpenProtocol (\r
407 Handle,\r
408 &gEfiBlockIoProtocolGuid,\r
409 (VOID **) &BlockIo,\r
410 This->DriverBindingHandle,\r
411 Controller,\r
412 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
413 );\r
414 if (EFI_ERROR (Status)) {\r
415 return Status;\r
416 }\r
417\r
beeeb22c 418 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo);\r
eb290d02 419\r
758ea946
HW
420 //\r
421 // Wait for the device's asynchronous I/O queue to become empty.\r
422 //\r
423 while (TRUE) {\r
424 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
425 IsEmpty = IsListEmpty (&Device->AsyncQueue);\r
426 gBS->RestoreTPL (OldTpl);\r
427\r
428 if (IsEmpty) {\r
429 break;\r
430 }\r
431\r
432 gBS->Stall (100);\r
433 }\r
434\r
eb290d02
FT
435 //\r
436 // Close the child handle\r
437 //\r
438 gBS->CloseProtocol (\r
439 Controller,\r
beeeb22c 440 &gEfiNvmExpressPassThruProtocolGuid,\r
eb290d02
FT
441 This->DriverBindingHandle,\r
442 Handle\r
443 );\r
444\r
445 //\r
446 // The Nvm Express driver installs the BlockIo and DiskInfo in the DriverBindingStart().\r
447 // Here should uninstall both of them.\r
448 //\r
449 Status = gBS->UninstallMultipleProtocolInterfaces (\r
450 Handle,\r
451 &gEfiDevicePathProtocolGuid,\r
452 Device->DevicePath,\r
453 &gEfiBlockIoProtocolGuid,\r
454 &Device->BlockIo,\r
758ea946
HW
455 &gEfiBlockIo2ProtocolGuid,\r
456 &Device->BlockIo2,\r
eb290d02
FT
457 &gEfiDiskInfoProtocolGuid,\r
458 &Device->DiskInfo,\r
459 NULL\r
460 );\r
461\r
462 if (EFI_ERROR (Status)) {\r
463 gBS->OpenProtocol (\r
464 Controller,\r
beeeb22c 465 &gEfiNvmExpressPassThruProtocolGuid,\r
6fe39780 466 (VOID **) &DummyInterface,\r
eb290d02
FT
467 This->DriverBindingHandle,\r
468 Handle,\r
469 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
470 );\r
471 return Status;\r
472 }\r
473\r
754b489b
TF
474 //\r
475 // If Storage Security Command Protocol is installed, then uninstall this protocol.\r
476 //\r
477 Status = gBS->OpenProtocol (\r
478 Handle,\r
479 &gEfiStorageSecurityCommandProtocolGuid,\r
480 (VOID **) &StorageSecurity,\r
481 This->DriverBindingHandle,\r
482 Controller,\r
483 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
484 );\r
485\r
486 if (!EFI_ERROR (Status)) {\r
487 Status = gBS->UninstallProtocolInterface (\r
488 Handle,\r
489 &gEfiStorageSecurityCommandProtocolGuid,\r
490 &Device->StorageSecurity\r
491 );\r
492 if (EFI_ERROR (Status)) {\r
493 gBS->OpenProtocol (\r
494 Controller,\r
495 &gEfiNvmExpressPassThruProtocolGuid,\r
6fe39780 496 (VOID **) &DummyInterface,\r
754b489b
TF
497 This->DriverBindingHandle,\r
498 Handle,\r
499 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
500 );\r
501 return Status;\r
502 }\r
503 }\r
504\r
eb290d02
FT
505 if(Device->DevicePath != NULL) {\r
506 FreePool (Device->DevicePath);\r
507 }\r
508\r
509 if (Device->ControllerNameTable != NULL) {\r
510 FreeUnicodeStringTable (Device->ControllerNameTable);\r
511 }\r
512\r
6a54db85
FT
513 FreePool (Device);\r
514\r
eb290d02
FT
515 return EFI_SUCCESS;\r
516}\r
517\r
758ea946
HW
518/**\r
519 Call back function when the timer event is signaled.\r
520\r
521 @param[in] Event The Event this notify function registered to.\r
522 @param[in] Context Pointer to the context data registered to the\r
523 Event.\r
524\r
525**/\r
526VOID\r
527EFIAPI\r
528ProcessAsyncTaskList (\r
529 IN EFI_EVENT Event,\r
530 IN VOID* Context\r
531 )\r
532{\r
533 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
534 EFI_PCI_IO_PROTOCOL *PciIo;\r
535 NVME_CQ *Cq;\r
536 UINT16 QueueId;\r
537 UINT32 Data;\r
538 LIST_ENTRY *Link;\r
539 LIST_ENTRY *NextLink;\r
540 NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;\r
541 NVME_BLKIO2_SUBTASK *Subtask;\r
542 NVME_BLKIO2_REQUEST *BlkIo2Request;\r
543 EFI_BLOCK_IO2_TOKEN *Token;\r
544 BOOLEAN HasNewItem;\r
545 EFI_STATUS Status;\r
546\r
547 Private = (NVME_CONTROLLER_PRIVATE_DATA*)Context;\r
548 QueueId = 2;\r
549 Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;\r
550 HasNewItem = FALSE;\r
f2333c70 551 PciIo = Private->PciIo;\r
758ea946
HW
552\r
553 //\r
554 // Submit asynchronous subtasks to the NVMe Submission Queue\r
555 //\r
556 for (Link = GetFirstNode (&Private->UnsubmittedSubtasks);\r
557 !IsNull (&Private->UnsubmittedSubtasks, Link);\r
558 Link = NextLink) {\r
559 NextLink = GetNextNode (&Private->UnsubmittedSubtasks, Link);\r
560 Subtask = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);\r
561 BlkIo2Request = Subtask->BlockIo2Request;\r
562 Token = BlkIo2Request->Token;\r
563 RemoveEntryList (Link);\r
564 BlkIo2Request->UnsubmittedSubtaskNum--;\r
565\r
566 //\r
567 // If any previous subtask fails, do not process subsequent ones.\r
568 //\r
569 if (Token->TransactionStatus != EFI_SUCCESS) {\r
570 if (IsListEmpty (&BlkIo2Request->SubtasksQueue) &&\r
571 BlkIo2Request->LastSubtaskSubmitted &&\r
572 (BlkIo2Request->UnsubmittedSubtaskNum == 0)) {\r
573 //\r
574 // Remove the BlockIo2 request from the device asynchronous queue.\r
575 //\r
576 RemoveEntryList (&BlkIo2Request->Link);\r
577 FreePool (BlkIo2Request);\r
578 gBS->SignalEvent (Token->Event);\r
579 }\r
580\r
581 FreePool (Subtask->CommandPacket->NvmeCmd);\r
582 FreePool (Subtask->CommandPacket->NvmeCompletion);\r
583 FreePool (Subtask->CommandPacket);\r
584 FreePool (Subtask);\r
585\r
586 continue;\r
587 }\r
588\r
589 Status = Private->Passthru.PassThru (\r
590 &Private->Passthru,\r
591 Subtask->NamespaceId,\r
592 Subtask->CommandPacket,\r
593 Subtask->Event\r
594 );\r
595 if (Status == EFI_NOT_READY) {\r
596 InsertHeadList (&Private->UnsubmittedSubtasks, Link);\r
597 BlkIo2Request->UnsubmittedSubtaskNum++;\r
598 break;\r
599 } else if (EFI_ERROR (Status)) {\r
600 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
601\r
602 if (IsListEmpty (&BlkIo2Request->SubtasksQueue) &&\r
603 Subtask->IsLast) {\r
604 //\r
605 // Remove the BlockIo2 request from the device asynchronous queue.\r
606 //\r
607 RemoveEntryList (&BlkIo2Request->Link);\r
608 FreePool (BlkIo2Request);\r
609 gBS->SignalEvent (Token->Event);\r
610 }\r
611\r
612 FreePool (Subtask->CommandPacket->NvmeCmd);\r
613 FreePool (Subtask->CommandPacket->NvmeCompletion);\r
614 FreePool (Subtask->CommandPacket);\r
615 FreePool (Subtask);\r
616 } else {\r
617 InsertTailList (&BlkIo2Request->SubtasksQueue, Link);\r
618 if (Subtask->IsLast) {\r
619 BlkIo2Request->LastSubtaskSubmitted = TRUE;\r
620 }\r
621 }\r
622 }\r
623\r
624 while (Cq->Pt != Private->Pt[QueueId]) {\r
625 ASSERT (Cq->Sqid == QueueId);\r
626\r
627 HasNewItem = TRUE;\r
628\r
629 //\r
630 // Find the command with given Command Id.\r
631 //\r
632 for (Link = GetFirstNode (&Private->AsyncPassThruQueue);\r
633 !IsNull (&Private->AsyncPassThruQueue, Link);\r
634 Link = NextLink) {\r
635 NextLink = GetNextNode (&Private->AsyncPassThruQueue, Link);\r
636 AsyncRequest = NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link);\r
637 if (AsyncRequest->CommandId == Cq->Cid) {\r
638 //\r
639 // Copy the Respose Queue entry for this command to the callers\r
640 // response buffer.\r
641 //\r
642 CopyMem (\r
643 AsyncRequest->Packet->NvmeCompletion,\r
644 Cq,\r
645 sizeof(EFI_NVM_EXPRESS_COMPLETION)\r
646 );\r
647\r
f2333c70
SP
648 //\r
649 // Free the resources allocated before cmd submission\r
650 //\r
651 if (AsyncRequest->MapData != NULL) {\r
652 PciIo->Unmap (PciIo, AsyncRequest->MapData);\r
653 }\r
654 if (AsyncRequest->MapMeta != NULL) {\r
655 PciIo->Unmap (PciIo, AsyncRequest->MapMeta);\r
656 }\r
657 if (AsyncRequest->MapPrpList != NULL) {\r
658 PciIo->Unmap (PciIo, AsyncRequest->MapPrpList);\r
659 }\r
660 if (AsyncRequest->PrpListHost != NULL) {\r
661 PciIo->FreeBuffer (\r
662 PciIo,\r
663 AsyncRequest->PrpListNo,\r
664 AsyncRequest->PrpListHost\r
665 );\r
666 }\r
667\r
758ea946
HW
668 RemoveEntryList (Link);\r
669 gBS->SignalEvent (AsyncRequest->CallerEvent);\r
670 FreePool (AsyncRequest);\r
671\r
672 //\r
673 // Update submission queue head.\r
674 //\r
675 Private->AsyncSqHead = Cq->Sqhd;\r
676 break;\r
677 }\r
678 }\r
679\r
680 Private->CqHdbl[QueueId].Cqh++;\r
681 if (Private->CqHdbl[QueueId].Cqh > NVME_ASYNC_CCQ_SIZE) {\r
682 Private->CqHdbl[QueueId].Cqh = 0;\r
683 Private->Pt[QueueId] ^= 1;\r
684 }\r
685\r
686 Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;\r
687 }\r
688\r
689 if (HasNewItem) {\r
758ea946
HW
690 Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueId]);\r
691 PciIo->Mem.Write (\r
692 PciIo,\r
693 EfiPciIoWidthUint32,\r
694 NVME_BAR,\r
695 NVME_CQHDBL_OFFSET(QueueId, Private->Cap.Dstrd),\r
696 1,\r
697 &Data\r
698 );\r
699 }\r
700}\r
701\r
eb290d02
FT
702/**\r
703 Tests to see if this driver supports a given controller. If a child device is provided,\r
704 it further tests to see if this driver supports creating a handle for the specified child device.\r
705\r
706 This function checks to see if the driver specified by This supports the device specified by\r
707 ControllerHandle. Drivers will typically use the device path attached to\r
708 ControllerHandle and/or the services from the bus I/O abstraction attached to\r
709 ControllerHandle to determine if the driver supports ControllerHandle. This function\r
710 may be called many times during platform initialization. In order to reduce boot times, the tests\r
711 performed by this function must be very small, and take as little time as possible to execute. This\r
712 function must not change the state of any hardware devices, and this function must be aware that the\r
713 device specified by ControllerHandle may already be managed by the same driver or a\r
714 different driver. This function must match its calls to AllocatePages() with FreePages(),\r
715 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
716 Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
717 already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
718 to guarantee the state of ControllerHandle is not modified by this function.\r
719\r
720 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
721 @param[in] ControllerHandle The handle of the controller to test. This handle\r
722 must support a protocol interface that supplies\r
723 an I/O abstraction to the driver.\r
724 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
725 parameter is ignored by device drivers, and is optional for bus\r
726 drivers. For bus drivers, if this parameter is not NULL, then\r
727 the bus driver must determine if the bus controller specified\r
728 by ControllerHandle and the child controller specified\r
729 by RemainingDevicePath are both supported by this\r
730 bus driver.\r
731\r
732 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
733 RemainingDevicePath is supported by the driver specified by This.\r
734 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
735 RemainingDevicePath is already being managed by the driver\r
736 specified by This.\r
737 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
738 RemainingDevicePath is already being managed by a different\r
739 driver or an application that requires exclusive access.\r
740 Currently not implemented.\r
741 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
742 RemainingDevicePath is not supported by the driver specified by This.\r
743**/\r
744EFI_STATUS\r
745EFIAPI\r
746NvmExpressDriverBindingSupported (\r
747 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
748 IN EFI_HANDLE Controller,\r
749 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
750 )\r
751{\r
752 EFI_STATUS Status;\r
753 EFI_DEV_PATH_PTR DevicePathNode;\r
754 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
755 EFI_PCI_IO_PROTOCOL *PciIo;\r
756 UINT8 ClassCode[3];\r
757\r
758 //\r
759 // Check whether device path is valid\r
760 //\r
761 if (RemainingDevicePath != NULL) {\r
762 //\r
763 // Check if RemainingDevicePath is the End of Device Path Node,\r
764 // if yes, go on checking other conditions\r
765 //\r
766 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
767 //\r
768 // If RemainingDevicePath isn't the End of Device Path Node,\r
769 // check its validation\r
770 //\r
771 DevicePathNode.DevPath = RemainingDevicePath;\r
772\r
773 if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||\r
774 (DevicePathNode.DevPath->SubType != MSG_NVME_NAMESPACE_DP) ||\r
754b489b
TF
775 (DevicePathNodeLength(DevicePathNode.DevPath) != sizeof(NVME_NAMESPACE_DEVICE_PATH))) {\r
776 return EFI_UNSUPPORTED;\r
eb290d02
FT
777 }\r
778 }\r
779 }\r
780\r
781 //\r
782 // Open the EFI Device Path protocol needed to perform the supported test\r
783 //\r
784 Status = gBS->OpenProtocol (\r
785 Controller,\r
786 &gEfiDevicePathProtocolGuid,\r
787 (VOID **) &ParentDevicePath,\r
788 This->DriverBindingHandle,\r
789 Controller,\r
790 EFI_OPEN_PROTOCOL_BY_DRIVER\r
791 );\r
792 if (Status == EFI_ALREADY_STARTED) {\r
793 return EFI_SUCCESS;\r
794 }\r
795\r
796 if (EFI_ERROR (Status)) {\r
797 return Status;\r
798 }\r
799\r
800 //\r
801 // Close protocol, don't use device path protocol in the Support() function\r
802 //\r
803 gBS->CloseProtocol (\r
804 Controller,\r
805 &gEfiDevicePathProtocolGuid,\r
806 This->DriverBindingHandle,\r
807 Controller\r
808 );\r
809\r
810 //\r
811 // Attempt to Open PCI I/O Protocol\r
812 //\r
813 Status = gBS->OpenProtocol (\r
814 Controller,\r
815 &gEfiPciIoProtocolGuid,\r
816 (VOID **) &PciIo,\r
817 This->DriverBindingHandle,\r
818 Controller,\r
819 EFI_OPEN_PROTOCOL_BY_DRIVER\r
820 );\r
821 if (Status == EFI_ALREADY_STARTED) {\r
822 return EFI_SUCCESS;\r
823 }\r
824\r
825 if (EFI_ERROR (Status)) {\r
826 return Status;\r
827 }\r
828\r
829 //\r
830 // Now further check the PCI header: Base class (offset 0x0B) and Sub Class (offset 0x0A).\r
831 // This controller should be a Nvm Express controller.\r
832 //\r
833 Status = PciIo->Pci.Read (\r
834 PciIo,\r
835 EfiPciIoWidthUint8,\r
836 PCI_CLASSCODE_OFFSET,\r
837 sizeof (ClassCode),\r
838 ClassCode\r
839 );\r
840 if (EFI_ERROR (Status)) {\r
841 goto Done;\r
842 }\r
843\r
844 //\r
845 // Examine Nvm Express controller PCI Configuration table fields\r
846 //\r
847 if ((ClassCode[0] != PCI_IF_NVMHCI) || (ClassCode[1] != PCI_CLASS_MASS_STORAGE_NVM) || (ClassCode[2] != PCI_CLASS_MASS_STORAGE)) {\r
848 Status = EFI_UNSUPPORTED;\r
849 }\r
850\r
851Done:\r
852 gBS->CloseProtocol (\r
853 Controller,\r
854 &gEfiPciIoProtocolGuid,\r
855 This->DriverBindingHandle,\r
856 Controller\r
857 );\r
858\r
859 return Status;\r
860}\r
861\r
862\r
863/**\r
864 Starts a device controller or a bus controller.\r
865\r
866 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
867 As a result, much of the error checking on the parameters to Start() has been moved into this\r
868 common boot service. It is legal to call Start() from other locations,\r
869 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
870 1. ControllerHandle must be a valid EFI_HANDLE.\r
871 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
872 EFI_DEVICE_PATH_PROTOCOL.\r
873 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
874 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
875\r
876 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
877 @param[in] ControllerHandle The handle of the controller to start. This handle\r
878 must support a protocol interface that supplies\r
879 an I/O abstraction to the driver.\r
880 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
881 parameter is ignored by device drivers, and is optional for bus\r
882 drivers. For a bus driver, if this parameter is NULL, then handles\r
883 for all the children of Controller are created by this driver.\r
884 If this parameter is not NULL and the first Device Path Node is\r
885 not the End of Device Path Node, then only the handle for the\r
886 child device specified by the first Device Path Node of\r
887 RemainingDevicePath is created by this driver.\r
888 If the first Device Path Node of RemainingDevicePath is\r
889 the End of Device Path Node, no child handle is created by this\r
890 driver.\r
891\r
892 @retval EFI_SUCCESS The device was started.\r
893 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
894 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
895 @retval Others The driver failded to start the device.\r
896\r
897**/\r
898EFI_STATUS\r
899EFIAPI\r
900NvmExpressDriverBindingStart (\r
901 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
902 IN EFI_HANDLE Controller,\r
903 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
904 )\r
905{\r
d6c55989
FT
906 EFI_STATUS Status;\r
907 EFI_PCI_IO_PROTOCOL *PciIo;\r
908 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
909 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
910 UINT32 NamespaceId;\r
911 EFI_PHYSICAL_ADDRESS MappedAddr;\r
912 UINTN Bytes;\r
913 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *Passthru;\r
eb290d02
FT
914\r
915 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: start\n"));\r
916\r
d6c55989
FT
917 Private = NULL;\r
918 Passthru = NULL;\r
eb290d02
FT
919 ParentDevicePath = NULL;\r
920\r
921 Status = gBS->OpenProtocol (\r
922 Controller,\r
923 &gEfiDevicePathProtocolGuid,\r
924 (VOID **) &ParentDevicePath,\r
925 This->DriverBindingHandle,\r
926 Controller,\r
927 EFI_OPEN_PROTOCOL_BY_DRIVER\r
928 );\r
929 if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
930 return Status;\r
931 }\r
932\r
933 Status = gBS->OpenProtocol (\r
934 Controller,\r
935 &gEfiPciIoProtocolGuid,\r
936 (VOID **) &PciIo,\r
937 This->DriverBindingHandle,\r
938 Controller,\r
939 EFI_OPEN_PROTOCOL_BY_DRIVER\r
940 );\r
941\r
942 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
943 return Status;\r
944 }\r
945\r
946 //\r
947 // Check EFI_ALREADY_STARTED to reuse the original NVME_CONTROLLER_PRIVATE_DATA.\r
948 //\r
949 if (Status != EFI_ALREADY_STARTED) {\r
950 Private = AllocateZeroPool (sizeof (NVME_CONTROLLER_PRIVATE_DATA));\r
951\r
952 if (Private == NULL) {\r
953 DEBUG ((EFI_D_ERROR, "NvmExpressDriverBindingStart: allocating pool for Nvme Private Data failed!\n"));\r
954 Status = EFI_OUT_OF_RESOURCES;\r
d6c55989 955 goto Exit;\r
eb290d02
FT
956 }\r
957\r
958 //\r
758ea946 959 // 6 x 4kB aligned buffers will be carved out of this buffer.\r
eb290d02
FT
960 // 1st 4kB boundary is the start of the admin submission queue.\r
961 // 2nd 4kB boundary is the start of the admin completion queue.\r
962 // 3rd 4kB boundary is the start of I/O submission queue #1.\r
963 // 4th 4kB boundary is the start of I/O completion queue #1.\r
758ea946
HW
964 // 5th 4kB boundary is the start of I/O submission queue #2.\r
965 // 6th 4kB boundary is the start of I/O completion queue #2.\r
eb290d02 966 //\r
758ea946 967 // Allocate 6 pages of memory, then map it for bus master read and write.\r
eb290d02
FT
968 //\r
969 Status = PciIo->AllocateBuffer (\r
970 PciIo,\r
971 AllocateAnyPages,\r
972 EfiBootServicesData,\r
758ea946 973 6,\r
eb290d02
FT
974 (VOID**)&Private->Buffer,\r
975 0\r
976 );\r
977 if (EFI_ERROR (Status)) {\r
d6c55989 978 goto Exit;\r
eb290d02
FT
979 }\r
980\r
758ea946 981 Bytes = EFI_PAGES_TO_SIZE (6);\r
eb290d02
FT
982 Status = PciIo->Map (\r
983 PciIo,\r
984 EfiPciIoOperationBusMasterCommonBuffer,\r
985 Private->Buffer,\r
986 &Bytes,\r
987 &MappedAddr,\r
988 &Private->Mapping\r
989 );\r
990\r
758ea946 991 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (6))) {\r
d6c55989 992 goto Exit;\r
eb290d02
FT
993 }\r
994\r
995 Private->BufferPciAddr = (UINT8 *)(UINTN)MappedAddr;\r
eb290d02
FT
996\r
997 Private->Signature = NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE;\r
998 Private->ControllerHandle = Controller;\r
999 Private->ImageHandle = This->DriverBindingHandle;\r
1000 Private->DriverBindingHandle = This->DriverBindingHandle;\r
1001 Private->PciIo = PciIo;\r
1002 Private->ParentDevicePath = ParentDevicePath;\r
1003 Private->Passthru.Mode = &Private->PassThruMode;\r
1004 Private->Passthru.PassThru = NvmExpressPassThru;\r
1005 Private->Passthru.GetNextNamespace = NvmExpressGetNextNamespace;\r
1006 Private->Passthru.BuildDevicePath = NvmExpressBuildDevicePath;\r
1007 Private->Passthru.GetNamespace = NvmExpressGetNamespace;\r
d6c55989 1008 CopyMem (&Private->PassThruMode, &gEfiNvmExpressPassThruMode, sizeof (EFI_NVM_EXPRESS_PASS_THRU_MODE));\r
758ea946
HW
1009 InitializeListHead (&Private->AsyncPassThruQueue);\r
1010 InitializeListHead (&Private->UnsubmittedSubtasks);\r
eb290d02
FT
1011\r
1012 Status = NvmeControllerInit (Private);\r
eb290d02 1013 if (EFI_ERROR(Status)) {\r
d6c55989 1014 goto Exit;\r
eb290d02
FT
1015 }\r
1016\r
758ea946
HW
1017 //\r
1018 // Start the asynchronous I/O completion monitor\r
1019 //\r
1020 Status = gBS->CreateEvent (\r
1021 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1022 TPL_NOTIFY,\r
1023 ProcessAsyncTaskList,\r
1024 Private,\r
1025 &Private->TimerEvent\r
1026 );\r
1027 if (EFI_ERROR (Status)) {\r
1028 goto Exit;\r
1029 }\r
1030\r
1031 Status = gBS->SetTimer (\r
1032 Private->TimerEvent,\r
1033 TimerPeriodic,\r
1034 NVME_HC_ASYNC_TIMER\r
1035 );\r
1036 if (EFI_ERROR (Status)) {\r
1037 goto Exit;\r
1038 }\r
1039\r
eb290d02
FT
1040 Status = gBS->InstallMultipleProtocolInterfaces (\r
1041 &Controller,\r
d6c55989
FT
1042 &gEfiNvmExpressPassThruProtocolGuid,\r
1043 &Private->Passthru,\r
eb290d02
FT
1044 NULL\r
1045 );\r
1046 if (EFI_ERROR (Status)) {\r
d6c55989 1047 goto Exit;\r
eb290d02 1048 }\r
7111e46f
RN
1049\r
1050 NvmeRegisterShutdownNotification ();\r
eb290d02
FT
1051 } else {\r
1052 Status = gBS->OpenProtocol (\r
1053 Controller,\r
d6c55989
FT
1054 &gEfiNvmExpressPassThruProtocolGuid,\r
1055 (VOID **) &Passthru,\r
eb290d02
FT
1056 This->DriverBindingHandle,\r
1057 Controller,\r
1058 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1059 );\r
1060 if (EFI_ERROR (Status)) {\r
d6c55989 1061 goto Exit;\r
eb290d02 1062 }\r
d6c55989
FT
1063\r
1064 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (Passthru);\r
eb290d02
FT
1065 }\r
1066\r
1067 if (RemainingDevicePath == NULL) {\r
1068 //\r
1069 // Enumerate all NVME namespaces in the controller\r
1070 //\r
1071 Status = DiscoverAllNamespaces (\r
1072 Private\r
1073 );\r
1074\r
1075 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
1076 //\r
1077 // Enumerate the specified NVME namespace\r
1078 //\r
1079 Status = Private->Passthru.GetNamespace (\r
1080 &Private->Passthru,\r
1081 RemainingDevicePath,\r
d6c55989 1082 &NamespaceId\r
eb290d02
FT
1083 );\r
1084\r
1085 if (!EFI_ERROR (Status)) {\r
d6c55989
FT
1086 Status = EnumerateNvmeDevNamespace (\r
1087 Private,\r
1088 NamespaceId\r
1089 );\r
eb290d02
FT
1090 }\r
1091 }\r
1092\r
1093 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end successfully\n"));\r
1094 return EFI_SUCCESS;\r
1095\r
d6c55989 1096Exit:\r
eb290d02
FT
1097 if ((Private != NULL) && (Private->Mapping != NULL)) {\r
1098 PciIo->Unmap (PciIo, Private->Mapping);\r
1099 }\r
1100\r
1101 if ((Private != NULL) && (Private->Buffer != NULL)) {\r
758ea946 1102 PciIo->FreeBuffer (PciIo, 6, Private->Buffer);\r
eb290d02
FT
1103 }\r
1104\r
ac231001
TF
1105 if ((Private != NULL) && (Private->ControllerData != NULL)) {\r
1106 FreePool (Private->ControllerData);\r
1107 }\r
1108\r
eb290d02 1109 if (Private != NULL) {\r
758ea946
HW
1110 if (Private->TimerEvent != NULL) {\r
1111 gBS->CloseEvent (Private->TimerEvent);\r
1112 }\r
1113\r
eb290d02
FT
1114 FreePool (Private);\r
1115 }\r
1116\r
1117 gBS->CloseProtocol (\r
1118 Controller,\r
1119 &gEfiPciIoProtocolGuid,\r
1120 This->DriverBindingHandle,\r
1121 Controller\r
1122 );\r
1123\r
1124 gBS->CloseProtocol (\r
1125 Controller,\r
1126 &gEfiDevicePathProtocolGuid,\r
1127 This->DriverBindingHandle,\r
1128 Controller\r
1129 );\r
1130\r
1131 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end with %r\n", Status));\r
1132\r
1133 return Status;\r
1134}\r
1135\r
1136\r
1137/**\r
1138 Stops a device controller or a bus controller.\r
1139\r
1140 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
1141 As a result, much of the error checking on the parameters to Stop() has been moved\r
1142 into this common boot service. It is legal to call Stop() from other locations,\r
1143 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
1144 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
1145 same driver's Start() function.\r
1146 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
1147 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
1148 Start() function, and the Start() function must have called OpenProtocol() on\r
1149 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
1150\r
1151 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1152 @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
1153 support a bus specific I/O protocol for the driver\r
1154 to use to stop the device.\r
1155 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
1156 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
1157 if NumberOfChildren is 0.\r
1158\r
1159 @retval EFI_SUCCESS The device was stopped.\r
1160 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
1161\r
1162**/\r
1163EFI_STATUS\r
1164EFIAPI\r
1165NvmExpressDriverBindingStop (\r
1166 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1167 IN EFI_HANDLE Controller,\r
1168 IN UINTN NumberOfChildren,\r
1169 IN EFI_HANDLE *ChildHandleBuffer\r
1170 )\r
1171{\r
1172 EFI_STATUS Status;\r
1173 BOOLEAN AllChildrenStopped;\r
1174 UINTN Index;\r
1175 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
beeeb22c 1176 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *PassThru;\r
758ea946
HW
1177 BOOLEAN IsEmpty;\r
1178 EFI_TPL OldTpl;\r
eb290d02
FT
1179\r
1180 if (NumberOfChildren == 0) {\r
1181 Status = gBS->OpenProtocol (\r
1182 Controller,\r
beeeb22c
TF
1183 &gEfiNvmExpressPassThruProtocolGuid,\r
1184 (VOID **) &PassThru,\r
eb290d02
FT
1185 This->DriverBindingHandle,\r
1186 Controller,\r
1187 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1188 );\r
1189\r
1190 if (!EFI_ERROR (Status)) {\r
beeeb22c 1191 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (PassThru);\r
758ea946
HW
1192\r
1193 //\r
1194 // Wait for the asynchronous PassThru queue to become empty.\r
1195 //\r
1196 while (TRUE) {\r
1197 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1198 IsEmpty = IsListEmpty (&Private->AsyncPassThruQueue) &&\r
1199 IsListEmpty (&Private->UnsubmittedSubtasks);\r
1200 gBS->RestoreTPL (OldTpl);\r
1201\r
1202 if (IsEmpty) {\r
1203 break;\r
1204 }\r
1205\r
1206 gBS->Stall (100);\r
1207 }\r
1208\r
eb290d02
FT
1209 gBS->UninstallMultipleProtocolInterfaces (\r
1210 Controller,\r
beeeb22c
TF
1211 &gEfiNvmExpressPassThruProtocolGuid,\r
1212 PassThru,\r
eb290d02
FT
1213 NULL\r
1214 );\r
1215\r
758ea946
HW
1216 if (Private->TimerEvent != NULL) {\r
1217 gBS->CloseEvent (Private->TimerEvent);\r
1218 }\r
1219\r
eb290d02
FT
1220 if (Private->Mapping != NULL) {\r
1221 Private->PciIo->Unmap (Private->PciIo, Private->Mapping);\r
1222 }\r
1223\r
1224 if (Private->Buffer != NULL) {\r
758ea946 1225 Private->PciIo->FreeBuffer (Private->PciIo, 6, Private->Buffer);\r
eb290d02
FT
1226 }\r
1227\r
1228 FreePool (Private->ControllerData);\r
1229 FreePool (Private);\r
1230 }\r
1231\r
1232 gBS->CloseProtocol (\r
1233 Controller,\r
1234 &gEfiPciIoProtocolGuid,\r
1235 This->DriverBindingHandle,\r
1236 Controller\r
1237 );\r
1238 gBS->CloseProtocol (\r
1239 Controller,\r
1240 &gEfiDevicePathProtocolGuid,\r
1241 This->DriverBindingHandle,\r
1242 Controller\r
1243 );\r
7111e46f
RN
1244\r
1245 NvmeUnregisterShutdownNotification ();\r
1246\r
eb290d02
FT
1247 return EFI_SUCCESS;\r
1248 }\r
1249\r
1250 AllChildrenStopped = TRUE;\r
1251\r
1252 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1253 Status = UnregisterNvmeNamespace (This, Controller, ChildHandleBuffer[Index]);\r
1254 if (EFI_ERROR (Status)) {\r
1255 AllChildrenStopped = FALSE;\r
1256 }\r
1257 }\r
1258\r
1259 if (!AllChildrenStopped) {\r
1260 return EFI_DEVICE_ERROR;\r
1261 }\r
1262\r
1263 return EFI_SUCCESS;\r
1264}\r
1265\r
1266/**\r
1267 This is the unload handle for the NVM Express driver.\r
1268\r
1269 Disconnect the driver specified by ImageHandle from the NVMe device in the handle database.\r
1270 Uninstall all the protocols installed in the driver.\r
1271\r
1272 @param[in] ImageHandle The drivers' driver image.\r
1273\r
1274 @retval EFI_SUCCESS The image is unloaded.\r
1275 @retval Others Failed to unload the image.\r
1276\r
1277**/\r
1278EFI_STATUS\r
1279EFIAPI\r
1280NvmExpressUnload (\r
1281 IN EFI_HANDLE ImageHandle\r
1282 )\r
1283{\r
1284 EFI_STATUS Status;\r
1285 EFI_HANDLE *DeviceHandleBuffer;\r
1286 UINTN DeviceHandleCount;\r
1287 UINTN Index;\r
eb290d02
FT
1288 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
1289 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
1290\r
1291 //\r
0a2326af
FT
1292 // Get the list of the device handles managed by this driver.\r
1293 // If there is an error getting the list, then means the driver\r
1294 // doesn't manage any device. At this way, we would only close\r
1295 // those protocols installed at image handle.\r
eb290d02 1296 //\r
0a2326af 1297 DeviceHandleBuffer = NULL;\r
eb290d02 1298 Status = gBS->LocateHandleBuffer (\r
0a2326af 1299 ByProtocol,\r
beeeb22c 1300 &gEfiNvmExpressPassThruProtocolGuid,\r
eb290d02
FT
1301 NULL,\r
1302 &DeviceHandleCount,\r
1303 &DeviceHandleBuffer\r
1304 );\r
1305\r
0a2326af
FT
1306 if (!EFI_ERROR (Status)) {\r
1307 //\r
1308 // Disconnect the driver specified by ImageHandle from all\r
1309 // the devices in the handle database.\r
1310 //\r
1311 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1312 Status = gBS->DisconnectController (\r
1313 DeviceHandleBuffer[Index],\r
1314 ImageHandle,\r
1315 NULL\r
1316 );\r
1317 if (EFI_ERROR (Status)) {\r
1318 goto EXIT;\r
1319 }\r
1320 }\r
eb290d02
FT
1321 }\r
1322\r
1323 //\r
0a2326af 1324 // Uninstall all the protocols installed in the driver entry point\r
eb290d02 1325 //\r
0a2326af
FT
1326 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1327 ImageHandle,\r
1328 &gEfiDriverBindingProtocolGuid,\r
1329 &gNvmExpressDriverBinding,\r
1330 &gEfiDriverSupportedEfiVersionProtocolGuid,\r
1331 &gNvmExpressDriverSupportedEfiVersion,\r
1332 NULL\r
1333 );\r
1334\r
1335 if (EFI_ERROR (Status)) {\r
1336 goto EXIT;\r
eb290d02
FT
1337 }\r
1338\r
1339 //\r
0a2326af
FT
1340 // Note we have to one by one uninstall the following protocols.\r
1341 // It's because some of them are optionally installed based on\r
1342 // the following PCD settings.\r
1343 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable\r
1344 // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable\r
1345 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable\r
1346 // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable\r
eb290d02 1347 //\r
0a2326af
FT
1348 Status = gBS->HandleProtocol (\r
1349 ImageHandle,\r
1350 &gEfiComponentNameProtocolGuid,\r
1351 (VOID **) &ComponentName\r
1352 );\r
1353 if (!EFI_ERROR (Status)) {\r
eb290d02
FT
1354 gBS->UninstallProtocolInterface (\r
1355 ImageHandle,\r
0a2326af
FT
1356 &gEfiComponentNameProtocolGuid,\r
1357 ComponentName\r
eb290d02 1358 );\r
0a2326af 1359 }\r
eb290d02 1360\r
0a2326af
FT
1361 Status = gBS->HandleProtocol (\r
1362 ImageHandle,\r
1363 &gEfiComponentName2ProtocolGuid,\r
1364 (VOID **) &ComponentName2\r
1365 );\r
1366 if (!EFI_ERROR (Status)) {\r
1367 gBS->UninstallProtocolInterface (\r
1368 ImageHandle,\r
1369 &gEfiComponentName2ProtocolGuid,\r
1370 ComponentName2\r
1371 );\r
eb290d02
FT
1372 }\r
1373\r
0a2326af
FT
1374 Status = EFI_SUCCESS;\r
1375\r
1376EXIT:\r
eb290d02
FT
1377 //\r
1378 // Free the buffer containing the list of handles from the handle database\r
1379 //\r
1380 if (DeviceHandleBuffer != NULL) {\r
1381 gBS->FreePool (DeviceHandleBuffer);\r
1382 }\r
0a2326af 1383 return Status;\r
eb290d02
FT
1384}\r
1385\r
1386/**\r
1387 The entry point for Nvm Express driver, used to install Nvm Express driver on the ImageHandle.\r
1388\r
1389 @param ImageHandle The firmware allocated handle for this driver image.\r
1390 @param SystemTable Pointer to the EFI system table.\r
1391\r
1392 @retval EFI_SUCCESS Driver loaded.\r
1393 @retval other Driver not loaded.\r
1394\r
1395**/\r
1396EFI_STATUS\r
1397EFIAPI\r
1398NvmExpressDriverEntry (\r
1399 IN EFI_HANDLE ImageHandle,\r
1400 IN EFI_SYSTEM_TABLE *SystemTable\r
1401 )\r
1402{\r
1403 EFI_STATUS Status;\r
1404\r
1405 Status = EfiLibInstallDriverBindingComponentName2 (\r
1406 ImageHandle,\r
1407 SystemTable,\r
1408 &gNvmExpressDriverBinding,\r
1409 ImageHandle,\r
1410 &gNvmExpressComponentName,\r
1411 &gNvmExpressComponentName2\r
1412 );\r
1413 ASSERT_EFI_ERROR (Status);\r
1414\r
1415 //\r
1416 // Install EFI Driver Supported EFI Version Protocol required for\r
1417 // EFI drivers that are on PCI and other plug in cards.\r
1418 //\r
1419 gNvmExpressDriverSupportedEfiVersion.FirmwareVersion = 0x00020028;\r
1420 Status = gBS->InstallMultipleProtocolInterfaces (\r
1421 &ImageHandle,\r
1422 &gEfiDriverSupportedEfiVersionProtocolGuid,\r
1423 &gNvmExpressDriverSupportedEfiVersion,\r
1424 NULL\r
1425 );\r
1426 ASSERT_EFI_ERROR (Status);\r
1427 return Status;\r
1428}\r