2 The NvmExpressPei driver is used to manage non-volatile memory subsystem
3 which follows NVM Express specification at PEI phase.
5 Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution. The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include "NvmExpressPei.h"
20 EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIoPpiListTemplate
= {
21 EFI_PEI_PPI_DESCRIPTOR_PPI
,
22 &gEfiPeiVirtualBlockIoPpiGuid
,
26 EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIo2PpiListTemplate
= {
27 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
28 &gEfiPeiVirtualBlockIo2PpiGuid
,
32 EFI_PEI_PPI_DESCRIPTOR mNvmeStorageSecurityPpiListTemplate
= {
33 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
34 &gEdkiiPeiStorageSecurityCommandPpiGuid
,
38 EFI_PEI_NOTIFY_DESCRIPTOR mNvmeEndOfPeiNotifyListTemplate
= {
39 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
40 &gEfiEndOfPeiSignalPpiGuid
,
45 Check if the specified Nvm Express device namespace is active, and then get the Identify
48 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
49 @param[in] NamespaceId The specified namespace identifier.
51 @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.
52 @return Others Error occurs when enumerating the namespace.
56 EnumerateNvmeDevNamespace (
57 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
,
62 NVME_ADMIN_NAMESPACE_DATA
*NamespaceData
;
63 PEI_NVME_NAMESPACE_INFO
*NamespaceInfo
;
69 NamespaceData
= (NVME_ADMIN_NAMESPACE_DATA
*) AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA
));
70 if (NamespaceData
== NULL
) {
71 return EFI_OUT_OF_RESOURCES
;
77 Status
= NvmeIdentifyNamespace (
82 if (EFI_ERROR (Status
)) {
83 DEBUG ((DEBUG_ERROR
, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__
, Status
));
90 if (NamespaceData
->Ncap
== 0) {
91 DEBUG ((DEBUG_INFO
, "%a: Namespace ID %d is an inactive one.\n", __FUNCTION__
, NamespaceId
));
92 Status
= EFI_DEVICE_ERROR
;
96 DeviceIndex
= Private
->ActiveNamespaceNum
;
97 NamespaceInfo
= &Private
->NamespaceInfo
[DeviceIndex
];
98 NamespaceInfo
->NamespaceId
= NamespaceId
;
99 NamespaceInfo
->NamespaceUuid
= NamespaceData
->Eui64
;
100 NamespaceInfo
->Controller
= Private
;
101 Private
->ActiveNamespaceNum
++;
104 // Build BlockIo media structure
106 Flbas
= NamespaceData
->Flbas
;
107 LbaFmtIdx
= Flbas
& 0xF;
108 Lbads
= NamespaceData
->LbaFormat
[LbaFmtIdx
].Lbads
;
110 NamespaceInfo
->Media
.InterfaceType
= MSG_NVME_NAMESPACE_DP
;
111 NamespaceInfo
->Media
.RemovableMedia
= FALSE
;
112 NamespaceInfo
->Media
.MediaPresent
= TRUE
;
113 NamespaceInfo
->Media
.ReadOnly
= FALSE
;
114 NamespaceInfo
->Media
.BlockSize
= (UINT32
) 1 << Lbads
;
115 NamespaceInfo
->Media
.LastBlock
= (EFI_PEI_LBA
) NamespaceData
->Nsze
- 1;
118 "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",
121 NamespaceInfo
->Media
.BlockSize
,
122 NamespaceInfo
->Media
.LastBlock
126 if (NamespaceData
!= NULL
) {
127 FreePool (NamespaceData
);
134 Discover all Nvm Express device active namespaces.
136 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
138 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
139 @return EFI_NOT_FOUND No active namespaces can be found.
143 NvmeDiscoverNamespaces (
144 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
149 Private
->ActiveNamespaceNum
= 0;
150 Private
->NamespaceInfo
= AllocateZeroPool (Private
->ControllerData
->Nn
* sizeof (PEI_NVME_NAMESPACE_INFO
));
153 // According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify
154 // controller data defines the number of valid namespaces present for the
155 // controller. Namespaces shall be allocated in order (starting with 1) and
156 // packed sequentially.
158 for (NamespaceId
= 1; NamespaceId
<= Private
->ControllerData
->Nn
; NamespaceId
++) {
160 // For now, we do not care the return status. Since if a valid namespace is inactive,
161 // error status will be returned. But we continue to enumerate other valid namespaces.
163 EnumerateNvmeDevNamespace (Private
, NamespaceId
);
165 if (Private
->ActiveNamespaceNum
== 0) {
166 return EFI_NOT_FOUND
;
173 One notified function to cleanup the allocated resources at the end of PEI.
175 @param[in] PeiServices Pointer to PEI Services Table.
176 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification
177 event that caused this function to execute.
178 @param[in] Ppi Pointer to the PPI data associated with this function.
180 @retval EFI_SUCCESS The function completes successfully
186 IN EFI_PEI_SERVICES
**PeiServices
,
187 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
191 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
193 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor
);
194 NvmeFreeDmaResource (Private
);
200 Entry point of the PEIM.
202 @param[in] FileHandle Handle of the file being invoked.
203 @param[in] PeiServices Describes the list of possible PEI Services.
205 @retval EFI_SUCCESS PPI successfully installed.
210 NvmExpressPeimEntry (
211 IN EFI_PEI_FILE_HANDLE FileHandle
,
212 IN CONST EFI_PEI_SERVICES
**PeiServices
216 EFI_BOOT_MODE BootMode
;
217 EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI
*NvmeHcPpi
;
220 UINTN DevicePathLength
;
221 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
222 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
223 EFI_PHYSICAL_ADDRESS DeviceAddress
;
225 DEBUG ((DEBUG_INFO
, "%a: Enters.\n", __FUNCTION__
));
228 // Get the current boot mode.
230 Status
= PeiServicesGetBootMode (&BootMode
);
231 if (EFI_ERROR (Status
)) {
232 DEBUG ((DEBUG_ERROR
, "%a: Fail to get the current boot mode.\n", __FUNCTION__
));
237 // Locate the NVME host controller PPI
239 Status
= PeiServicesLocatePpi (
240 &gEdkiiPeiNvmExpressHostControllerPpiGuid
,
245 if (EFI_ERROR (Status
)) {
246 DEBUG ((DEBUG_ERROR
, "%a: Fail to locate NvmeHostControllerPpi.\n", __FUNCTION__
));
247 return EFI_UNSUPPORTED
;
253 Status
= NvmeHcPpi
->GetNvmeHcMmioBar (
259 // When status is error, meant no controller is found
261 if (EFI_ERROR (Status
)) {
265 Status
= NvmeHcPpi
->GetNvmeHcDevicePath (
271 if (EFI_ERROR (Status
)) {
273 DEBUG_ERROR
, "%a: Fail to allocate get the device path for Controller %d.\n",
274 __FUNCTION__
, Controller
280 // Check validity of the device path of the NVM Express controller.
282 Status
= NvmeIsHcDevicePathValid (DevicePath
, DevicePathLength
);
283 if (EFI_ERROR (Status
)) {
285 DEBUG_ERROR
, "%a: The device path is invalid for Controller %d.\n",
286 __FUNCTION__
, Controller
293 // For S3 resume performance consideration, not all NVM Express controllers
294 // will be initialized. The driver consumes the content within
295 // S3StorageDeviceInitList LockBox to see if a controller will be skipped
298 if ((BootMode
== BOOT_ON_S3_RESUME
) &&
299 (NvmeS3SkipThisController (DevicePath
, DevicePathLength
))) {
301 DEBUG_ERROR
, "%a: Controller %d is skipped during S3.\n",
302 __FUNCTION__
, Controller
309 // Memory allocation for controller private data
311 Private
= AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA
));
312 if (Private
== NULL
) {
314 DEBUG_ERROR
, "%a: Fail to allocate private data for Controller %d.\n",
315 __FUNCTION__
, Controller
317 return EFI_OUT_OF_RESOURCES
;
321 // Memory allocation for transfer-related data
323 Status
= IoMmuAllocateBuffer (
327 &Private
->BufferMapping
329 if (EFI_ERROR (Status
)) {
331 DEBUG_ERROR
, "%a: Fail to allocate DMA buffers for Controller %d.\n",
332 __FUNCTION__
, Controller
336 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Private
->Buffer
));
337 DEBUG ((DEBUG_INFO
, "%a: DMA buffer base at 0x%x\n", __FUNCTION__
, Private
->Buffer
));
340 // Initialize controller private data
342 Private
->Signature
= NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE
;
343 Private
->MmioBase
= MmioBase
;
344 Private
->DevicePathLength
= DevicePathLength
;
345 Private
->DevicePath
= DevicePath
;
348 // Initialize the NVME controller
350 Status
= NvmeControllerInit (Private
);
351 if (EFI_ERROR (Status
)) {
354 "%a: Controller initialization fail for Controller %d with Status - %r.\n",
355 __FUNCTION__
, Controller
, Status
357 NvmeFreeDmaResource (Private
);
363 // Enumerate the NVME namespaces on the controller
365 Status
= NvmeDiscoverNamespaces (Private
);
366 if (EFI_ERROR (Status
)) {
368 // No active namespace was found on the controller
372 "%a: Namespaces discovery fail for Controller %d with Status - %r.\n",
373 __FUNCTION__
, Controller
, Status
375 NvmeFreeDmaResource (Private
);
380 Private
->BlkIoPpi
.GetNumberOfBlockDevices
= NvmeBlockIoPeimGetDeviceNo
;
381 Private
->BlkIoPpi
.GetBlockDeviceMediaInfo
= NvmeBlockIoPeimGetMediaInfo
;
382 Private
->BlkIoPpi
.ReadBlocks
= NvmeBlockIoPeimReadBlocks
;
384 &Private
->BlkIoPpiList
,
385 &mNvmeBlkIoPpiListTemplate
,
386 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
388 Private
->BlkIoPpiList
.Ppi
= &Private
->BlkIoPpi
;
390 Private
->BlkIo2Ppi
.Revision
= EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION
;
391 Private
->BlkIo2Ppi
.GetNumberOfBlockDevices
= NvmeBlockIoPeimGetDeviceNo2
;
392 Private
->BlkIo2Ppi
.GetBlockDeviceMediaInfo
= NvmeBlockIoPeimGetMediaInfo2
;
393 Private
->BlkIo2Ppi
.ReadBlocks
= NvmeBlockIoPeimReadBlocks2
;
395 &Private
->BlkIo2PpiList
,
396 &mNvmeBlkIo2PpiListTemplate
,
397 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
399 Private
->BlkIo2PpiList
.Ppi
= &Private
->BlkIo2Ppi
;
400 PeiServicesInstallPpi (&Private
->BlkIoPpiList
);
403 // Check if the NVME controller supports the Security Receive/Send commands
405 if ((Private
->ControllerData
->Oacs
& SECURITY_SEND_RECEIVE_SUPPORTED
) != 0) {
408 "%a: Security Security Command PPI will be produced for Controller %d.\n",
409 __FUNCTION__
, Controller
411 Private
->StorageSecurityPpi
.Revision
= EDKII_STORAGE_SECURITY_PPI_REVISION
;
412 Private
->StorageSecurityPpi
.GetNumberofDevices
= NvmeStorageSecurityGetDeviceNo
;
413 Private
->StorageSecurityPpi
.GetDevicePath
= NvmeStorageSecurityGetDevicePath
;
414 Private
->StorageSecurityPpi
.ReceiveData
= NvmeStorageSecurityReceiveData
;
415 Private
->StorageSecurityPpi
.SendData
= NvmeStorageSecuritySendData
;
417 &Private
->StorageSecurityPpiList
,
418 &mNvmeStorageSecurityPpiListTemplate
,
419 sizeof (EFI_PEI_PPI_DESCRIPTOR
)
421 Private
->StorageSecurityPpiList
.Ppi
= &Private
->StorageSecurityPpi
;
422 PeiServicesInstallPpi (&Private
->StorageSecurityPpiList
);
426 &Private
->EndOfPeiNotifyList
,
427 &mNvmeEndOfPeiNotifyListTemplate
,
428 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR
)
430 PeiServicesNotifyPpi (&Private
->EndOfPeiNotifyList
);
433 DEBUG_INFO
, "%a: Controller %d has been successfully initialized.\n",
434 __FUNCTION__
, Controller