]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
MdeModulePkg/NvmExpress: Fix uninitialized field used in NVMe DiskInfo
[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
d2a2678b 5 Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>\r
eb290d02
FT
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php.\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "NvmExpress.h"\r
17\r
18//\r
19// NVM Express Driver Binding Protocol Instance\r
20//\r
21EFI_DRIVER_BINDING_PROTOCOL gNvmExpressDriverBinding = {\r
22 NvmExpressDriverBindingSupported,\r
23 NvmExpressDriverBindingStart,\r
24 NvmExpressDriverBindingStop,\r
25 0x10,\r
26 NULL,\r
27 NULL\r
28};\r
29\r
30//\r
31// NVM Express EFI Driver Supported EFI Version Protocol Instance\r
32//\r
33EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiVersion = {\r
34 sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), // Size of Protocol structure.\r
35 0 // Version number to be filled at start up.\r
36};\r
37\r
d6c55989
FT
38//\r
39// Template for NVM Express Pass Thru Mode data structure.\r
40//\r
41GLOBAL_REMOVE_IF_UNREFERENCED EFI_NVM_EXPRESS_PASS_THRU_MODE gEfiNvmExpressPassThruMode = {\r
42 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL | EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM,\r
43 sizeof (UINTN),\r
44 0x10100\r
45};\r
46\r
eb290d02
FT
47/**\r
48 Check if the specified Nvm Express device namespace is active, and create child handles\r
49 for them with BlockIo and DiskInfo protocol instances.\r
50\r
51 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
52 @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be\r
53 allocated and built. Caller must set the NamespaceId to zero if the\r
54 device path node will contain a valid UUID.\r
eb290d02
FT
55\r
56 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
57 @return Others Some error occurs when enumerating the namespaces.\r
58\r
59**/\r
60EFI_STATUS\r
61EnumerateNvmeDevNamespace (\r
62 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
d6c55989 63 UINT32 NamespaceId\r
eb290d02
FT
64 )\r
65{\r
66 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
67 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;\r
68 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
69 EFI_HANDLE DeviceHandle;\r
70 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
71 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
72 NVME_DEVICE_PRIVATE_DATA *Device;\r
73 EFI_STATUS Status;\r
74 UINT32 Lbads;\r
75 UINT32 Flbas;\r
76 UINT32 LbaFmtIdx;\r
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
137\r
138 Flbas = NamespaceData->Flbas;\r
2f34e065 139 LbaFmtIdx = Flbas & 0xF;\r
eb290d02
FT
140 Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;\r
141 Device->Media.BlockSize = (UINT32)1 << Lbads;\r
142\r
143 Device->Media.LastBlock = NamespaceData->Nsze - 1;\r
144 Device->Media.LogicalBlocksPerPhysicalBlock = 1;\r
145 Device->Media.LowestAlignedLba = 1;\r
146\r
147 //\r
148 // Create BlockIo Protocol instance\r
149 //\r
150 Device->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
151 Device->BlockIo.Media = &Device->Media;\r
152 Device->BlockIo.Reset = NvmeBlockIoReset;\r
153 Device->BlockIo.ReadBlocks = NvmeBlockIoReadBlocks;\r
154 Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks;\r
155 Device->BlockIo.FlushBlocks = NvmeBlockIoFlushBlocks;\r
156\r
754b489b
TF
157 //\r
158 // Create StorageSecurityProtocol Instance\r
159 //\r
160 Device->StorageSecurity.ReceiveData = NvmeStorageSecurityReceiveData;\r
161 Device->StorageSecurity.SendData = NvmeStorageSecuritySendData;\r
162\r
eb290d02
FT
163 //\r
164 // Create DiskInfo Protocol instance\r
165 //\r
d2a2678b 166 CopyMem (&Device->NamespaceData, NamespaceData, sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
eb290d02
FT
167 InitializeDiskInfo (Device);\r
168\r
169 //\r
170 // Create a Nvm Express Namespace Device Path Node\r
171 //\r
172 Status = Private->Passthru.BuildDevicePath (\r
173 &Private->Passthru,\r
174 Device->NamespaceId,\r
eb290d02
FT
175 &NewDevicePathNode\r
176 );\r
177\r
178 if (EFI_ERROR(Status)) {\r
179 goto Exit;\r
180 }\r
181\r
182 //\r
183 // Append the SSD node to the controller's device path\r
184 //\r
185 DevicePath = AppendDevicePathNode (ParentDevicePath, NewDevicePathNode);\r
186 if (DevicePath == NULL) {\r
187 Status = EFI_OUT_OF_RESOURCES;\r
188 goto Exit;\r
189 }\r
190\r
191 DeviceHandle = NULL;\r
192 RemainingDevicePath = DevicePath;\r
193 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
194 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
195 Status = EFI_ALREADY_STARTED;\r
196 FreePool (DevicePath);\r
197 goto Exit;\r
198 }\r
199\r
200 Device->DevicePath = DevicePath;\r
201\r
202 //\r
203 // Make sure the handle is NULL so we create a new handle\r
204 //\r
205 Device->DeviceHandle = NULL;\r
206\r
207 Status = gBS->InstallMultipleProtocolInterfaces (\r
208 &Device->DeviceHandle,\r
209 &gEfiDevicePathProtocolGuid,\r
210 Device->DevicePath,\r
211 &gEfiBlockIoProtocolGuid,\r
212 &Device->BlockIo,\r
213 &gEfiDiskInfoProtocolGuid,\r
214 &Device->DiskInfo,\r
215 NULL\r
216 );\r
217\r
218 if(EFI_ERROR(Status)) {\r
219 goto Exit;\r
220 }\r
754b489b
TF
221\r
222 //\r
223 // Check if the NVMe controller supports the Security Send and Security Receive commands\r
224 //\r
225 if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {\r
226 Status = gBS->InstallProtocolInterface (\r
227 &Device->DeviceHandle,\r
228 &gEfiStorageSecurityCommandProtocolGuid,\r
229 EFI_NATIVE_INTERFACE,\r
230 &Device->StorageSecurity\r
231 );\r
232 if(EFI_ERROR(Status)) {\r
233 gBS->UninstallMultipleProtocolInterfaces (\r
234 &Device->DeviceHandle,\r
235 &gEfiDevicePathProtocolGuid,\r
236 Device->DevicePath,\r
237 &gEfiBlockIoProtocolGuid,\r
238 &Device->BlockIo,\r
239 &gEfiDiskInfoProtocolGuid,\r
240 &Device->DiskInfo,\r
241 NULL\r
242 );\r
243 goto Exit;\r
244 }\r
245 }\r
246\r
eb290d02
FT
247 gBS->OpenProtocol (\r
248 Private->ControllerHandle,\r
beeeb22c
TF
249 &gEfiNvmExpressPassThruProtocolGuid,\r
250 (VOID **) &Private->Passthru,\r
eb290d02
FT
251 Private->DriverBindingHandle,\r
252 Device->DeviceHandle,\r
253 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
254 );\r
255\r
7b8883c6
FT
256 //\r
257 // Dump NvmExpress Identify Namespace Data\r
258 //\r
259 DEBUG ((EFI_D_INFO, " == NVME IDENTIFY NAMESPACE [%d] DATA ==\n", NamespaceId));\r
260 DEBUG ((EFI_D_INFO, " NSZE : 0x%x\n", NamespaceData->Nsze));\r
261 DEBUG ((EFI_D_INFO, " NCAP : 0x%x\n", NamespaceData->Ncap));\r
262 DEBUG ((EFI_D_INFO, " NUSE : 0x%x\n", NamespaceData->Nuse));\r
263 DEBUG ((EFI_D_INFO, " LBAF0.LBADS : 0x%x\n", (NamespaceData->LbaFormat[0].Lbads)));\r
264\r
eb290d02
FT
265 //\r
266 // Build controller name for Component Name (2) protocol.\r
267 //\r
268 UnicodeSPrintAsciiFormat (Device->ModelName, sizeof (Device->ModelName), "%a-%a-%x", Private->ControllerData->Sn, Private->ControllerData->Mn, NamespaceData->Eui64);\r
269\r
270 AddUnicodeString2 (\r
271 "eng",\r
272 gNvmExpressComponentName.SupportedLanguages,\r
273 &Device->ControllerNameTable,\r
274 Device->ModelName,\r
275 TRUE\r
276 );\r
277\r
278 AddUnicodeString2 (\r
279 "en",\r
280 gNvmExpressComponentName2.SupportedLanguages,\r
281 &Device->ControllerNameTable,\r
282 Device->ModelName,\r
283 FALSE\r
284 );\r
285 }\r
286\r
287Exit:\r
288 if(NamespaceData != NULL) {\r
289 FreePool (NamespaceData);\r
290 }\r
291\r
6a54db85
FT
292 if (NewDevicePathNode != NULL) {\r
293 FreePool (NewDevicePathNode);\r
294 }\r
295\r
eb290d02
FT
296 if(EFI_ERROR(Status) && (Device != NULL) && (Device->DevicePath != NULL)) {\r
297 FreePool (Device->DevicePath);\r
298 }\r
299 if(EFI_ERROR(Status) && (Device != NULL)) {\r
300 FreePool (Device);\r
301 }\r
302 return Status;\r
303}\r
304\r
305/**\r
306 Discover all Nvm Express device namespaces, and create child handles for them with BlockIo\r
307 and DiskInfo protocol instances.\r
308\r
309 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
310\r
311 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
312 @return Others Some error occurs when enumerating the namespaces.\r
313\r
314**/\r
315EFI_STATUS\r
316DiscoverAllNamespaces (\r
317 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
318 )\r
319{\r
320 EFI_STATUS Status;\r
321 UINT32 NamespaceId;\r
d6c55989 322 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *Passthru;\r
eb290d02
FT
323\r
324 NamespaceId = 0xFFFFFFFF;\r
eb290d02
FT
325 Passthru = &Private->Passthru;\r
326\r
327 while (TRUE) {\r
328 Status = Passthru->GetNextNamespace (\r
329 Passthru,\r
d6c55989 330 (UINT32 *)&NamespaceId\r
eb290d02
FT
331 );\r
332\r
333 if (EFI_ERROR (Status)) {\r
334 break;\r
335 }\r
336\r
337 Status = EnumerateNvmeDevNamespace (\r
338 Private,\r
d6c55989 339 NamespaceId\r
eb290d02
FT
340 );\r
341\r
342 if (EFI_ERROR(Status)) {\r
343 continue;\r
344 }\r
345 }\r
346\r
347 return EFI_SUCCESS;\r
348}\r
349\r
350/**\r
351 Unregisters a Nvm Express device namespace.\r
352\r
353 This function removes the protocols installed on the controller handle and\r
354 frees the resources allocated for the namespace.\r
355\r
356 @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.\r
357 @param Controller The controller handle of the namespace.\r
358 @param Handle The child handle.\r
359\r
360 @retval EFI_SUCCESS The namespace is successfully unregistered.\r
361 @return Others Some error occurs when unregistering the namespace.\r
362\r
363**/\r
364EFI_STATUS\r
365UnregisterNvmeNamespace (\r
366 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
367 IN EFI_HANDLE Controller,\r
368 IN EFI_HANDLE Handle\r
369 )\r
370{\r
371 EFI_STATUS Status;\r
eb290d02
FT
372 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
373 NVME_DEVICE_PRIVATE_DATA *Device;\r
beeeb22c 374 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
754b489b 375 EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;\r
eb290d02
FT
376\r
377 BlockIo = NULL;\r
378\r
379 Status = gBS->OpenProtocol (\r
380 Handle,\r
381 &gEfiBlockIoProtocolGuid,\r
382 (VOID **) &BlockIo,\r
383 This->DriverBindingHandle,\r
384 Controller,\r
385 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
386 );\r
387 if (EFI_ERROR (Status)) {\r
388 return Status;\r
389 }\r
390\r
beeeb22c
TF
391 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo);\r
392 Private = Device->Controller;\r
eb290d02
FT
393\r
394 //\r
395 // Close the child handle\r
396 //\r
397 gBS->CloseProtocol (\r
398 Controller,\r
beeeb22c 399 &gEfiNvmExpressPassThruProtocolGuid,\r
eb290d02
FT
400 This->DriverBindingHandle,\r
401 Handle\r
402 );\r
403\r
404 //\r
405 // The Nvm Express driver installs the BlockIo and DiskInfo in the DriverBindingStart().\r
406 // Here should uninstall both of them.\r
407 //\r
408 Status = gBS->UninstallMultipleProtocolInterfaces (\r
409 Handle,\r
410 &gEfiDevicePathProtocolGuid,\r
411 Device->DevicePath,\r
412 &gEfiBlockIoProtocolGuid,\r
413 &Device->BlockIo,\r
414 &gEfiDiskInfoProtocolGuid,\r
415 &Device->DiskInfo,\r
416 NULL\r
417 );\r
418\r
419 if (EFI_ERROR (Status)) {\r
420 gBS->OpenProtocol (\r
421 Controller,\r
beeeb22c
TF
422 &gEfiNvmExpressPassThruProtocolGuid,\r
423 (VOID **) &Private->Passthru,\r
eb290d02
FT
424 This->DriverBindingHandle,\r
425 Handle,\r
426 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
427 );\r
428 return Status;\r
429 }\r
430\r
754b489b
TF
431 //\r
432 // If Storage Security Command Protocol is installed, then uninstall this protocol.\r
433 //\r
434 Status = gBS->OpenProtocol (\r
435 Handle,\r
436 &gEfiStorageSecurityCommandProtocolGuid,\r
437 (VOID **) &StorageSecurity,\r
438 This->DriverBindingHandle,\r
439 Controller,\r
440 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
441 );\r
442\r
443 if (!EFI_ERROR (Status)) {\r
444 Status = gBS->UninstallProtocolInterface (\r
445 Handle,\r
446 &gEfiStorageSecurityCommandProtocolGuid,\r
447 &Device->StorageSecurity\r
448 );\r
449 if (EFI_ERROR (Status)) {\r
450 gBS->OpenProtocol (\r
451 Controller,\r
452 &gEfiNvmExpressPassThruProtocolGuid,\r
453 (VOID **) &Private->Passthru,\r
454 This->DriverBindingHandle,\r
455 Handle,\r
456 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
457 );\r
458 return Status;\r
459 }\r
460 }\r
461\r
eb290d02
FT
462 if(Device->DevicePath != NULL) {\r
463 FreePool (Device->DevicePath);\r
464 }\r
465\r
466 if (Device->ControllerNameTable != NULL) {\r
467 FreeUnicodeStringTable (Device->ControllerNameTable);\r
468 }\r
469\r
6a54db85
FT
470 FreePool (Device);\r
471\r
eb290d02
FT
472 return EFI_SUCCESS;\r
473}\r
474\r
475/**\r
476 Tests to see if this driver supports a given controller. If a child device is provided,\r
477 it further tests to see if this driver supports creating a handle for the specified child device.\r
478\r
479 This function checks to see if the driver specified by This supports the device specified by\r
480 ControllerHandle. Drivers will typically use the device path attached to\r
481 ControllerHandle and/or the services from the bus I/O abstraction attached to\r
482 ControllerHandle to determine if the driver supports ControllerHandle. This function\r
483 may be called many times during platform initialization. In order to reduce boot times, the tests\r
484 performed by this function must be very small, and take as little time as possible to execute. This\r
485 function must not change the state of any hardware devices, and this function must be aware that the\r
486 device specified by ControllerHandle may already be managed by the same driver or a\r
487 different driver. This function must match its calls to AllocatePages() with FreePages(),\r
488 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
489 Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
490 already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
491 to guarantee the state of ControllerHandle is not modified by this function.\r
492\r
493 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
494 @param[in] ControllerHandle The handle of the controller to test. This handle\r
495 must support a protocol interface that supplies\r
496 an I/O abstraction to the driver.\r
497 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
498 parameter is ignored by device drivers, and is optional for bus\r
499 drivers. For bus drivers, if this parameter is not NULL, then\r
500 the bus driver must determine if the bus controller specified\r
501 by ControllerHandle and the child controller specified\r
502 by RemainingDevicePath are both supported by this\r
503 bus driver.\r
504\r
505 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
506 RemainingDevicePath is supported by the driver specified by This.\r
507 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
508 RemainingDevicePath is already being managed by the driver\r
509 specified by This.\r
510 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
511 RemainingDevicePath is already being managed by a different\r
512 driver or an application that requires exclusive access.\r
513 Currently not implemented.\r
514 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
515 RemainingDevicePath is not supported by the driver specified by This.\r
516**/\r
517EFI_STATUS\r
518EFIAPI\r
519NvmExpressDriverBindingSupported (\r
520 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
521 IN EFI_HANDLE Controller,\r
522 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
523 )\r
524{\r
525 EFI_STATUS Status;\r
526 EFI_DEV_PATH_PTR DevicePathNode;\r
527 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
528 EFI_PCI_IO_PROTOCOL *PciIo;\r
529 UINT8 ClassCode[3];\r
530\r
531 //\r
532 // Check whether device path is valid\r
533 //\r
534 if (RemainingDevicePath != NULL) {\r
535 //\r
536 // Check if RemainingDevicePath is the End of Device Path Node,\r
537 // if yes, go on checking other conditions\r
538 //\r
539 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
540 //\r
541 // If RemainingDevicePath isn't the End of Device Path Node,\r
542 // check its validation\r
543 //\r
544 DevicePathNode.DevPath = RemainingDevicePath;\r
545\r
546 if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||\r
547 (DevicePathNode.DevPath->SubType != MSG_NVME_NAMESPACE_DP) ||\r
754b489b
TF
548 (DevicePathNodeLength(DevicePathNode.DevPath) != sizeof(NVME_NAMESPACE_DEVICE_PATH))) {\r
549 return EFI_UNSUPPORTED;\r
eb290d02
FT
550 }\r
551 }\r
552 }\r
553\r
554 //\r
555 // Open the EFI Device Path protocol needed to perform the supported test\r
556 //\r
557 Status = gBS->OpenProtocol (\r
558 Controller,\r
559 &gEfiDevicePathProtocolGuid,\r
560 (VOID **) &ParentDevicePath,\r
561 This->DriverBindingHandle,\r
562 Controller,\r
563 EFI_OPEN_PROTOCOL_BY_DRIVER\r
564 );\r
565 if (Status == EFI_ALREADY_STARTED) {\r
566 return EFI_SUCCESS;\r
567 }\r
568\r
569 if (EFI_ERROR (Status)) {\r
570 return Status;\r
571 }\r
572\r
573 //\r
574 // Close protocol, don't use device path protocol in the Support() function\r
575 //\r
576 gBS->CloseProtocol (\r
577 Controller,\r
578 &gEfiDevicePathProtocolGuid,\r
579 This->DriverBindingHandle,\r
580 Controller\r
581 );\r
582\r
583 //\r
584 // Attempt to Open PCI I/O Protocol\r
585 //\r
586 Status = gBS->OpenProtocol (\r
587 Controller,\r
588 &gEfiPciIoProtocolGuid,\r
589 (VOID **) &PciIo,\r
590 This->DriverBindingHandle,\r
591 Controller,\r
592 EFI_OPEN_PROTOCOL_BY_DRIVER\r
593 );\r
594 if (Status == EFI_ALREADY_STARTED) {\r
595 return EFI_SUCCESS;\r
596 }\r
597\r
598 if (EFI_ERROR (Status)) {\r
599 return Status;\r
600 }\r
601\r
602 //\r
603 // Now further check the PCI header: Base class (offset 0x0B) and Sub Class (offset 0x0A).\r
604 // This controller should be a Nvm Express controller.\r
605 //\r
606 Status = PciIo->Pci.Read (\r
607 PciIo,\r
608 EfiPciIoWidthUint8,\r
609 PCI_CLASSCODE_OFFSET,\r
610 sizeof (ClassCode),\r
611 ClassCode\r
612 );\r
613 if (EFI_ERROR (Status)) {\r
614 goto Done;\r
615 }\r
616\r
617 //\r
618 // Examine Nvm Express controller PCI Configuration table fields\r
619 //\r
620 if ((ClassCode[0] != PCI_IF_NVMHCI) || (ClassCode[1] != PCI_CLASS_MASS_STORAGE_NVM) || (ClassCode[2] != PCI_CLASS_MASS_STORAGE)) {\r
621 Status = EFI_UNSUPPORTED;\r
622 }\r
623\r
624Done:\r
625 gBS->CloseProtocol (\r
626 Controller,\r
627 &gEfiPciIoProtocolGuid,\r
628 This->DriverBindingHandle,\r
629 Controller\r
630 );\r
631\r
632 return Status;\r
633}\r
634\r
635\r
636/**\r
637 Starts a device controller or a bus controller.\r
638\r
639 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
640 As a result, much of the error checking on the parameters to Start() has been moved into this\r
641 common boot service. It is legal to call Start() from other locations,\r
642 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
643 1. ControllerHandle must be a valid EFI_HANDLE.\r
644 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
645 EFI_DEVICE_PATH_PROTOCOL.\r
646 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
647 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
648\r
649 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
650 @param[in] ControllerHandle The handle of the controller to start. This handle\r
651 must support a protocol interface that supplies\r
652 an I/O abstraction to the driver.\r
653 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
654 parameter is ignored by device drivers, and is optional for bus\r
655 drivers. For a bus driver, if this parameter is NULL, then handles\r
656 for all the children of Controller are created by this driver.\r
657 If this parameter is not NULL and the first Device Path Node is\r
658 not the End of Device Path Node, then only the handle for the\r
659 child device specified by the first Device Path Node of\r
660 RemainingDevicePath is created by this driver.\r
661 If the first Device Path Node of RemainingDevicePath is\r
662 the End of Device Path Node, no child handle is created by this\r
663 driver.\r
664\r
665 @retval EFI_SUCCESS The device was started.\r
666 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
667 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
668 @retval Others The driver failded to start the device.\r
669\r
670**/\r
671EFI_STATUS\r
672EFIAPI\r
673NvmExpressDriverBindingStart (\r
674 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
675 IN EFI_HANDLE Controller,\r
676 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
677 )\r
678{\r
d6c55989
FT
679 EFI_STATUS Status;\r
680 EFI_PCI_IO_PROTOCOL *PciIo;\r
681 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
682 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
683 UINT32 NamespaceId;\r
684 EFI_PHYSICAL_ADDRESS MappedAddr;\r
685 UINTN Bytes;\r
686 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *Passthru;\r
eb290d02
FT
687\r
688 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: start\n"));\r
689\r
d6c55989
FT
690 Private = NULL;\r
691 Passthru = NULL;\r
eb290d02
FT
692 ParentDevicePath = NULL;\r
693\r
694 Status = gBS->OpenProtocol (\r
695 Controller,\r
696 &gEfiDevicePathProtocolGuid,\r
697 (VOID **) &ParentDevicePath,\r
698 This->DriverBindingHandle,\r
699 Controller,\r
700 EFI_OPEN_PROTOCOL_BY_DRIVER\r
701 );\r
702 if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
703 return Status;\r
704 }\r
705\r
706 Status = gBS->OpenProtocol (\r
707 Controller,\r
708 &gEfiPciIoProtocolGuid,\r
709 (VOID **) &PciIo,\r
710 This->DriverBindingHandle,\r
711 Controller,\r
712 EFI_OPEN_PROTOCOL_BY_DRIVER\r
713 );\r
714\r
715 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
716 return Status;\r
717 }\r
718\r
719 //\r
720 // Check EFI_ALREADY_STARTED to reuse the original NVME_CONTROLLER_PRIVATE_DATA.\r
721 //\r
722 if (Status != EFI_ALREADY_STARTED) {\r
723 Private = AllocateZeroPool (sizeof (NVME_CONTROLLER_PRIVATE_DATA));\r
724\r
725 if (Private == NULL) {\r
726 DEBUG ((EFI_D_ERROR, "NvmExpressDriverBindingStart: allocating pool for Nvme Private Data failed!\n"));\r
727 Status = EFI_OUT_OF_RESOURCES;\r
d6c55989 728 goto Exit;\r
eb290d02
FT
729 }\r
730\r
731 //\r
732 // 4 x 4kB aligned buffers will be carved out of this buffer.\r
733 // 1st 4kB boundary is the start of the admin submission queue.\r
734 // 2nd 4kB boundary is the start of the admin completion queue.\r
735 // 3rd 4kB boundary is the start of I/O submission queue #1.\r
736 // 4th 4kB boundary is the start of I/O completion queue #1.\r
737 //\r
738 // Allocate 4 pages of memory, then map it for bus master read and write.\r
739 //\r
740 Status = PciIo->AllocateBuffer (\r
741 PciIo,\r
742 AllocateAnyPages,\r
743 EfiBootServicesData,\r
7b8883c6 744 4,\r
eb290d02
FT
745 (VOID**)&Private->Buffer,\r
746 0\r
747 );\r
748 if (EFI_ERROR (Status)) {\r
d6c55989 749 goto Exit;\r
eb290d02
FT
750 }\r
751\r
752 Bytes = EFI_PAGES_TO_SIZE (4);\r
753 Status = PciIo->Map (\r
754 PciIo,\r
755 EfiPciIoOperationBusMasterCommonBuffer,\r
756 Private->Buffer,\r
757 &Bytes,\r
758 &MappedAddr,\r
759 &Private->Mapping\r
760 );\r
761\r
762 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (4))) {\r
d6c55989 763 goto Exit;\r
eb290d02
FT
764 }\r
765\r
766 Private->BufferPciAddr = (UINT8 *)(UINTN)MappedAddr;\r
767 ZeroMem (Private->Buffer, EFI_PAGES_TO_SIZE (4));\r
768\r
769 Private->Signature = NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE;\r
770 Private->ControllerHandle = Controller;\r
771 Private->ImageHandle = This->DriverBindingHandle;\r
772 Private->DriverBindingHandle = This->DriverBindingHandle;\r
773 Private->PciIo = PciIo;\r
774 Private->ParentDevicePath = ParentDevicePath;\r
775 Private->Passthru.Mode = &Private->PassThruMode;\r
776 Private->Passthru.PassThru = NvmExpressPassThru;\r
777 Private->Passthru.GetNextNamespace = NvmExpressGetNextNamespace;\r
778 Private->Passthru.BuildDevicePath = NvmExpressBuildDevicePath;\r
779 Private->Passthru.GetNamespace = NvmExpressGetNamespace;\r
d6c55989 780 CopyMem (&Private->PassThruMode, &gEfiNvmExpressPassThruMode, sizeof (EFI_NVM_EXPRESS_PASS_THRU_MODE));\r
eb290d02
FT
781\r
782 Status = NvmeControllerInit (Private);\r
eb290d02 783 if (EFI_ERROR(Status)) {\r
d6c55989 784 goto Exit;\r
eb290d02
FT
785 }\r
786\r
787 Status = gBS->InstallMultipleProtocolInterfaces (\r
788 &Controller,\r
d6c55989
FT
789 &gEfiNvmExpressPassThruProtocolGuid,\r
790 &Private->Passthru,\r
eb290d02
FT
791 NULL\r
792 );\r
793 if (EFI_ERROR (Status)) {\r
d6c55989 794 goto Exit;\r
eb290d02
FT
795 }\r
796 } else {\r
797 Status = gBS->OpenProtocol (\r
798 Controller,\r
d6c55989
FT
799 &gEfiNvmExpressPassThruProtocolGuid,\r
800 (VOID **) &Passthru,\r
eb290d02
FT
801 This->DriverBindingHandle,\r
802 Controller,\r
803 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
804 );\r
805 if (EFI_ERROR (Status)) {\r
d6c55989 806 goto Exit;\r
eb290d02 807 }\r
d6c55989
FT
808\r
809 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (Passthru);\r
eb290d02
FT
810 }\r
811\r
812 if (RemainingDevicePath == NULL) {\r
813 //\r
814 // Enumerate all NVME namespaces in the controller\r
815 //\r
816 Status = DiscoverAllNamespaces (\r
817 Private\r
818 );\r
819\r
820 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
821 //\r
822 // Enumerate the specified NVME namespace\r
823 //\r
824 Status = Private->Passthru.GetNamespace (\r
825 &Private->Passthru,\r
826 RemainingDevicePath,\r
d6c55989 827 &NamespaceId\r
eb290d02
FT
828 );\r
829\r
830 if (!EFI_ERROR (Status)) {\r
d6c55989
FT
831 Status = EnumerateNvmeDevNamespace (\r
832 Private,\r
833 NamespaceId\r
834 );\r
eb290d02
FT
835 }\r
836 }\r
837\r
838 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end successfully\n"));\r
839 return EFI_SUCCESS;\r
840\r
d6c55989 841Exit:\r
eb290d02
FT
842 if ((Private != NULL) && (Private->Mapping != NULL)) {\r
843 PciIo->Unmap (PciIo, Private->Mapping);\r
844 }\r
845\r
846 if ((Private != NULL) && (Private->Buffer != NULL)) {\r
847 PciIo->FreeBuffer (PciIo, 4, Private->Buffer);\r
848 }\r
849\r
850 if (Private != NULL) {\r
851 FreePool (Private);\r
852 }\r
853\r
854 gBS->CloseProtocol (\r
855 Controller,\r
856 &gEfiPciIoProtocolGuid,\r
857 This->DriverBindingHandle,\r
858 Controller\r
859 );\r
860\r
861 gBS->CloseProtocol (\r
862 Controller,\r
863 &gEfiDevicePathProtocolGuid,\r
864 This->DriverBindingHandle,\r
865 Controller\r
866 );\r
867\r
868 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end with %r\n", Status));\r
869\r
870 return Status;\r
871}\r
872\r
873\r
874/**\r
875 Stops a device controller or a bus controller.\r
876\r
877 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
878 As a result, much of the error checking on the parameters to Stop() has been moved\r
879 into this common boot service. It is legal to call Stop() from other locations,\r
880 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
881 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
882 same driver's Start() function.\r
883 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
884 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
885 Start() function, and the Start() function must have called OpenProtocol() on\r
886 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
887\r
888 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
889 @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
890 support a bus specific I/O protocol for the driver\r
891 to use to stop the device.\r
892 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
893 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
894 if NumberOfChildren is 0.\r
895\r
896 @retval EFI_SUCCESS The device was stopped.\r
897 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
898\r
899**/\r
900EFI_STATUS\r
901EFIAPI\r
902NvmExpressDriverBindingStop (\r
903 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
904 IN EFI_HANDLE Controller,\r
905 IN UINTN NumberOfChildren,\r
906 IN EFI_HANDLE *ChildHandleBuffer\r
907 )\r
908{\r
909 EFI_STATUS Status;\r
910 BOOLEAN AllChildrenStopped;\r
911 UINTN Index;\r
912 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
beeeb22c 913 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *PassThru;\r
eb290d02
FT
914\r
915 if (NumberOfChildren == 0) {\r
916 Status = gBS->OpenProtocol (\r
917 Controller,\r
beeeb22c
TF
918 &gEfiNvmExpressPassThruProtocolGuid,\r
919 (VOID **) &PassThru,\r
eb290d02
FT
920 This->DriverBindingHandle,\r
921 Controller,\r
922 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
923 );\r
924\r
925 if (!EFI_ERROR (Status)) {\r
beeeb22c 926 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (PassThru);\r
eb290d02
FT
927 gBS->UninstallMultipleProtocolInterfaces (\r
928 Controller,\r
beeeb22c
TF
929 &gEfiNvmExpressPassThruProtocolGuid,\r
930 PassThru,\r
eb290d02
FT
931 NULL\r
932 );\r
933\r
934 if (Private->Mapping != NULL) {\r
935 Private->PciIo->Unmap (Private->PciIo, Private->Mapping);\r
936 }\r
937\r
938 if (Private->Buffer != NULL) {\r
939 Private->PciIo->FreeBuffer (Private->PciIo, 4, Private->Buffer);\r
940 }\r
941\r
942 FreePool (Private->ControllerData);\r
943 FreePool (Private);\r
944 }\r
945\r
946 gBS->CloseProtocol (\r
947 Controller,\r
948 &gEfiPciIoProtocolGuid,\r
949 This->DriverBindingHandle,\r
950 Controller\r
951 );\r
952 gBS->CloseProtocol (\r
953 Controller,\r
954 &gEfiDevicePathProtocolGuid,\r
955 This->DriverBindingHandle,\r
956 Controller\r
957 );\r
958 return EFI_SUCCESS;\r
959 }\r
960\r
961 AllChildrenStopped = TRUE;\r
962\r
963 for (Index = 0; Index < NumberOfChildren; Index++) {\r
964 Status = UnregisterNvmeNamespace (This, Controller, ChildHandleBuffer[Index]);\r
965 if (EFI_ERROR (Status)) {\r
966 AllChildrenStopped = FALSE;\r
967 }\r
968 }\r
969\r
970 if (!AllChildrenStopped) {\r
971 return EFI_DEVICE_ERROR;\r
972 }\r
973\r
974 return EFI_SUCCESS;\r
975}\r
976\r
977/**\r
978 This is the unload handle for the NVM Express driver.\r
979\r
980 Disconnect the driver specified by ImageHandle from the NVMe device in the handle database.\r
981 Uninstall all the protocols installed in the driver.\r
982\r
983 @param[in] ImageHandle The drivers' driver image.\r
984\r
985 @retval EFI_SUCCESS The image is unloaded.\r
986 @retval Others Failed to unload the image.\r
987\r
988**/\r
989EFI_STATUS\r
990EFIAPI\r
991NvmExpressUnload (\r
992 IN EFI_HANDLE ImageHandle\r
993 )\r
994{\r
995 EFI_STATUS Status;\r
996 EFI_HANDLE *DeviceHandleBuffer;\r
997 UINTN DeviceHandleCount;\r
998 UINTN Index;\r
eb290d02
FT
999 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
1000 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
1001\r
1002 //\r
0a2326af
FT
1003 // Get the list of the device handles managed by this driver.\r
1004 // If there is an error getting the list, then means the driver\r
1005 // doesn't manage any device. At this way, we would only close\r
1006 // those protocols installed at image handle.\r
eb290d02 1007 //\r
0a2326af 1008 DeviceHandleBuffer = NULL;\r
eb290d02 1009 Status = gBS->LocateHandleBuffer (\r
0a2326af 1010 ByProtocol,\r
beeeb22c 1011 &gEfiNvmExpressPassThruProtocolGuid,\r
eb290d02
FT
1012 NULL,\r
1013 &DeviceHandleCount,\r
1014 &DeviceHandleBuffer\r
1015 );\r
1016\r
0a2326af
FT
1017 if (!EFI_ERROR (Status)) {\r
1018 //\r
1019 // Disconnect the driver specified by ImageHandle from all\r
1020 // the devices in the handle database.\r
1021 //\r
1022 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1023 Status = gBS->DisconnectController (\r
1024 DeviceHandleBuffer[Index],\r
1025 ImageHandle,\r
1026 NULL\r
1027 );\r
1028 if (EFI_ERROR (Status)) {\r
1029 goto EXIT;\r
1030 }\r
1031 }\r
eb290d02
FT
1032 }\r
1033\r
1034 //\r
0a2326af 1035 // Uninstall all the protocols installed in the driver entry point\r
eb290d02 1036 //\r
0a2326af
FT
1037 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1038 ImageHandle,\r
1039 &gEfiDriverBindingProtocolGuid,\r
1040 &gNvmExpressDriverBinding,\r
1041 &gEfiDriverSupportedEfiVersionProtocolGuid,\r
1042 &gNvmExpressDriverSupportedEfiVersion,\r
1043 NULL\r
1044 );\r
1045\r
1046 if (EFI_ERROR (Status)) {\r
1047 goto EXIT;\r
eb290d02
FT
1048 }\r
1049\r
1050 //\r
0a2326af
FT
1051 // Note we have to one by one uninstall the following protocols.\r
1052 // It's because some of them are optionally installed based on\r
1053 // the following PCD settings.\r
1054 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable\r
1055 // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable\r
1056 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable\r
1057 // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable\r
eb290d02 1058 //\r
0a2326af
FT
1059 Status = gBS->HandleProtocol (\r
1060 ImageHandle,\r
1061 &gEfiComponentNameProtocolGuid,\r
1062 (VOID **) &ComponentName\r
1063 );\r
1064 if (!EFI_ERROR (Status)) {\r
eb290d02
FT
1065 gBS->UninstallProtocolInterface (\r
1066 ImageHandle,\r
0a2326af
FT
1067 &gEfiComponentNameProtocolGuid,\r
1068 ComponentName\r
eb290d02 1069 );\r
0a2326af 1070 }\r
eb290d02 1071\r
0a2326af
FT
1072 Status = gBS->HandleProtocol (\r
1073 ImageHandle,\r
1074 &gEfiComponentName2ProtocolGuid,\r
1075 (VOID **) &ComponentName2\r
1076 );\r
1077 if (!EFI_ERROR (Status)) {\r
1078 gBS->UninstallProtocolInterface (\r
1079 ImageHandle,\r
1080 &gEfiComponentName2ProtocolGuid,\r
1081 ComponentName2\r
1082 );\r
eb290d02
FT
1083 }\r
1084\r
0a2326af
FT
1085 Status = EFI_SUCCESS;\r
1086\r
1087EXIT:\r
eb290d02
FT
1088 //\r
1089 // Free the buffer containing the list of handles from the handle database\r
1090 //\r
1091 if (DeviceHandleBuffer != NULL) {\r
1092 gBS->FreePool (DeviceHandleBuffer);\r
1093 }\r
0a2326af 1094 return Status;\r
eb290d02
FT
1095}\r
1096\r
1097/**\r
1098 The entry point for Nvm Express driver, used to install Nvm Express driver on the ImageHandle.\r
1099\r
1100 @param ImageHandle The firmware allocated handle for this driver image.\r
1101 @param SystemTable Pointer to the EFI system table.\r
1102\r
1103 @retval EFI_SUCCESS Driver loaded.\r
1104 @retval other Driver not loaded.\r
1105\r
1106**/\r
1107EFI_STATUS\r
1108EFIAPI\r
1109NvmExpressDriverEntry (\r
1110 IN EFI_HANDLE ImageHandle,\r
1111 IN EFI_SYSTEM_TABLE *SystemTable\r
1112 )\r
1113{\r
1114 EFI_STATUS Status;\r
1115\r
1116 Status = EfiLibInstallDriverBindingComponentName2 (\r
1117 ImageHandle,\r
1118 SystemTable,\r
1119 &gNvmExpressDriverBinding,\r
1120 ImageHandle,\r
1121 &gNvmExpressComponentName,\r
1122 &gNvmExpressComponentName2\r
1123 );\r
1124 ASSERT_EFI_ERROR (Status);\r
1125\r
1126 //\r
1127 // Install EFI Driver Supported EFI Version Protocol required for\r
1128 // EFI drivers that are on PCI and other plug in cards.\r
1129 //\r
1130 gNvmExpressDriverSupportedEfiVersion.FirmwareVersion = 0x00020028;\r
1131 Status = gBS->InstallMultipleProtocolInterfaces (\r
1132 &ImageHandle,\r
1133 &gEfiDriverSupportedEfiVersionProtocolGuid,\r
1134 &gNvmExpressDriverSupportedEfiVersion,\r
1135 NULL\r
1136 );\r
1137 ASSERT_EFI_ERROR (Status);\r
1138 return Status;\r
1139}\r