]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
MdeModulePkg/NvmExpressDxe: Fix some bugs
[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
5 Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
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
38/**\r
39 Check if the specified Nvm Express device namespace is active, and create child handles\r
40 for them with BlockIo and DiskInfo protocol instances.\r
41\r
42 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
43 @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be\r
44 allocated and built. Caller must set the NamespaceId to zero if the\r
45 device path node will contain a valid UUID.\r
46 @param[in] NamespaceUuid The NVM Express namespace UUID for which a device path node is to be\r
47 allocated and built. UUID will only be valid of the Namespace ID is zero.\r
48\r
49 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
50 @return Others Some error occurs when enumerating the namespaces.\r
51\r
52**/\r
53EFI_STATUS\r
54EnumerateNvmeDevNamespace (\r
55 IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
56 UINT32 NamespaceId,\r
57 UINT64 NamespaceUuid\r
58 )\r
59{\r
60 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
61 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;\r
62 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
63 EFI_HANDLE DeviceHandle;\r
64 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
65 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
66 NVME_DEVICE_PRIVATE_DATA *Device;\r
67 EFI_STATUS Status;\r
68 UINT32 Lbads;\r
69 UINT32 Flbas;\r
70 UINT32 LbaFmtIdx;\r
71\r
72 NewDevicePathNode = NULL;\r
73 DevicePath = NULL;\r
74 Device = NULL;\r
75\r
76 //\r
77 // Allocate a buffer for Identify Namespace data\r
78 //\r
79 NamespaceData = AllocateZeroPool(sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
80 if(NamespaceData == NULL) {\r
81 return EFI_OUT_OF_RESOURCES;\r
82 }\r
83\r
84 ParentDevicePath = Private->ParentDevicePath;\r
85 //\r
86 // Identify Namespace\r
87 //\r
88 Status = NvmeIdentifyNamespace (\r
89 Private,\r
90 NamespaceId,\r
91 (VOID *)NamespaceData\r
92 );\r
93 if (EFI_ERROR(Status)) {\r
94 goto Exit;\r
95 }\r
96 //\r
97 // Validate Namespace\r
98 //\r
99 if (NamespaceData->Ncap == 0) {\r
100 Status = EFI_DEVICE_ERROR;\r
101 } else {\r
102 //\r
103 // allocate device private data for each discovered namespace\r
104 //\r
105 Device = AllocateZeroPool(sizeof(NVME_DEVICE_PRIVATE_DATA));\r
106 if (Device == NULL) {\r
107 goto Exit;\r
108 }\r
109\r
110 //\r
111 // Initialize SSD namespace instance data\r
112 //\r
113 Device->Signature = NVME_DEVICE_PRIVATE_DATA_SIGNATURE;\r
114 Device->NamespaceId = NamespaceId;\r
115 Device->NamespaceUuid = NamespaceData->Eui64;\r
116\r
117 Device->ControllerHandle = Private->ControllerHandle;\r
118 Device->DriverBindingHandle = Private->DriverBindingHandle;\r
119 Device->Controller = Private;\r
120\r
121 //\r
122 // Build BlockIo media structure\r
123 //\r
124 Device->Media.MediaId = 0;\r
125 Device->Media.RemovableMedia = FALSE;\r
126 Device->Media.MediaPresent = TRUE;\r
127 Device->Media.LogicalPartition = FALSE;\r
128 Device->Media.ReadOnly = FALSE;\r
129 Device->Media.WriteCaching = FALSE;\r
130\r
131 Flbas = NamespaceData->Flbas;\r
132 LbaFmtIdx = Flbas & 3;\r
133 Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;\r
134 Device->Media.BlockSize = (UINT32)1 << Lbads;\r
135\r
136 Device->Media.LastBlock = NamespaceData->Nsze - 1;\r
137 Device->Media.LogicalBlocksPerPhysicalBlock = 1;\r
138 Device->Media.LowestAlignedLba = 1;\r
139\r
140 //\r
141 // Create BlockIo Protocol instance\r
142 //\r
143 Device->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
144 Device->BlockIo.Media = &Device->Media;\r
145 Device->BlockIo.Reset = NvmeBlockIoReset;\r
146 Device->BlockIo.ReadBlocks = NvmeBlockIoReadBlocks;\r
147 Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks;\r
148 Device->BlockIo.FlushBlocks = NvmeBlockIoFlushBlocks;\r
149\r
150 //\r
151 // Create DiskInfo Protocol instance\r
152 //\r
153 InitializeDiskInfo (Device);\r
154\r
155 //\r
156 // Create a Nvm Express Namespace Device Path Node\r
157 //\r
158 Status = Private->Passthru.BuildDevicePath (\r
159 &Private->Passthru,\r
160 Device->NamespaceId,\r
161 Device->NamespaceUuid,\r
162 &NewDevicePathNode\r
163 );\r
164\r
165 if (EFI_ERROR(Status)) {\r
166 goto Exit;\r
167 }\r
168\r
169 //\r
170 // Append the SSD node to the controller's device path\r
171 //\r
172 DevicePath = AppendDevicePathNode (ParentDevicePath, NewDevicePathNode);\r
173 if (DevicePath == NULL) {\r
174 Status = EFI_OUT_OF_RESOURCES;\r
175 goto Exit;\r
176 }\r
177\r
178 DeviceHandle = NULL;\r
179 RemainingDevicePath = DevicePath;\r
180 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
181 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
182 Status = EFI_ALREADY_STARTED;\r
183 FreePool (DevicePath);\r
184 goto Exit;\r
185 }\r
186\r
187 Device->DevicePath = DevicePath;\r
188\r
189 //\r
190 // Make sure the handle is NULL so we create a new handle\r
191 //\r
192 Device->DeviceHandle = NULL;\r
193\r
194 Status = gBS->InstallMultipleProtocolInterfaces (\r
195 &Device->DeviceHandle,\r
196 &gEfiDevicePathProtocolGuid,\r
197 Device->DevicePath,\r
198 &gEfiBlockIoProtocolGuid,\r
199 &Device->BlockIo,\r
200 &gEfiDiskInfoProtocolGuid,\r
201 &Device->DiskInfo,\r
202 NULL\r
203 );\r
204\r
205 if(EFI_ERROR(Status)) {\r
206 goto Exit;\r
207 }\r
208 gBS->OpenProtocol (\r
209 Private->ControllerHandle,\r
210 &gEfiPciIoProtocolGuid,\r
211 (VOID **) &Private->PciIo,\r
212 Private->DriverBindingHandle,\r
213 Device->DeviceHandle,\r
214 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
215 );\r
216\r
7b8883c6
FT
217 //\r
218 // Dump NvmExpress Identify Namespace Data\r
219 //\r
220 DEBUG ((EFI_D_INFO, " == NVME IDENTIFY NAMESPACE [%d] DATA ==\n", NamespaceId));\r
221 DEBUG ((EFI_D_INFO, " NSZE : 0x%x\n", NamespaceData->Nsze));\r
222 DEBUG ((EFI_D_INFO, " NCAP : 0x%x\n", NamespaceData->Ncap));\r
223 DEBUG ((EFI_D_INFO, " NUSE : 0x%x\n", NamespaceData->Nuse));\r
224 DEBUG ((EFI_D_INFO, " LBAF0.LBADS : 0x%x\n", (NamespaceData->LbaFormat[0].Lbads)));\r
225\r
eb290d02
FT
226 //\r
227 // Build controller name for Component Name (2) protocol.\r
228 //\r
229 UnicodeSPrintAsciiFormat (Device->ModelName, sizeof (Device->ModelName), "%a-%a-%x", Private->ControllerData->Sn, Private->ControllerData->Mn, NamespaceData->Eui64);\r
230\r
231 AddUnicodeString2 (\r
232 "eng",\r
233 gNvmExpressComponentName.SupportedLanguages,\r
234 &Device->ControllerNameTable,\r
235 Device->ModelName,\r
236 TRUE\r
237 );\r
238\r
239 AddUnicodeString2 (\r
240 "en",\r
241 gNvmExpressComponentName2.SupportedLanguages,\r
242 &Device->ControllerNameTable,\r
243 Device->ModelName,\r
244 FALSE\r
245 );\r
246 }\r
247\r
248Exit:\r
249 if(NamespaceData != NULL) {\r
250 FreePool (NamespaceData);\r
251 }\r
252\r
253 if(EFI_ERROR(Status) && (Device != NULL) && (Device->DevicePath != NULL)) {\r
254 FreePool (Device->DevicePath);\r
255 }\r
256 if(EFI_ERROR(Status) && (Device != NULL)) {\r
257 FreePool (Device);\r
258 }\r
259 return Status;\r
260}\r
261\r
262/**\r
263 Discover all Nvm Express device namespaces, and create child handles for them with BlockIo\r
264 and DiskInfo protocol instances.\r
265\r
266 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
267\r
268 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
269 @return Others Some error occurs when enumerating the namespaces.\r
270\r
271**/\r
272EFI_STATUS\r
273DiscoverAllNamespaces (\r
274 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
275 )\r
276{\r
277 EFI_STATUS Status;\r
278 UINT32 NamespaceId;\r
279 UINT64 NamespaceUuid;\r
280 NVM_EXPRESS_PASS_THRU_PROTOCOL *Passthru;\r
281\r
282 NamespaceId = 0xFFFFFFFF;\r
283 NamespaceUuid = 0;\r
284 Passthru = &Private->Passthru;\r
285\r
286 while (TRUE) {\r
287 Status = Passthru->GetNextNamespace (\r
288 Passthru,\r
289 (UINT32 *)&NamespaceId,\r
290 (UINT64 *)&NamespaceUuid\r
291 );\r
292\r
293 if (EFI_ERROR (Status)) {\r
294 break;\r
295 }\r
296\r
297 Status = EnumerateNvmeDevNamespace (\r
298 Private,\r
299 NamespaceId,\r
300 NamespaceUuid\r
301 );\r
302\r
303 if (EFI_ERROR(Status)) {\r
304 continue;\r
305 }\r
306 }\r
307\r
308 return EFI_SUCCESS;\r
309}\r
310\r
311/**\r
312 Unregisters a Nvm Express device namespace.\r
313\r
314 This function removes the protocols installed on the controller handle and\r
315 frees the resources allocated for the namespace.\r
316\r
317 @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.\r
318 @param Controller The controller handle of the namespace.\r
319 @param Handle The child handle.\r
320\r
321 @retval EFI_SUCCESS The namespace is successfully unregistered.\r
322 @return Others Some error occurs when unregistering the namespace.\r
323\r
324**/\r
325EFI_STATUS\r
326UnregisterNvmeNamespace (\r
327 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
328 IN EFI_HANDLE Controller,\r
329 IN EFI_HANDLE Handle\r
330 )\r
331{\r
332 EFI_STATUS Status;\r
333 EFI_PCI_IO_PROTOCOL *PciIo;\r
334 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
335 NVME_DEVICE_PRIVATE_DATA *Device;\r
336\r
337 BlockIo = NULL;\r
338\r
339 Status = gBS->OpenProtocol (\r
340 Handle,\r
341 &gEfiBlockIoProtocolGuid,\r
342 (VOID **) &BlockIo,\r
343 This->DriverBindingHandle,\r
344 Controller,\r
345 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
346 );\r
347 if (EFI_ERROR (Status)) {\r
348 return Status;\r
349 }\r
350\r
351 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo);\r
352\r
353 //\r
354 // Close the child handle\r
355 //\r
356 gBS->CloseProtocol (\r
357 Controller,\r
358 &gEfiPciIoProtocolGuid,\r
359 This->DriverBindingHandle,\r
360 Handle\r
361 );\r
362\r
363 //\r
364 // The Nvm Express driver installs the BlockIo and DiskInfo in the DriverBindingStart().\r
365 // Here should uninstall both of them.\r
366 //\r
367 Status = gBS->UninstallMultipleProtocolInterfaces (\r
368 Handle,\r
369 &gEfiDevicePathProtocolGuid,\r
370 Device->DevicePath,\r
371 &gEfiBlockIoProtocolGuid,\r
372 &Device->BlockIo,\r
373 &gEfiDiskInfoProtocolGuid,\r
374 &Device->DiskInfo,\r
375 NULL\r
376 );\r
377\r
378 if (EFI_ERROR (Status)) {\r
379 gBS->OpenProtocol (\r
380 Controller,\r
381 &gEfiPciIoProtocolGuid,\r
382 (VOID **) &PciIo,\r
383 This->DriverBindingHandle,\r
384 Handle,\r
385 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
386 );\r
387 return Status;\r
388 }\r
389\r
390 if(Device->DevicePath != NULL) {\r
391 FreePool (Device->DevicePath);\r
392 }\r
393\r
394 if (Device->ControllerNameTable != NULL) {\r
395 FreeUnicodeStringTable (Device->ControllerNameTable);\r
396 }\r
397\r
398 return EFI_SUCCESS;\r
399}\r
400\r
401/**\r
402 Tests to see if this driver supports a given controller. If a child device is provided,\r
403 it further tests to see if this driver supports creating a handle for the specified child device.\r
404\r
405 This function checks to see if the driver specified by This supports the device specified by\r
406 ControllerHandle. Drivers will typically use the device path attached to\r
407 ControllerHandle and/or the services from the bus I/O abstraction attached to\r
408 ControllerHandle to determine if the driver supports ControllerHandle. This function\r
409 may be called many times during platform initialization. In order to reduce boot times, the tests\r
410 performed by this function must be very small, and take as little time as possible to execute. This\r
411 function must not change the state of any hardware devices, and this function must be aware that the\r
412 device specified by ControllerHandle may already be managed by the same driver or a\r
413 different driver. This function must match its calls to AllocatePages() with FreePages(),\r
414 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
415 Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
416 already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
417 to guarantee the state of ControllerHandle is not modified by this function.\r
418\r
419 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
420 @param[in] ControllerHandle The handle of the controller to test. This handle\r
421 must support a protocol interface that supplies\r
422 an I/O abstraction to the driver.\r
423 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
424 parameter is ignored by device drivers, and is optional for bus\r
425 drivers. For bus drivers, if this parameter is not NULL, then\r
426 the bus driver must determine if the bus controller specified\r
427 by ControllerHandle and the child controller specified\r
428 by RemainingDevicePath are both supported by this\r
429 bus driver.\r
430\r
431 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
432 RemainingDevicePath is supported by the driver specified by This.\r
433 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
434 RemainingDevicePath is already being managed by the driver\r
435 specified by This.\r
436 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
437 RemainingDevicePath is already being managed by a different\r
438 driver or an application that requires exclusive access.\r
439 Currently not implemented.\r
440 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
441 RemainingDevicePath is not supported by the driver specified by This.\r
442**/\r
443EFI_STATUS\r
444EFIAPI\r
445NvmExpressDriverBindingSupported (\r
446 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
447 IN EFI_HANDLE Controller,\r
448 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
449 )\r
450{\r
451 EFI_STATUS Status;\r
452 EFI_DEV_PATH_PTR DevicePathNode;\r
453 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
454 EFI_PCI_IO_PROTOCOL *PciIo;\r
455 UINT8 ClassCode[3];\r
456\r
457 //\r
458 // Check whether device path is valid\r
459 //\r
460 if (RemainingDevicePath != NULL) {\r
461 //\r
462 // Check if RemainingDevicePath is the End of Device Path Node,\r
463 // if yes, go on checking other conditions\r
464 //\r
465 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
466 //\r
467 // If RemainingDevicePath isn't the End of Device Path Node,\r
468 // check its validation\r
469 //\r
470 DevicePathNode.DevPath = RemainingDevicePath;\r
471\r
472 if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||\r
473 (DevicePathNode.DevPath->SubType != MSG_NVME_NAMESPACE_DP) ||\r
474 DevicePathNodeLength(DevicePathNode.DevPath) != sizeof(NVME_NAMESPACE_DEVICE_PATH)) {\r
475 return EFI_UNSUPPORTED;\r
476 }\r
477 }\r
478 }\r
479\r
480 //\r
481 // Open the EFI Device Path protocol needed to perform the supported test\r
482 //\r
483 Status = gBS->OpenProtocol (\r
484 Controller,\r
485 &gEfiDevicePathProtocolGuid,\r
486 (VOID **) &ParentDevicePath,\r
487 This->DriverBindingHandle,\r
488 Controller,\r
489 EFI_OPEN_PROTOCOL_BY_DRIVER\r
490 );\r
491 if (Status == EFI_ALREADY_STARTED) {\r
492 return EFI_SUCCESS;\r
493 }\r
494\r
495 if (EFI_ERROR (Status)) {\r
496 return Status;\r
497 }\r
498\r
499 //\r
500 // Close protocol, don't use device path protocol in the Support() function\r
501 //\r
502 gBS->CloseProtocol (\r
503 Controller,\r
504 &gEfiDevicePathProtocolGuid,\r
505 This->DriverBindingHandle,\r
506 Controller\r
507 );\r
508\r
509 //\r
510 // Attempt to Open PCI I/O Protocol\r
511 //\r
512 Status = gBS->OpenProtocol (\r
513 Controller,\r
514 &gEfiPciIoProtocolGuid,\r
515 (VOID **) &PciIo,\r
516 This->DriverBindingHandle,\r
517 Controller,\r
518 EFI_OPEN_PROTOCOL_BY_DRIVER\r
519 );\r
520 if (Status == EFI_ALREADY_STARTED) {\r
521 return EFI_SUCCESS;\r
522 }\r
523\r
524 if (EFI_ERROR (Status)) {\r
525 return Status;\r
526 }\r
527\r
528 //\r
529 // Now further check the PCI header: Base class (offset 0x0B) and Sub Class (offset 0x0A).\r
530 // This controller should be a Nvm Express controller.\r
531 //\r
532 Status = PciIo->Pci.Read (\r
533 PciIo,\r
534 EfiPciIoWidthUint8,\r
535 PCI_CLASSCODE_OFFSET,\r
536 sizeof (ClassCode),\r
537 ClassCode\r
538 );\r
539 if (EFI_ERROR (Status)) {\r
540 goto Done;\r
541 }\r
542\r
543 //\r
544 // Examine Nvm Express controller PCI Configuration table fields\r
545 //\r
546 if ((ClassCode[0] != PCI_IF_NVMHCI) || (ClassCode[1] != PCI_CLASS_MASS_STORAGE_NVM) || (ClassCode[2] != PCI_CLASS_MASS_STORAGE)) {\r
547 Status = EFI_UNSUPPORTED;\r
548 }\r
549\r
550Done:\r
551 gBS->CloseProtocol (\r
552 Controller,\r
553 &gEfiPciIoProtocolGuid,\r
554 This->DriverBindingHandle,\r
555 Controller\r
556 );\r
557\r
558 return Status;\r
559}\r
560\r
561\r
562/**\r
563 Starts a device controller or a bus controller.\r
564\r
565 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
566 As a result, much of the error checking on the parameters to Start() has been moved into this\r
567 common boot service. It is legal to call Start() from other locations,\r
568 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
569 1. ControllerHandle must be a valid EFI_HANDLE.\r
570 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
571 EFI_DEVICE_PATH_PROTOCOL.\r
572 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
573 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
574\r
575 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
576 @param[in] ControllerHandle The handle of the controller to start. This handle\r
577 must support a protocol interface that supplies\r
578 an I/O abstraction to the driver.\r
579 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
580 parameter is ignored by device drivers, and is optional for bus\r
581 drivers. For a bus driver, if this parameter is NULL, then handles\r
582 for all the children of Controller are created by this driver.\r
583 If this parameter is not NULL and the first Device Path Node is\r
584 not the End of Device Path Node, then only the handle for the\r
585 child device specified by the first Device Path Node of\r
586 RemainingDevicePath is created by this driver.\r
587 If the first Device Path Node of RemainingDevicePath is\r
588 the End of Device Path Node, no child handle is created by this\r
589 driver.\r
590\r
591 @retval EFI_SUCCESS The device was started.\r
592 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
593 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
594 @retval Others The driver failded to start the device.\r
595\r
596**/\r
597EFI_STATUS\r
598EFIAPI\r
599NvmExpressDriverBindingStart (\r
600 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
601 IN EFI_HANDLE Controller,\r
602 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
603 )\r
604{\r
605 EFI_STATUS Status;\r
606 EFI_PCI_IO_PROTOCOL *PciIo;\r
607 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
608 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
609 UINT32 NamespaceId;\r
610 UINT64 NamespaceUuid;\r
611 EFI_PHYSICAL_ADDRESS MappedAddr;\r
612 UINTN Bytes;\r
613\r
614 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: start\n"));\r
615\r
616 Private = NULL;\r
617 ParentDevicePath = NULL;\r
618\r
619 Status = gBS->OpenProtocol (\r
620 Controller,\r
621 &gEfiDevicePathProtocolGuid,\r
622 (VOID **) &ParentDevicePath,\r
623 This->DriverBindingHandle,\r
624 Controller,\r
625 EFI_OPEN_PROTOCOL_BY_DRIVER\r
626 );\r
627 if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
628 return Status;\r
629 }\r
630\r
631 Status = gBS->OpenProtocol (\r
632 Controller,\r
633 &gEfiPciIoProtocolGuid,\r
634 (VOID **) &PciIo,\r
635 This->DriverBindingHandle,\r
636 Controller,\r
637 EFI_OPEN_PROTOCOL_BY_DRIVER\r
638 );\r
639\r
640 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
641 return Status;\r
642 }\r
643\r
644 //\r
645 // Check EFI_ALREADY_STARTED to reuse the original NVME_CONTROLLER_PRIVATE_DATA.\r
646 //\r
647 if (Status != EFI_ALREADY_STARTED) {\r
648 Private = AllocateZeroPool (sizeof (NVME_CONTROLLER_PRIVATE_DATA));\r
649\r
650 if (Private == NULL) {\r
651 DEBUG ((EFI_D_ERROR, "NvmExpressDriverBindingStart: allocating pool for Nvme Private Data failed!\n"));\r
652 Status = EFI_OUT_OF_RESOURCES;\r
653 goto Exit2;\r
654 }\r
655\r
656 //\r
657 // 4 x 4kB aligned buffers will be carved out of this buffer.\r
658 // 1st 4kB boundary is the start of the admin submission queue.\r
659 // 2nd 4kB boundary is the start of the admin completion queue.\r
660 // 3rd 4kB boundary is the start of I/O submission queue #1.\r
661 // 4th 4kB boundary is the start of I/O completion queue #1.\r
662 //\r
663 // Allocate 4 pages of memory, then map it for bus master read and write.\r
664 //\r
665 Status = PciIo->AllocateBuffer (\r
666 PciIo,\r
667 AllocateAnyPages,\r
668 EfiBootServicesData,\r
7b8883c6 669 4,\r
eb290d02
FT
670 (VOID**)&Private->Buffer,\r
671 0\r
672 );\r
673 if (EFI_ERROR (Status)) {\r
674 goto Exit2;\r
675 }\r
676\r
677 Bytes = EFI_PAGES_TO_SIZE (4);\r
678 Status = PciIo->Map (\r
679 PciIo,\r
680 EfiPciIoOperationBusMasterCommonBuffer,\r
681 Private->Buffer,\r
682 &Bytes,\r
683 &MappedAddr,\r
684 &Private->Mapping\r
685 );\r
686\r
687 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (4))) {\r
688 goto Exit2;\r
689 }\r
690\r
691 Private->BufferPciAddr = (UINT8 *)(UINTN)MappedAddr;\r
692 ZeroMem (Private->Buffer, EFI_PAGES_TO_SIZE (4));\r
693\r
694 Private->Signature = NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE;\r
695 Private->ControllerHandle = Controller;\r
696 Private->ImageHandle = This->DriverBindingHandle;\r
697 Private->DriverBindingHandle = This->DriverBindingHandle;\r
698 Private->PciIo = PciIo;\r
699 Private->ParentDevicePath = ParentDevicePath;\r
700 Private->Passthru.Mode = &Private->PassThruMode;\r
701 Private->Passthru.PassThru = NvmExpressPassThru;\r
702 Private->Passthru.GetNextNamespace = NvmExpressGetNextNamespace;\r
703 Private->Passthru.BuildDevicePath = NvmExpressBuildDevicePath;\r
704 Private->Passthru.GetNamespace = NvmExpressGetNamespace;\r
705 Private->PassThruMode.Attributes = NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL;\r
706\r
707 Status = NvmeControllerInit (Private);\r
708\r
709 if (EFI_ERROR(Status)) {\r
710 goto Exit2;\r
711 }\r
712\r
713 Status = gBS->InstallMultipleProtocolInterfaces (\r
714 &Controller,\r
715 &gEfiCallerIdGuid,\r
716 Private,\r
717 NULL\r
718 );\r
719 if (EFI_ERROR (Status)) {\r
720 goto Exit2;\r
721 }\r
722 } else {\r
723 Status = gBS->OpenProtocol (\r
724 Controller,\r
725 &gEfiCallerIdGuid,\r
726 (VOID **) &Private,\r
727 This->DriverBindingHandle,\r
728 Controller,\r
729 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
730 );\r
731 if (EFI_ERROR (Status)) {\r
732 Private = NULL;\r
733 goto Exit1;\r
734 }\r
735 }\r
736\r
737 if (RemainingDevicePath == NULL) {\r
738 //\r
739 // Enumerate all NVME namespaces in the controller\r
740 //\r
741 Status = DiscoverAllNamespaces (\r
742 Private\r
743 );\r
744\r
745 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
746 //\r
747 // Enumerate the specified NVME namespace\r
748 //\r
749 Status = Private->Passthru.GetNamespace (\r
750 &Private->Passthru,\r
751 RemainingDevicePath,\r
752 &NamespaceId,\r
753 &NamespaceUuid\r
754 );\r
755\r
756 if (!EFI_ERROR (Status)) {\r
757 Status = EnumerateNvmeDevNamespace (\r
758 Private,\r
759 NamespaceId,\r
760 NamespaceUuid\r
761 );\r
762 }\r
763 }\r
764\r
765 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end successfully\n"));\r
766 return EFI_SUCCESS;\r
767\r
768Exit1:\r
769 gBS->UninstallMultipleProtocolInterfaces (\r
770 Controller,\r
771 &gEfiCallerIdGuid,\r
772 Private,\r
773 NULL\r
774 );\r
775Exit2:\r
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
931 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
932 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
933 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
934\r
935 //\r
936 // Get the list of all the handles in the handle database.\r
937 // If there is an error getting the list, then the unload\r
938 // operation fails.\r
939 //\r
940 Status = gBS->LocateHandleBuffer (\r
941 AllHandles,\r
942 NULL,\r
943 NULL,\r
944 &DeviceHandleCount,\r
945 &DeviceHandleBuffer\r
946 );\r
947\r
948 if (EFI_ERROR (Status)) {\r
949 return Status;\r
950 }\r
951\r
952 //\r
953 // Disconnect the driver specified by ImageHandle from all\r
954 // the devices in the handle database.\r
955 //\r
956 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
957 Status = gBS->DisconnectController (\r
958 DeviceHandleBuffer[Index],\r
959 ImageHandle,\r
960 NULL\r
961 );\r
962 }\r
963\r
964 //\r
965 // Uninstall all the protocols installed in the driver entry point\r
966 //\r
967 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
968 Status = gBS->HandleProtocol (\r
969 DeviceHandleBuffer[Index],\r
970 &gEfiDriverBindingProtocolGuid,\r
971 (VOID **) &DriverBinding\r
972 );\r
973\r
974 if (EFI_ERROR (Status)) {\r
975 continue;\r
976 }\r
977\r
978 if (DriverBinding->ImageHandle != ImageHandle) {\r
979 continue;\r
980 }\r
981\r
982 gBS->UninstallProtocolInterface (\r
983 ImageHandle,\r
984 &gEfiDriverBindingProtocolGuid,\r
985 DriverBinding\r
986 );\r
987\r
988 Status = gBS->HandleProtocol (\r
989 DeviceHandleBuffer[Index],\r
990 &gEfiComponentNameProtocolGuid,\r
991 (VOID **) &ComponentName\r
992 );\r
993 if (!EFI_ERROR (Status)) {\r
994 gBS->UninstallProtocolInterface (\r
995 ImageHandle,\r
996 &gEfiComponentNameProtocolGuid,\r
997 ComponentName\r
998 );\r
999 }\r
1000\r
1001 Status = gBS->HandleProtocol (\r
1002 DeviceHandleBuffer[Index],\r
1003 &gEfiComponentName2ProtocolGuid,\r
1004 (VOID **) &ComponentName2\r
1005 );\r
1006 if (!EFI_ERROR (Status)) {\r
1007 gBS->UninstallProtocolInterface (\r
1008 ImageHandle,\r
1009 &gEfiComponentName2ProtocolGuid,\r
1010 ComponentName2\r
1011 );\r
1012 }\r
1013 }\r
1014\r
1015 //\r
1016 // Free the buffer containing the list of handles from the handle database\r
1017 //\r
1018 if (DeviceHandleBuffer != NULL) {\r
1019 gBS->FreePool (DeviceHandleBuffer);\r
1020 }\r
1021 return EFI_SUCCESS;\r
1022}\r
1023\r
1024/**\r
1025 The entry point for Nvm Express driver, used to install Nvm Express driver on the ImageHandle.\r
1026\r
1027 @param ImageHandle The firmware allocated handle for this driver image.\r
1028 @param SystemTable Pointer to the EFI system table.\r
1029\r
1030 @retval EFI_SUCCESS Driver loaded.\r
1031 @retval other Driver not loaded.\r
1032\r
1033**/\r
1034EFI_STATUS\r
1035EFIAPI\r
1036NvmExpressDriverEntry (\r
1037 IN EFI_HANDLE ImageHandle,\r
1038 IN EFI_SYSTEM_TABLE *SystemTable\r
1039 )\r
1040{\r
1041 EFI_STATUS Status;\r
1042\r
1043 Status = EfiLibInstallDriverBindingComponentName2 (\r
1044 ImageHandle,\r
1045 SystemTable,\r
1046 &gNvmExpressDriverBinding,\r
1047 ImageHandle,\r
1048 &gNvmExpressComponentName,\r
1049 &gNvmExpressComponentName2\r
1050 );\r
1051 ASSERT_EFI_ERROR (Status);\r
1052\r
1053 //\r
1054 // Install EFI Driver Supported EFI Version Protocol required for\r
1055 // EFI drivers that are on PCI and other plug in cards.\r
1056 //\r
1057 gNvmExpressDriverSupportedEfiVersion.FirmwareVersion = 0x00020028;\r
1058 Status = gBS->InstallMultipleProtocolInterfaces (\r
1059 &ImageHandle,\r
1060 &gEfiDriverSupportedEfiVersionProtocolGuid,\r
1061 &gNvmExpressDriverSupportedEfiVersion,\r
1062 NULL\r
1063 );\r
1064 ASSERT_EFI_ERROR (Status);\r
1065 return Status;\r
1066}\r