]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressPei/NvmExpressPei.c
MdeModulePkg/NvmExpressPei: Add logic to produce SSC PPI
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressPei / NvmExpressPei.c
CommitLineData
b8b69433
HW
1/** @file\r
2 The NvmExpressPei driver is used to manage non-volatile memory subsystem\r
3 which follows NVM Express specification at PEI phase.\r
4\r
4104423a 5 Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>\r
b8b69433
HW
6\r
7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions\r
9 of the BSD License which accompanies this distribution. The\r
10 full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16**/\r
17\r
18#include "NvmExpressPei.h"\r
19\r
20EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIoPpiListTemplate = {\r
21 EFI_PEI_PPI_DESCRIPTOR_PPI,\r
22 &gEfiPeiVirtualBlockIoPpiGuid,\r
23 NULL\r
24};\r
25\r
26EFI_PEI_PPI_DESCRIPTOR mNvmeBlkIo2PpiListTemplate = {\r
2e15b750 27 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
b8b69433
HW
28 &gEfiPeiVirtualBlockIo2PpiGuid,\r
29 NULL\r
30};\r
31\r
2e15b750
HW
32EFI_PEI_PPI_DESCRIPTOR mNvmeStorageSecurityPpiListTemplate = {\r
33 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
34 &gEdkiiPeiStorageSecurityCommandPpiGuid,\r
35 NULL\r
36};\r
37\r
b8b69433
HW
38EFI_PEI_NOTIFY_DESCRIPTOR mNvmeEndOfPeiNotifyListTemplate = {\r
39 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
40 &gEfiEndOfPeiSignalPpiGuid,\r
41 NvmePeimEndOfPei\r
42};\r
43\r
44/**\r
45 Check if the specified Nvm Express device namespace is active, and then get the Identify\r
46 Namespace data.\r
47\r
48 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
49 @param[in] NamespaceId The specified namespace identifier.\r
50\r
51 @retval EFI_SUCCESS The specified namespace in the device is successfully enumerated.\r
52 @return Others Error occurs when enumerating the namespace.\r
53\r
54**/\r
55EFI_STATUS\r
56EnumerateNvmeDevNamespace (\r
57 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private,\r
58 IN UINT32 NamespaceId\r
59 )\r
60{\r
61 EFI_STATUS Status;\r
62 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
63 PEI_NVME_NAMESPACE_INFO *NamespaceInfo;\r
64 UINT32 DeviceIndex;\r
65 UINT32 Lbads;\r
66 UINT32 Flbas;\r
67 UINT32 LbaFmtIdx;\r
68\r
69 NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *) AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
70 if (NamespaceData == NULL) {\r
71 return EFI_OUT_OF_RESOURCES;\r
72 }\r
73\r
74 //\r
75 // Identify Namespace\r
76 //\r
77 Status = NvmeIdentifyNamespace (\r
78 Private,\r
79 NamespaceId,\r
80 NamespaceData\r
81 );\r
82 if (EFI_ERROR (Status)) {\r
83 DEBUG ((DEBUG_ERROR, "%a: NvmeIdentifyNamespace fail, Status - %r\n", __FUNCTION__, Status));\r
84 goto Exit;\r
85 }\r
86\r
87 //\r
88 // Validate Namespace\r
89 //\r
90 if (NamespaceData->Ncap == 0) {\r
91 DEBUG ((DEBUG_INFO, "%a: Namespace ID %d is an inactive one.\n", __FUNCTION__, NamespaceId));\r
92 Status = EFI_DEVICE_ERROR;\r
93 goto Exit;\r
94 }\r
95\r
96 DeviceIndex = Private->ActiveNamespaceNum;\r
97 NamespaceInfo = &Private->NamespaceInfo[DeviceIndex];\r
98 NamespaceInfo->NamespaceId = NamespaceId;\r
99 NamespaceInfo->NamespaceUuid = NamespaceData->Eui64;\r
100 NamespaceInfo->Controller = Private;\r
101 Private->ActiveNamespaceNum++;\r
102\r
103 //\r
104 // Build BlockIo media structure\r
105 //\r
106 Flbas = NamespaceData->Flbas;\r
107 LbaFmtIdx = Flbas & 0xF;\r
108 Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;\r
109\r
110 NamespaceInfo->Media.InterfaceType = MSG_NVME_NAMESPACE_DP;\r
111 NamespaceInfo->Media.RemovableMedia = FALSE;\r
112 NamespaceInfo->Media.MediaPresent = TRUE;\r
113 NamespaceInfo->Media.ReadOnly = FALSE;\r
114 NamespaceInfo->Media.BlockSize = (UINT32) 1 << Lbads;\r
115 NamespaceInfo->Media.LastBlock = (EFI_PEI_LBA) NamespaceData->Nsze - 1;\r
116 DEBUG ((\r
117 DEBUG_INFO,\r
118 "%a: Namespace ID %d - BlockSize = 0x%x, LastBlock = 0x%lx\n",\r
119 __FUNCTION__,\r
120 NamespaceId,\r
121 NamespaceInfo->Media.BlockSize,\r
122 NamespaceInfo->Media.LastBlock\r
123 ));\r
124\r
125Exit:\r
126 if (NamespaceData != NULL) {\r
127 FreePool (NamespaceData);\r
128 }\r
129\r
130 return Status;\r
131}\r
132\r
133/**\r
134 Discover all Nvm Express device active namespaces.\r
135\r
136 @param[in,out] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.\r
137\r
138 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
139 @return EFI_NOT_FOUND No active namespaces can be found.\r
140\r
141**/\r
142EFI_STATUS\r
143NvmeDiscoverNamespaces (\r
144 IN OUT PEI_NVME_CONTROLLER_PRIVATE_DATA *Private\r
145 )\r
146{\r
147 UINT32 NamespaceId;\r
148\r
149 Private->ActiveNamespaceNum = 0;\r
150 Private->NamespaceInfo = AllocateZeroPool (Private->ControllerData->Nn * sizeof (PEI_NVME_NAMESPACE_INFO));\r
151\r
152 //\r
153 // According to Nvm Express 1.1 spec Figure 82, the field 'Nn' of the identify\r
154 // controller data defines the number of valid namespaces present for the\r
155 // controller. Namespaces shall be allocated in order (starting with 1) and\r
156 // packed sequentially.\r
157 //\r
158 for (NamespaceId = 1; NamespaceId <= Private->ControllerData->Nn; NamespaceId++) {\r
159 //\r
160 // For now, we do not care the return status. Since if a valid namespace is inactive,\r
161 // error status will be returned. But we continue to enumerate other valid namespaces.\r
162 //\r
163 EnumerateNvmeDevNamespace (Private, NamespaceId);\r
164 }\r
165 if (Private->ActiveNamespaceNum == 0) {\r
166 return EFI_NOT_FOUND;\r
167 }\r
168\r
169 return EFI_SUCCESS;\r
170}\r
171\r
172/**\r
173 One notified function to cleanup the allocated resources at the end of PEI.\r
174\r
175 @param[in] PeiServices Pointer to PEI Services Table.\r
176 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification\r
177 event that caused this function to execute.\r
178 @param[in] Ppi Pointer to the PPI data associated with this function.\r
179\r
180 @retval EFI_SUCCESS The function completes successfully\r
181\r
182**/\r
183EFI_STATUS\r
184EFIAPI\r
185NvmePeimEndOfPei (\r
186 IN EFI_PEI_SERVICES **PeiServices,\r
187 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
188 IN VOID *Ppi\r
189 )\r
190{\r
191 PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;\r
192\r
193 Private = GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);\r
2e15b750 194 NvmeFreeDmaResource (Private);\r
b8b69433
HW
195\r
196 return EFI_SUCCESS;\r
197}\r
198\r
199/**\r
200 Entry point of the PEIM.\r
201\r
202 @param[in] FileHandle Handle of the file being invoked.\r
203 @param[in] PeiServices Describes the list of possible PEI Services.\r
204\r
205 @retval EFI_SUCCESS PPI successfully installed.\r
206\r
207**/\r
208EFI_STATUS\r
209EFIAPI\r
210NvmExpressPeimEntry (\r
211 IN EFI_PEI_FILE_HANDLE FileHandle,\r
212 IN CONST EFI_PEI_SERVICES **PeiServices\r
213 )\r
214{\r
215 EFI_STATUS Status;\r
216 EDKII_NVM_EXPRESS_HOST_CONTROLLER_PPI *NvmeHcPpi;\r
217 UINT8 Controller;\r
218 UINTN MmioBase;\r
2e15b750
HW
219 UINTN DevicePathLength;\r
220 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
b8b69433
HW
221 PEI_NVME_CONTROLLER_PRIVATE_DATA *Private;\r
222 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
223\r
2e15b750
HW
224 DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));\r
225\r
b8b69433
HW
226 //\r
227 // Locate the NVME host controller PPI\r
228 //\r
229 Status = PeiServicesLocatePpi (\r
230 &gEdkiiPeiNvmExpressHostControllerPpiGuid,\r
231 0,\r
232 NULL,\r
233 (VOID **) &NvmeHcPpi\r
234 );\r
235 if (EFI_ERROR (Status)) {\r
236 DEBUG ((DEBUG_ERROR, "%a: Fail to locate NvmeHostControllerPpi.\n", __FUNCTION__));\r
237 return EFI_UNSUPPORTED;\r
238 }\r
239\r
b8b69433
HW
240 Controller = 0;\r
241 MmioBase = 0;\r
242 while (TRUE) {\r
243 Status = NvmeHcPpi->GetNvmeHcMmioBar (\r
244 NvmeHcPpi,\r
245 Controller,\r
246 &MmioBase\r
247 );\r
248 //\r
249 // When status is error, meant no controller is found\r
250 //\r
251 if (EFI_ERROR (Status)) {\r
252 break;\r
253 }\r
254\r
2e15b750
HW
255 Status = NvmeHcPpi->GetNvmeHcDevicePath (\r
256 NvmeHcPpi,\r
257 Controller,\r
258 &DevicePathLength,\r
259 &DevicePath\r
260 );\r
261 if (EFI_ERROR (Status)) {\r
262 DEBUG ((\r
263 DEBUG_ERROR, "%a: Fail to allocate get the device path for Controller %d.\n",\r
264 __FUNCTION__, Controller\r
265 ));\r
266 return Status;\r
267 }\r
268\r
269 //\r
270 // Check validity of the device path of the NVM Express controller.\r
271 //\r
272 Status = NvmeIsHcDevicePathValid (DevicePath, DevicePathLength);\r
273 if (EFI_ERROR (Status)) {\r
274 DEBUG ((\r
275 DEBUG_ERROR, "%a: The device path is invalid for Controller %d.\n",\r
276 __FUNCTION__, Controller\r
277 ));\r
278 Controller++;\r
279 continue;\r
280 }\r
281\r
b8b69433
HW
282 //\r
283 // Memory allocation for controller private data\r
284 //\r
285 Private = AllocateZeroPool (sizeof (PEI_NVME_CONTROLLER_PRIVATE_DATA));\r
286 if (Private == NULL) {\r
287 DEBUG ((\r
2e15b750
HW
288 DEBUG_ERROR, "%a: Fail to allocate private data for Controller %d.\n",\r
289 __FUNCTION__, Controller\r
b8b69433
HW
290 ));\r
291 return EFI_OUT_OF_RESOURCES;\r
292 }\r
293\r
294 //\r
295 // Memory allocation for transfer-related data\r
296 //\r
297 Status = IoMmuAllocateBuffer (\r
298 NVME_MEM_MAX_PAGES,\r
299 &Private->Buffer,\r
300 &DeviceAddress,\r
301 &Private->BufferMapping\r
302 );\r
303 if (EFI_ERROR (Status)) {\r
304 DEBUG ((\r
2e15b750
HW
305 DEBUG_ERROR, "%a: Fail to allocate DMA buffers for Controller %d.\n",\r
306 __FUNCTION__, Controller\r
b8b69433 307 ));\r
b8b69433
HW
308 return Status;\r
309 }\r
310 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Private->Buffer));\r
311 DEBUG ((DEBUG_INFO, "%a: DMA buffer base at 0x%x\n", __FUNCTION__, Private->Buffer));\r
312\r
313 //\r
314 // Initialize controller private data\r
315 //\r
2e15b750
HW
316 Private->Signature = NVME_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;\r
317 Private->MmioBase = MmioBase;\r
318 Private->DevicePathLength = DevicePathLength;\r
319 Private->DevicePath = DevicePath;\r
b8b69433
HW
320\r
321 //\r
322 // Initialize the NVME controller\r
323 //\r
324 Status = NvmeControllerInit (Private);\r
325 if (EFI_ERROR (Status)) {\r
326 DEBUG ((\r
327 DEBUG_ERROR,\r
328 "%a: Controller initialization fail for Controller %d with Status - %r.\n",\r
2e15b750 329 __FUNCTION__, Controller, Status\r
b8b69433 330 ));\r
2e15b750 331 NvmeFreeDmaResource (Private);\r
b8b69433
HW
332 Controller++;\r
333 continue;\r
334 }\r
335\r
336 //\r
337 // Enumerate the NVME namespaces on the controller\r
338 //\r
339 Status = NvmeDiscoverNamespaces (Private);\r
340 if (EFI_ERROR (Status)) {\r
341 //\r
342 // No active namespace was found on the controller\r
343 //\r
344 DEBUG ((\r
345 DEBUG_ERROR,\r
346 "%a: Namespaces discovery fail for Controller %d with Status - %r.\n",\r
2e15b750 347 __FUNCTION__, Controller, Status\r
b8b69433 348 ));\r
2e15b750 349 NvmeFreeDmaResource (Private);\r
b8b69433
HW
350 Controller++;\r
351 continue;\r
352 }\r
353\r
2e15b750
HW
354 Private->BlkIoPpi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo;\r
355 Private->BlkIoPpi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo;\r
356 Private->BlkIoPpi.ReadBlocks = NvmeBlockIoPeimReadBlocks;\r
357 CopyMem (\r
358 &Private->BlkIoPpiList,\r
359 &mNvmeBlkIoPpiListTemplate,\r
360 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
361 );\r
362 Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;\r
363\r
364 Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;\r
365 Private->BlkIo2Ppi.GetNumberOfBlockDevices = NvmeBlockIoPeimGetDeviceNo2;\r
366 Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = NvmeBlockIoPeimGetMediaInfo2;\r
367 Private->BlkIo2Ppi.ReadBlocks = NvmeBlockIoPeimReadBlocks2;\r
368 CopyMem (\r
369 &Private->BlkIo2PpiList,\r
370 &mNvmeBlkIo2PpiListTemplate,\r
371 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
372 );\r
373 Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;\r
b8b69433 374 PeiServicesInstallPpi (&Private->BlkIoPpiList);\r
2e15b750
HW
375\r
376 //\r
377 // Check if the NVME controller supports the Security Receive/Send commands\r
378 //\r
379 if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {\r
380 DEBUG ((\r
381 DEBUG_INFO,\r
382 "%a: Security Security Command PPI will be produced for Controller %d.\n",\r
383 __FUNCTION__, Controller\r
384 ));\r
385 Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION;\r
386 Private->StorageSecurityPpi.GetNumberofDevices = NvmeStorageSecurityGetDeviceNo;\r
387 Private->StorageSecurityPpi.GetDevicePath = NvmeStorageSecurityGetDevicePath;\r
388 Private->StorageSecurityPpi.ReceiveData = NvmeStorageSecurityReceiveData;\r
389 Private->StorageSecurityPpi.SendData = NvmeStorageSecuritySendData;\r
390 CopyMem (\r
391 &Private->StorageSecurityPpiList,\r
392 &mNvmeStorageSecurityPpiListTemplate,\r
393 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
394 );\r
395 Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi;\r
396 PeiServicesInstallPpi (&Private->StorageSecurityPpiList);\r
397 }\r
398\r
399 CopyMem (\r
400 &Private->EndOfPeiNotifyList,\r
401 &mNvmeEndOfPeiNotifyListTemplate,\r
402 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)\r
403 );\r
404 PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);\r
405\r
b8b69433 406 DEBUG ((\r
2e15b750
HW
407 DEBUG_INFO, "%a: Controller %d has been successfully initialized.\n",\r
408 __FUNCTION__, Controller\r
b8b69433
HW
409 ));\r
410 Controller++;\r
411 }\r
412\r
413 return EFI_SUCCESS;\r
414}\r