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