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