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