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