]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
MdeModulePkg NvmExpressDxe: Add BlockIo2 support
[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
d2a2678b 5 Copyright (c) 2013 - 2016, 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
da7c7274
FT
77 UINT8 Sn[21];\r
78 UINT8 Mn[41];\r
eb290d02
FT
79\r
80 NewDevicePathNode = NULL;\r
81 DevicePath = NULL;\r
82 Device = NULL;\r
83\r
84 //\r
85 // Allocate a buffer for Identify Namespace data\r
86 //\r
87 NamespaceData = AllocateZeroPool(sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
88 if(NamespaceData == NULL) {\r
89 return EFI_OUT_OF_RESOURCES;\r
90 }\r
91\r
92 ParentDevicePath = Private->ParentDevicePath;\r
93 //\r
94 // Identify Namespace\r
95 //\r
96 Status = NvmeIdentifyNamespace (\r
97 Private,\r
98 NamespaceId,\r
99 (VOID *)NamespaceData\r
100 );\r
101 if (EFI_ERROR(Status)) {\r
102 goto Exit;\r
103 }\r
104 //\r
105 // Validate Namespace\r
106 //\r
107 if (NamespaceData->Ncap == 0) {\r
108 Status = EFI_DEVICE_ERROR;\r
109 } else {\r
110 //\r
111 // allocate device private data for each discovered namespace\r
112 //\r
113 Device = AllocateZeroPool(sizeof(NVME_DEVICE_PRIVATE_DATA));\r
114 if (Device == NULL) {\r
6a54db85 115 Status = EFI_OUT_OF_RESOURCES;\r
eb290d02
FT
116 goto Exit;\r
117 }\r
118\r
119 //\r
120 // Initialize SSD namespace instance data\r
121 //\r
122 Device->Signature = NVME_DEVICE_PRIVATE_DATA_SIGNATURE;\r
123 Device->NamespaceId = NamespaceId;\r
124 Device->NamespaceUuid = NamespaceData->Eui64;\r
125\r
126 Device->ControllerHandle = Private->ControllerHandle;\r
127 Device->DriverBindingHandle = Private->DriverBindingHandle;\r
128 Device->Controller = Private;\r
129\r
130 //\r
131 // Build BlockIo media structure\r
132 //\r
133 Device->Media.MediaId = 0;\r
134 Device->Media.RemovableMedia = FALSE;\r
135 Device->Media.MediaPresent = TRUE;\r
136 Device->Media.LogicalPartition = FALSE;\r
137 Device->Media.ReadOnly = FALSE;\r
138 Device->Media.WriteCaching = FALSE;\r
9cc0168a 139 Device->Media.IoAlign = Private->PassThruMode.IoAlign;\r
eb290d02
FT
140\r
141 Flbas = NamespaceData->Flbas;\r
2f34e065 142 LbaFmtIdx = Flbas & 0xF;\r
eb290d02
FT
143 Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;\r
144 Device->Media.BlockSize = (UINT32)1 << Lbads;\r
145\r
146 Device->Media.LastBlock = NamespaceData->Nsze - 1;\r
147 Device->Media.LogicalBlocksPerPhysicalBlock = 1;\r
148 Device->Media.LowestAlignedLba = 1;\r
149\r
150 //\r
151 // Create BlockIo Protocol instance\r
152 //\r
153 Device->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
154 Device->BlockIo.Media = &Device->Media;\r
155 Device->BlockIo.Reset = NvmeBlockIoReset;\r
156 Device->BlockIo.ReadBlocks = NvmeBlockIoReadBlocks;\r
157 Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks;\r
158 Device->BlockIo.FlushBlocks = NvmeBlockIoFlushBlocks;\r
159\r
758ea946
HW
160 //\r
161 // Create BlockIo2 Protocol instance\r
162 //\r
163 Device->BlockIo2.Media = &Device->Media;\r
164 Device->BlockIo2.Reset = NvmeBlockIoResetEx;\r
165 Device->BlockIo2.ReadBlocksEx = NvmeBlockIoReadBlocksEx;\r
166 Device->BlockIo2.WriteBlocksEx = NvmeBlockIoWriteBlocksEx;\r
167 Device->BlockIo2.FlushBlocksEx = NvmeBlockIoFlushBlocksEx;\r
168 InitializeListHead (&Device->AsyncQueue);\r
169\r
754b489b
TF
170 //\r
171 // Create StorageSecurityProtocol Instance\r
172 //\r
173 Device->StorageSecurity.ReceiveData = NvmeStorageSecurityReceiveData;\r
174 Device->StorageSecurity.SendData = NvmeStorageSecuritySendData;\r
175\r
eb290d02
FT
176 //\r
177 // Create DiskInfo Protocol instance\r
178 //\r
d2a2678b 179 CopyMem (&Device->NamespaceData, NamespaceData, sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
eb290d02
FT
180 InitializeDiskInfo (Device);\r
181\r
182 //\r
183 // Create a Nvm Express Namespace Device Path Node\r
184 //\r
185 Status = Private->Passthru.BuildDevicePath (\r
186 &Private->Passthru,\r
187 Device->NamespaceId,\r
eb290d02
FT
188 &NewDevicePathNode\r
189 );\r
190\r
191 if (EFI_ERROR(Status)) {\r
192 goto Exit;\r
193 }\r
194\r
195 //\r
196 // Append the SSD node to the controller's device path\r
197 //\r
198 DevicePath = AppendDevicePathNode (ParentDevicePath, NewDevicePathNode);\r
199 if (DevicePath == NULL) {\r
200 Status = EFI_OUT_OF_RESOURCES;\r
201 goto Exit;\r
202 }\r
203\r
204 DeviceHandle = NULL;\r
205 RemainingDevicePath = DevicePath;\r
206 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
207 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
208 Status = EFI_ALREADY_STARTED;\r
209 FreePool (DevicePath);\r
210 goto Exit;\r
211 }\r
212\r
213 Device->DevicePath = DevicePath;\r
214\r
215 //\r
216 // Make sure the handle is NULL so we create a new handle\r
217 //\r
218 Device->DeviceHandle = NULL;\r
219\r
220 Status = gBS->InstallMultipleProtocolInterfaces (\r
221 &Device->DeviceHandle,\r
222 &gEfiDevicePathProtocolGuid,\r
223 Device->DevicePath,\r
224 &gEfiBlockIoProtocolGuid,\r
225 &Device->BlockIo,\r
758ea946
HW
226 &gEfiBlockIo2ProtocolGuid,\r
227 &Device->BlockIo2,\r
eb290d02
FT
228 &gEfiDiskInfoProtocolGuid,\r
229 &Device->DiskInfo,\r
230 NULL\r
231 );\r
232\r
233 if(EFI_ERROR(Status)) {\r
234 goto Exit;\r
235 }\r
754b489b
TF
236\r
237 //\r
238 // Check if the NVMe controller supports the Security Send and Security Receive commands\r
239 //\r
240 if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {\r
241 Status = gBS->InstallProtocolInterface (\r
242 &Device->DeviceHandle,\r
243 &gEfiStorageSecurityCommandProtocolGuid,\r
244 EFI_NATIVE_INTERFACE,\r
245 &Device->StorageSecurity\r
246 );\r
247 if(EFI_ERROR(Status)) {\r
248 gBS->UninstallMultipleProtocolInterfaces (\r
249 &Device->DeviceHandle,\r
250 &gEfiDevicePathProtocolGuid,\r
251 Device->DevicePath,\r
252 &gEfiBlockIoProtocolGuid,\r
253 &Device->BlockIo,\r
758ea946
HW
254 &gEfiBlockIo2ProtocolGuid,\r
255 &Device->BlockIo2,\r
754b489b
TF
256 &gEfiDiskInfoProtocolGuid,\r
257 &Device->DiskInfo,\r
258 NULL\r
259 );\r
260 goto Exit;\r
261 }\r
262 }\r
263\r
eb290d02
FT
264 gBS->OpenProtocol (\r
265 Private->ControllerHandle,\r
beeeb22c
TF
266 &gEfiNvmExpressPassThruProtocolGuid,\r
267 (VOID **) &Private->Passthru,\r
eb290d02
FT
268 Private->DriverBindingHandle,\r
269 Device->DeviceHandle,\r
270 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
271 );\r
272\r
7b8883c6
FT
273 //\r
274 // Dump NvmExpress Identify Namespace Data\r
275 //\r
276 DEBUG ((EFI_D_INFO, " == NVME IDENTIFY NAMESPACE [%d] DATA ==\n", NamespaceId));\r
277 DEBUG ((EFI_D_INFO, " NSZE : 0x%x\n", NamespaceData->Nsze));\r
278 DEBUG ((EFI_D_INFO, " NCAP : 0x%x\n", NamespaceData->Ncap));\r
279 DEBUG ((EFI_D_INFO, " NUSE : 0x%x\n", NamespaceData->Nuse));\r
280 DEBUG ((EFI_D_INFO, " LBAF0.LBADS : 0x%x\n", (NamespaceData->LbaFormat[0].Lbads)));\r
281\r
eb290d02
FT
282 //\r
283 // Build controller name for Component Name (2) protocol.\r
284 //\r
da7c7274
FT
285 CopyMem (Sn, Private->ControllerData->Sn, sizeof (Private->ControllerData->Sn));\r
286 Sn[20] = 0;\r
287 CopyMem (Mn, Private->ControllerData->Mn, sizeof (Private->ControllerData->Mn));\r
288 Mn[40] = 0;\r
289 UnicodeSPrintAsciiFormat (Device->ModelName, sizeof (Device->ModelName), "%a-%a-%x", Sn, Mn, NamespaceData->Eui64);\r
eb290d02
FT
290\r
291 AddUnicodeString2 (\r
292 "eng",\r
293 gNvmExpressComponentName.SupportedLanguages,\r
294 &Device->ControllerNameTable,\r
295 Device->ModelName,\r
296 TRUE\r
297 );\r
298\r
299 AddUnicodeString2 (\r
300 "en",\r
301 gNvmExpressComponentName2.SupportedLanguages,\r
302 &Device->ControllerNameTable,\r
303 Device->ModelName,\r
304 FALSE\r
305 );\r
306 }\r
307\r
308Exit:\r
309 if(NamespaceData != NULL) {\r
310 FreePool (NamespaceData);\r
311 }\r
312\r
6a54db85
FT
313 if (NewDevicePathNode != NULL) {\r
314 FreePool (NewDevicePathNode);\r
315 }\r
316\r
eb290d02
FT
317 if(EFI_ERROR(Status) && (Device != NULL) && (Device->DevicePath != NULL)) {\r
318 FreePool (Device->DevicePath);\r
319 }\r
320 if(EFI_ERROR(Status) && (Device != NULL)) {\r
321 FreePool (Device);\r
322 }\r
323 return Status;\r
324}\r
325\r
326/**\r
327 Discover all Nvm Express device namespaces, and create child handles for them with BlockIo\r
328 and DiskInfo protocol instances.\r
329\r
330 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
331\r
332 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
333 @return Others Some error occurs when enumerating the namespaces.\r
334\r
335**/\r
336EFI_STATUS\r
337DiscoverAllNamespaces (\r
338 IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
339 )\r
340{\r
341 EFI_STATUS Status;\r
342 UINT32 NamespaceId;\r
d6c55989 343 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *Passthru;\r
eb290d02
FT
344\r
345 NamespaceId = 0xFFFFFFFF;\r
eb290d02
FT
346 Passthru = &Private->Passthru;\r
347\r
348 while (TRUE) {\r
349 Status = Passthru->GetNextNamespace (\r
350 Passthru,\r
d6c55989 351 (UINT32 *)&NamespaceId\r
eb290d02
FT
352 );\r
353\r
354 if (EFI_ERROR (Status)) {\r
355 break;\r
356 }\r
357\r
358 Status = EnumerateNvmeDevNamespace (\r
359 Private,\r
d6c55989 360 NamespaceId\r
eb290d02
FT
361 );\r
362\r
363 if (EFI_ERROR(Status)) {\r
364 continue;\r
365 }\r
366 }\r
367\r
368 return EFI_SUCCESS;\r
369}\r
370\r
371/**\r
372 Unregisters a Nvm Express device namespace.\r
373\r
374 This function removes the protocols installed on the controller handle and\r
375 frees the resources allocated for the namespace.\r
376\r
377 @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.\r
378 @param Controller The controller handle of the namespace.\r
379 @param Handle The child handle.\r
380\r
381 @retval EFI_SUCCESS The namespace is successfully unregistered.\r
382 @return Others Some error occurs when unregistering the namespace.\r
383\r
384**/\r
385EFI_STATUS\r
386UnregisterNvmeNamespace (\r
387 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
388 IN EFI_HANDLE Controller,\r
389 IN EFI_HANDLE Handle\r
390 )\r
391{\r
392 EFI_STATUS Status;\r
eb290d02
FT
393 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
394 NVME_DEVICE_PRIVATE_DATA *Device;\r
beeeb22c 395 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
754b489b 396 EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;\r
758ea946
HW
397 BOOLEAN IsEmpty;\r
398 EFI_TPL OldTpl;\r
eb290d02
FT
399\r
400 BlockIo = NULL;\r
401\r
402 Status = gBS->OpenProtocol (\r
403 Handle,\r
404 &gEfiBlockIoProtocolGuid,\r
405 (VOID **) &BlockIo,\r
406 This->DriverBindingHandle,\r
407 Controller,\r
408 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
409 );\r
410 if (EFI_ERROR (Status)) {\r
411 return Status;\r
412 }\r
413\r
beeeb22c
TF
414 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo);\r
415 Private = Device->Controller;\r
eb290d02 416\r
758ea946
HW
417 //\r
418 // Wait for the device's asynchronous I/O queue to become empty.\r
419 //\r
420 while (TRUE) {\r
421 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
422 IsEmpty = IsListEmpty (&Device->AsyncQueue);\r
423 gBS->RestoreTPL (OldTpl);\r
424\r
425 if (IsEmpty) {\r
426 break;\r
427 }\r
428\r
429 gBS->Stall (100);\r
430 }\r
431\r
eb290d02
FT
432 //\r
433 // Close the child handle\r
434 //\r
435 gBS->CloseProtocol (\r
436 Controller,\r
beeeb22c 437 &gEfiNvmExpressPassThruProtocolGuid,\r
eb290d02
FT
438 This->DriverBindingHandle,\r
439 Handle\r
440 );\r
441\r
442 //\r
443 // The Nvm Express driver installs the BlockIo and DiskInfo in the DriverBindingStart().\r
444 // Here should uninstall both of them.\r
445 //\r
446 Status = gBS->UninstallMultipleProtocolInterfaces (\r
447 Handle,\r
448 &gEfiDevicePathProtocolGuid,\r
449 Device->DevicePath,\r
450 &gEfiBlockIoProtocolGuid,\r
451 &Device->BlockIo,\r
758ea946
HW
452 &gEfiBlockIo2ProtocolGuid,\r
453 &Device->BlockIo2,\r
eb290d02
FT
454 &gEfiDiskInfoProtocolGuid,\r
455 &Device->DiskInfo,\r
456 NULL\r
457 );\r
458\r
459 if (EFI_ERROR (Status)) {\r
460 gBS->OpenProtocol (\r
461 Controller,\r
beeeb22c
TF
462 &gEfiNvmExpressPassThruProtocolGuid,\r
463 (VOID **) &Private->Passthru,\r
eb290d02
FT
464 This->DriverBindingHandle,\r
465 Handle,\r
466 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
467 );\r
468 return Status;\r
469 }\r
470\r
754b489b
TF
471 //\r
472 // If Storage Security Command Protocol is installed, then uninstall this protocol.\r
473 //\r
474 Status = gBS->OpenProtocol (\r
475 Handle,\r
476 &gEfiStorageSecurityCommandProtocolGuid,\r
477 (VOID **) &StorageSecurity,\r
478 This->DriverBindingHandle,\r
479 Controller,\r
480 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
481 );\r
482\r
483 if (!EFI_ERROR (Status)) {\r
484 Status = gBS->UninstallProtocolInterface (\r
485 Handle,\r
486 &gEfiStorageSecurityCommandProtocolGuid,\r
487 &Device->StorageSecurity\r
488 );\r
489 if (EFI_ERROR (Status)) {\r
490 gBS->OpenProtocol (\r
491 Controller,\r
492 &gEfiNvmExpressPassThruProtocolGuid,\r
493 (VOID **) &Private->Passthru,\r
494 This->DriverBindingHandle,\r
495 Handle,\r
496 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
497 );\r
498 return Status;\r
499 }\r
500 }\r
501\r
eb290d02
FT
502 if(Device->DevicePath != NULL) {\r
503 FreePool (Device->DevicePath);\r
504 }\r
505\r
506 if (Device->ControllerNameTable != NULL) {\r
507 FreeUnicodeStringTable (Device->ControllerNameTable);\r
508 }\r
509\r
6a54db85
FT
510 FreePool (Device);\r
511\r
eb290d02
FT
512 return EFI_SUCCESS;\r
513}\r
514\r
758ea946
HW
515/**\r
516 Call back function when the timer event is signaled.\r
517\r
518 @param[in] Event The Event this notify function registered to.\r
519 @param[in] Context Pointer to the context data registered to the\r
520 Event.\r
521\r
522**/\r
523VOID\r
524EFIAPI\r
525ProcessAsyncTaskList (\r
526 IN EFI_EVENT Event,\r
527 IN VOID* Context\r
528 )\r
529{\r
530 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
531 EFI_PCI_IO_PROTOCOL *PciIo;\r
532 NVME_CQ *Cq;\r
533 UINT16 QueueId;\r
534 UINT32 Data;\r
535 LIST_ENTRY *Link;\r
536 LIST_ENTRY *NextLink;\r
537 NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;\r
538 NVME_BLKIO2_SUBTASK *Subtask;\r
539 NVME_BLKIO2_REQUEST *BlkIo2Request;\r
540 EFI_BLOCK_IO2_TOKEN *Token;\r
541 BOOLEAN HasNewItem;\r
542 EFI_STATUS Status;\r
543\r
544 Private = (NVME_CONTROLLER_PRIVATE_DATA*)Context;\r
545 QueueId = 2;\r
546 Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;\r
547 HasNewItem = FALSE;\r
548\r
549 //\r
550 // Submit asynchronous subtasks to the NVMe Submission Queue\r
551 //\r
552 for (Link = GetFirstNode (&Private->UnsubmittedSubtasks);\r
553 !IsNull (&Private->UnsubmittedSubtasks, Link);\r
554 Link = NextLink) {\r
555 NextLink = GetNextNode (&Private->UnsubmittedSubtasks, Link);\r
556 Subtask = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);\r
557 BlkIo2Request = Subtask->BlockIo2Request;\r
558 Token = BlkIo2Request->Token;\r
559 RemoveEntryList (Link);\r
560 BlkIo2Request->UnsubmittedSubtaskNum--;\r
561\r
562 //\r
563 // If any previous subtask fails, do not process subsequent ones.\r
564 //\r
565 if (Token->TransactionStatus != EFI_SUCCESS) {\r
566 if (IsListEmpty (&BlkIo2Request->SubtasksQueue) &&\r
567 BlkIo2Request->LastSubtaskSubmitted &&\r
568 (BlkIo2Request->UnsubmittedSubtaskNum == 0)) {\r
569 //\r
570 // Remove the BlockIo2 request from the device asynchronous queue.\r
571 //\r
572 RemoveEntryList (&BlkIo2Request->Link);\r
573 FreePool (BlkIo2Request);\r
574 gBS->SignalEvent (Token->Event);\r
575 }\r
576\r
577 FreePool (Subtask->CommandPacket->NvmeCmd);\r
578 FreePool (Subtask->CommandPacket->NvmeCompletion);\r
579 FreePool (Subtask->CommandPacket);\r
580 FreePool (Subtask);\r
581\r
582 continue;\r
583 }\r
584\r
585 Status = Private->Passthru.PassThru (\r
586 &Private->Passthru,\r
587 Subtask->NamespaceId,\r
588 Subtask->CommandPacket,\r
589 Subtask->Event\r
590 );\r
591 if (Status == EFI_NOT_READY) {\r
592 InsertHeadList (&Private->UnsubmittedSubtasks, Link);\r
593 BlkIo2Request->UnsubmittedSubtaskNum++;\r
594 break;\r
595 } else if (EFI_ERROR (Status)) {\r
596 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
597\r
598 if (IsListEmpty (&BlkIo2Request->SubtasksQueue) &&\r
599 Subtask->IsLast) {\r
600 //\r
601 // Remove the BlockIo2 request from the device asynchronous queue.\r
602 //\r
603 RemoveEntryList (&BlkIo2Request->Link);\r
604 FreePool (BlkIo2Request);\r
605 gBS->SignalEvent (Token->Event);\r
606 }\r
607\r
608 FreePool (Subtask->CommandPacket->NvmeCmd);\r
609 FreePool (Subtask->CommandPacket->NvmeCompletion);\r
610 FreePool (Subtask->CommandPacket);\r
611 FreePool (Subtask);\r
612 } else {\r
613 InsertTailList (&BlkIo2Request->SubtasksQueue, Link);\r
614 if (Subtask->IsLast) {\r
615 BlkIo2Request->LastSubtaskSubmitted = TRUE;\r
616 }\r
617 }\r
618 }\r
619\r
620 while (Cq->Pt != Private->Pt[QueueId]) {\r
621 ASSERT (Cq->Sqid == QueueId);\r
622\r
623 HasNewItem = TRUE;\r
624\r
625 //\r
626 // Find the command with given Command Id.\r
627 //\r
628 for (Link = GetFirstNode (&Private->AsyncPassThruQueue);\r
629 !IsNull (&Private->AsyncPassThruQueue, Link);\r
630 Link = NextLink) {\r
631 NextLink = GetNextNode (&Private->AsyncPassThruQueue, Link);\r
632 AsyncRequest = NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link);\r
633 if (AsyncRequest->CommandId == Cq->Cid) {\r
634 //\r
635 // Copy the Respose Queue entry for this command to the callers\r
636 // response buffer.\r
637 //\r
638 CopyMem (\r
639 AsyncRequest->Packet->NvmeCompletion,\r
640 Cq,\r
641 sizeof(EFI_NVM_EXPRESS_COMPLETION)\r
642 );\r
643\r
644 RemoveEntryList (Link);\r
645 gBS->SignalEvent (AsyncRequest->CallerEvent);\r
646 FreePool (AsyncRequest);\r
647\r
648 //\r
649 // Update submission queue head.\r
650 //\r
651 Private->AsyncSqHead = Cq->Sqhd;\r
652 break;\r
653 }\r
654 }\r
655\r
656 Private->CqHdbl[QueueId].Cqh++;\r
657 if (Private->CqHdbl[QueueId].Cqh > NVME_ASYNC_CCQ_SIZE) {\r
658 Private->CqHdbl[QueueId].Cqh = 0;\r
659 Private->Pt[QueueId] ^= 1;\r
660 }\r
661\r
662 Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;\r
663 }\r
664\r
665 if (HasNewItem) {\r
666 PciIo = Private->PciIo;\r
667 Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueId]);\r
668 PciIo->Mem.Write (\r
669 PciIo,\r
670 EfiPciIoWidthUint32,\r
671 NVME_BAR,\r
672 NVME_CQHDBL_OFFSET(QueueId, Private->Cap.Dstrd),\r
673 1,\r
674 &Data\r
675 );\r
676 }\r
677}\r
678\r
eb290d02
FT
679/**\r
680 Tests to see if this driver supports a given controller. If a child device is provided,\r
681 it further tests to see if this driver supports creating a handle for the specified child device.\r
682\r
683 This function checks to see if the driver specified by This supports the device specified by\r
684 ControllerHandle. Drivers will typically use the device path attached to\r
685 ControllerHandle and/or the services from the bus I/O abstraction attached to\r
686 ControllerHandle to determine if the driver supports ControllerHandle. This function\r
687 may be called many times during platform initialization. In order to reduce boot times, the tests\r
688 performed by this function must be very small, and take as little time as possible to execute. This\r
689 function must not change the state of any hardware devices, and this function must be aware that the\r
690 device specified by ControllerHandle may already be managed by the same driver or a\r
691 different driver. This function must match its calls to AllocatePages() with FreePages(),\r
692 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
693 Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
694 already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
695 to guarantee the state of ControllerHandle is not modified by this function.\r
696\r
697 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
698 @param[in] ControllerHandle The handle of the controller to test. This handle\r
699 must support a protocol interface that supplies\r
700 an I/O abstraction to the driver.\r
701 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
702 parameter is ignored by device drivers, and is optional for bus\r
703 drivers. For bus drivers, if this parameter is not NULL, then\r
704 the bus driver must determine if the bus controller specified\r
705 by ControllerHandle and the child controller specified\r
706 by RemainingDevicePath are both supported by this\r
707 bus driver.\r
708\r
709 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
710 RemainingDevicePath is supported by the driver specified by This.\r
711 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
712 RemainingDevicePath is already being managed by the driver\r
713 specified by This.\r
714 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
715 RemainingDevicePath is already being managed by a different\r
716 driver or an application that requires exclusive access.\r
717 Currently not implemented.\r
718 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
719 RemainingDevicePath is not supported by the driver specified by This.\r
720**/\r
721EFI_STATUS\r
722EFIAPI\r
723NvmExpressDriverBindingSupported (\r
724 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
725 IN EFI_HANDLE Controller,\r
726 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
727 )\r
728{\r
729 EFI_STATUS Status;\r
730 EFI_DEV_PATH_PTR DevicePathNode;\r
731 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
732 EFI_PCI_IO_PROTOCOL *PciIo;\r
733 UINT8 ClassCode[3];\r
734\r
735 //\r
736 // Check whether device path is valid\r
737 //\r
738 if (RemainingDevicePath != NULL) {\r
739 //\r
740 // Check if RemainingDevicePath is the End of Device Path Node,\r
741 // if yes, go on checking other conditions\r
742 //\r
743 if (!IsDevicePathEnd (RemainingDevicePath)) {\r
744 //\r
745 // If RemainingDevicePath isn't the End of Device Path Node,\r
746 // check its validation\r
747 //\r
748 DevicePathNode.DevPath = RemainingDevicePath;\r
749\r
750 if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||\r
751 (DevicePathNode.DevPath->SubType != MSG_NVME_NAMESPACE_DP) ||\r
754b489b
TF
752 (DevicePathNodeLength(DevicePathNode.DevPath) != sizeof(NVME_NAMESPACE_DEVICE_PATH))) {\r
753 return EFI_UNSUPPORTED;\r
eb290d02
FT
754 }\r
755 }\r
756 }\r
757\r
758 //\r
759 // Open the EFI Device Path protocol needed to perform the supported test\r
760 //\r
761 Status = gBS->OpenProtocol (\r
762 Controller,\r
763 &gEfiDevicePathProtocolGuid,\r
764 (VOID **) &ParentDevicePath,\r
765 This->DriverBindingHandle,\r
766 Controller,\r
767 EFI_OPEN_PROTOCOL_BY_DRIVER\r
768 );\r
769 if (Status == EFI_ALREADY_STARTED) {\r
770 return EFI_SUCCESS;\r
771 }\r
772\r
773 if (EFI_ERROR (Status)) {\r
774 return Status;\r
775 }\r
776\r
777 //\r
778 // Close protocol, don't use device path protocol in the Support() function\r
779 //\r
780 gBS->CloseProtocol (\r
781 Controller,\r
782 &gEfiDevicePathProtocolGuid,\r
783 This->DriverBindingHandle,\r
784 Controller\r
785 );\r
786\r
787 //\r
788 // Attempt to Open PCI I/O Protocol\r
789 //\r
790 Status = gBS->OpenProtocol (\r
791 Controller,\r
792 &gEfiPciIoProtocolGuid,\r
793 (VOID **) &PciIo,\r
794 This->DriverBindingHandle,\r
795 Controller,\r
796 EFI_OPEN_PROTOCOL_BY_DRIVER\r
797 );\r
798 if (Status == EFI_ALREADY_STARTED) {\r
799 return EFI_SUCCESS;\r
800 }\r
801\r
802 if (EFI_ERROR (Status)) {\r
803 return Status;\r
804 }\r
805\r
806 //\r
807 // Now further check the PCI header: Base class (offset 0x0B) and Sub Class (offset 0x0A).\r
808 // This controller should be a Nvm Express controller.\r
809 //\r
810 Status = PciIo->Pci.Read (\r
811 PciIo,\r
812 EfiPciIoWidthUint8,\r
813 PCI_CLASSCODE_OFFSET,\r
814 sizeof (ClassCode),\r
815 ClassCode\r
816 );\r
817 if (EFI_ERROR (Status)) {\r
818 goto Done;\r
819 }\r
820\r
821 //\r
822 // Examine Nvm Express controller PCI Configuration table fields\r
823 //\r
824 if ((ClassCode[0] != PCI_IF_NVMHCI) || (ClassCode[1] != PCI_CLASS_MASS_STORAGE_NVM) || (ClassCode[2] != PCI_CLASS_MASS_STORAGE)) {\r
825 Status = EFI_UNSUPPORTED;\r
826 }\r
827\r
828Done:\r
829 gBS->CloseProtocol (\r
830 Controller,\r
831 &gEfiPciIoProtocolGuid,\r
832 This->DriverBindingHandle,\r
833 Controller\r
834 );\r
835\r
836 return Status;\r
837}\r
838\r
839\r
840/**\r
841 Starts a device controller or a bus controller.\r
842\r
843 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
844 As a result, much of the error checking on the parameters to Start() has been moved into this\r
845 common boot service. It is legal to call Start() from other locations,\r
846 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
847 1. ControllerHandle must be a valid EFI_HANDLE.\r
848 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
849 EFI_DEVICE_PATH_PROTOCOL.\r
850 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
851 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
852\r
853 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
854 @param[in] ControllerHandle The handle of the controller to start. This handle\r
855 must support a protocol interface that supplies\r
856 an I/O abstraction to the driver.\r
857 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
858 parameter is ignored by device drivers, and is optional for bus\r
859 drivers. For a bus driver, if this parameter is NULL, then handles\r
860 for all the children of Controller are created by this driver.\r
861 If this parameter is not NULL and the first Device Path Node is\r
862 not the End of Device Path Node, then only the handle for the\r
863 child device specified by the first Device Path Node of\r
864 RemainingDevicePath is created by this driver.\r
865 If the first Device Path Node of RemainingDevicePath is\r
866 the End of Device Path Node, no child handle is created by this\r
867 driver.\r
868\r
869 @retval EFI_SUCCESS The device was started.\r
870 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
871 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
872 @retval Others The driver failded to start the device.\r
873\r
874**/\r
875EFI_STATUS\r
876EFIAPI\r
877NvmExpressDriverBindingStart (\r
878 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
879 IN EFI_HANDLE Controller,\r
880 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
881 )\r
882{\r
d6c55989
FT
883 EFI_STATUS Status;\r
884 EFI_PCI_IO_PROTOCOL *PciIo;\r
885 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
886 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
887 UINT32 NamespaceId;\r
888 EFI_PHYSICAL_ADDRESS MappedAddr;\r
889 UINTN Bytes;\r
890 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *Passthru;\r
eb290d02
FT
891\r
892 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: start\n"));\r
893\r
d6c55989
FT
894 Private = NULL;\r
895 Passthru = NULL;\r
eb290d02
FT
896 ParentDevicePath = NULL;\r
897\r
898 Status = gBS->OpenProtocol (\r
899 Controller,\r
900 &gEfiDevicePathProtocolGuid,\r
901 (VOID **) &ParentDevicePath,\r
902 This->DriverBindingHandle,\r
903 Controller,\r
904 EFI_OPEN_PROTOCOL_BY_DRIVER\r
905 );\r
906 if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
907 return Status;\r
908 }\r
909\r
910 Status = gBS->OpenProtocol (\r
911 Controller,\r
912 &gEfiPciIoProtocolGuid,\r
913 (VOID **) &PciIo,\r
914 This->DriverBindingHandle,\r
915 Controller,\r
916 EFI_OPEN_PROTOCOL_BY_DRIVER\r
917 );\r
918\r
919 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
920 return Status;\r
921 }\r
922\r
923 //\r
924 // Check EFI_ALREADY_STARTED to reuse the original NVME_CONTROLLER_PRIVATE_DATA.\r
925 //\r
926 if (Status != EFI_ALREADY_STARTED) {\r
927 Private = AllocateZeroPool (sizeof (NVME_CONTROLLER_PRIVATE_DATA));\r
928\r
929 if (Private == NULL) {\r
930 DEBUG ((EFI_D_ERROR, "NvmExpressDriverBindingStart: allocating pool for Nvme Private Data failed!\n"));\r
931 Status = EFI_OUT_OF_RESOURCES;\r
d6c55989 932 goto Exit;\r
eb290d02
FT
933 }\r
934\r
935 //\r
758ea946 936 // 6 x 4kB aligned buffers will be carved out of this buffer.\r
eb290d02
FT
937 // 1st 4kB boundary is the start of the admin submission queue.\r
938 // 2nd 4kB boundary is the start of the admin completion queue.\r
939 // 3rd 4kB boundary is the start of I/O submission queue #1.\r
940 // 4th 4kB boundary is the start of I/O completion queue #1.\r
758ea946
HW
941 // 5th 4kB boundary is the start of I/O submission queue #2.\r
942 // 6th 4kB boundary is the start of I/O completion queue #2.\r
eb290d02 943 //\r
758ea946 944 // Allocate 6 pages of memory, then map it for bus master read and write.\r
eb290d02
FT
945 //\r
946 Status = PciIo->AllocateBuffer (\r
947 PciIo,\r
948 AllocateAnyPages,\r
949 EfiBootServicesData,\r
758ea946 950 6,\r
eb290d02
FT
951 (VOID**)&Private->Buffer,\r
952 0\r
953 );\r
954 if (EFI_ERROR (Status)) {\r
d6c55989 955 goto Exit;\r
eb290d02
FT
956 }\r
957\r
758ea946 958 Bytes = EFI_PAGES_TO_SIZE (6);\r
eb290d02
FT
959 Status = PciIo->Map (\r
960 PciIo,\r
961 EfiPciIoOperationBusMasterCommonBuffer,\r
962 Private->Buffer,\r
963 &Bytes,\r
964 &MappedAddr,\r
965 &Private->Mapping\r
966 );\r
967\r
758ea946 968 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (6))) {\r
d6c55989 969 goto Exit;\r
eb290d02
FT
970 }\r
971\r
972 Private->BufferPciAddr = (UINT8 *)(UINTN)MappedAddr;\r
eb290d02
FT
973\r
974 Private->Signature = NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE;\r
975 Private->ControllerHandle = Controller;\r
976 Private->ImageHandle = This->DriverBindingHandle;\r
977 Private->DriverBindingHandle = This->DriverBindingHandle;\r
978 Private->PciIo = PciIo;\r
979 Private->ParentDevicePath = ParentDevicePath;\r
980 Private->Passthru.Mode = &Private->PassThruMode;\r
981 Private->Passthru.PassThru = NvmExpressPassThru;\r
982 Private->Passthru.GetNextNamespace = NvmExpressGetNextNamespace;\r
983 Private->Passthru.BuildDevicePath = NvmExpressBuildDevicePath;\r
984 Private->Passthru.GetNamespace = NvmExpressGetNamespace;\r
d6c55989 985 CopyMem (&Private->PassThruMode, &gEfiNvmExpressPassThruMode, sizeof (EFI_NVM_EXPRESS_PASS_THRU_MODE));\r
758ea946
HW
986 InitializeListHead (&Private->AsyncPassThruQueue);\r
987 InitializeListHead (&Private->UnsubmittedSubtasks);\r
eb290d02
FT
988\r
989 Status = NvmeControllerInit (Private);\r
eb290d02 990 if (EFI_ERROR(Status)) {\r
d6c55989 991 goto Exit;\r
eb290d02
FT
992 }\r
993\r
758ea946
HW
994 //\r
995 // Start the asynchronous I/O completion monitor\r
996 //\r
997 Status = gBS->CreateEvent (\r
998 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
999 TPL_NOTIFY,\r
1000 ProcessAsyncTaskList,\r
1001 Private,\r
1002 &Private->TimerEvent\r
1003 );\r
1004 if (EFI_ERROR (Status)) {\r
1005 goto Exit;\r
1006 }\r
1007\r
1008 Status = gBS->SetTimer (\r
1009 Private->TimerEvent,\r
1010 TimerPeriodic,\r
1011 NVME_HC_ASYNC_TIMER\r
1012 );\r
1013 if (EFI_ERROR (Status)) {\r
1014 goto Exit;\r
1015 }\r
1016\r
eb290d02
FT
1017 Status = gBS->InstallMultipleProtocolInterfaces (\r
1018 &Controller,\r
d6c55989
FT
1019 &gEfiNvmExpressPassThruProtocolGuid,\r
1020 &Private->Passthru,\r
eb290d02
FT
1021 NULL\r
1022 );\r
1023 if (EFI_ERROR (Status)) {\r
d6c55989 1024 goto Exit;\r
eb290d02
FT
1025 }\r
1026 } else {\r
1027 Status = gBS->OpenProtocol (\r
1028 Controller,\r
d6c55989
FT
1029 &gEfiNvmExpressPassThruProtocolGuid,\r
1030 (VOID **) &Passthru,\r
eb290d02
FT
1031 This->DriverBindingHandle,\r
1032 Controller,\r
1033 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1034 );\r
1035 if (EFI_ERROR (Status)) {\r
d6c55989 1036 goto Exit;\r
eb290d02 1037 }\r
d6c55989
FT
1038\r
1039 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (Passthru);\r
eb290d02
FT
1040 }\r
1041\r
1042 if (RemainingDevicePath == NULL) {\r
1043 //\r
1044 // Enumerate all NVME namespaces in the controller\r
1045 //\r
1046 Status = DiscoverAllNamespaces (\r
1047 Private\r
1048 );\r
1049\r
1050 } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
1051 //\r
1052 // Enumerate the specified NVME namespace\r
1053 //\r
1054 Status = Private->Passthru.GetNamespace (\r
1055 &Private->Passthru,\r
1056 RemainingDevicePath,\r
d6c55989 1057 &NamespaceId\r
eb290d02
FT
1058 );\r
1059\r
1060 if (!EFI_ERROR (Status)) {\r
d6c55989
FT
1061 Status = EnumerateNvmeDevNamespace (\r
1062 Private,\r
1063 NamespaceId\r
1064 );\r
eb290d02
FT
1065 }\r
1066 }\r
1067\r
1068 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end successfully\n"));\r
1069 return EFI_SUCCESS;\r
1070\r
d6c55989 1071Exit:\r
eb290d02
FT
1072 if ((Private != NULL) && (Private->Mapping != NULL)) {\r
1073 PciIo->Unmap (PciIo, Private->Mapping);\r
1074 }\r
1075\r
1076 if ((Private != NULL) && (Private->Buffer != NULL)) {\r
758ea946 1077 PciIo->FreeBuffer (PciIo, 6, Private->Buffer);\r
eb290d02
FT
1078 }\r
1079\r
ac231001
TF
1080 if ((Private != NULL) && (Private->ControllerData != NULL)) {\r
1081 FreePool (Private->ControllerData);\r
1082 }\r
1083\r
eb290d02 1084 if (Private != NULL) {\r
758ea946
HW
1085 if (Private->TimerEvent != NULL) {\r
1086 gBS->CloseEvent (Private->TimerEvent);\r
1087 }\r
1088\r
eb290d02
FT
1089 FreePool (Private);\r
1090 }\r
1091\r
1092 gBS->CloseProtocol (\r
1093 Controller,\r
1094 &gEfiPciIoProtocolGuid,\r
1095 This->DriverBindingHandle,\r
1096 Controller\r
1097 );\r
1098\r
1099 gBS->CloseProtocol (\r
1100 Controller,\r
1101 &gEfiDevicePathProtocolGuid,\r
1102 This->DriverBindingHandle,\r
1103 Controller\r
1104 );\r
1105\r
1106 DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end with %r\n", Status));\r
1107\r
1108 return Status;\r
1109}\r
1110\r
1111\r
1112/**\r
1113 Stops a device controller or a bus controller.\r
1114\r
1115 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
1116 As a result, much of the error checking on the parameters to Stop() has been moved\r
1117 into this common boot service. It is legal to call Stop() from other locations,\r
1118 but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
1119 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
1120 same driver's Start() function.\r
1121 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
1122 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
1123 Start() function, and the Start() function must have called OpenProtocol() on\r
1124 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
1125\r
1126 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
1127 @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
1128 support a bus specific I/O protocol for the driver\r
1129 to use to stop the device.\r
1130 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
1131 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
1132 if NumberOfChildren is 0.\r
1133\r
1134 @retval EFI_SUCCESS The device was stopped.\r
1135 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
1136\r
1137**/\r
1138EFI_STATUS\r
1139EFIAPI\r
1140NvmExpressDriverBindingStop (\r
1141 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1142 IN EFI_HANDLE Controller,\r
1143 IN UINTN NumberOfChildren,\r
1144 IN EFI_HANDLE *ChildHandleBuffer\r
1145 )\r
1146{\r
1147 EFI_STATUS Status;\r
1148 BOOLEAN AllChildrenStopped;\r
1149 UINTN Index;\r
1150 NVME_CONTROLLER_PRIVATE_DATA *Private;\r
beeeb22c 1151 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *PassThru;\r
758ea946
HW
1152 BOOLEAN IsEmpty;\r
1153 EFI_TPL OldTpl;\r
eb290d02
FT
1154\r
1155 if (NumberOfChildren == 0) {\r
1156 Status = gBS->OpenProtocol (\r
1157 Controller,\r
beeeb22c
TF
1158 &gEfiNvmExpressPassThruProtocolGuid,\r
1159 (VOID **) &PassThru,\r
eb290d02
FT
1160 This->DriverBindingHandle,\r
1161 Controller,\r
1162 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1163 );\r
1164\r
1165 if (!EFI_ERROR (Status)) {\r
beeeb22c 1166 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (PassThru);\r
758ea946
HW
1167\r
1168 //\r
1169 // Wait for the asynchronous PassThru queue to become empty.\r
1170 //\r
1171 while (TRUE) {\r
1172 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1173 IsEmpty = IsListEmpty (&Private->AsyncPassThruQueue) &&\r
1174 IsListEmpty (&Private->UnsubmittedSubtasks);\r
1175 gBS->RestoreTPL (OldTpl);\r
1176\r
1177 if (IsEmpty) {\r
1178 break;\r
1179 }\r
1180\r
1181 gBS->Stall (100);\r
1182 }\r
1183\r
eb290d02
FT
1184 gBS->UninstallMultipleProtocolInterfaces (\r
1185 Controller,\r
beeeb22c
TF
1186 &gEfiNvmExpressPassThruProtocolGuid,\r
1187 PassThru,\r
eb290d02
FT
1188 NULL\r
1189 );\r
1190\r
758ea946
HW
1191 if (Private->TimerEvent != NULL) {\r
1192 gBS->CloseEvent (Private->TimerEvent);\r
1193 }\r
1194\r
eb290d02
FT
1195 if (Private->Mapping != NULL) {\r
1196 Private->PciIo->Unmap (Private->PciIo, Private->Mapping);\r
1197 }\r
1198\r
1199 if (Private->Buffer != NULL) {\r
758ea946 1200 Private->PciIo->FreeBuffer (Private->PciIo, 6, Private->Buffer);\r
eb290d02
FT
1201 }\r
1202\r
1203 FreePool (Private->ControllerData);\r
1204 FreePool (Private);\r
1205 }\r
1206\r
1207 gBS->CloseProtocol (\r
1208 Controller,\r
1209 &gEfiPciIoProtocolGuid,\r
1210 This->DriverBindingHandle,\r
1211 Controller\r
1212 );\r
1213 gBS->CloseProtocol (\r
1214 Controller,\r
1215 &gEfiDevicePathProtocolGuid,\r
1216 This->DriverBindingHandle,\r
1217 Controller\r
1218 );\r
1219 return EFI_SUCCESS;\r
1220 }\r
1221\r
1222 AllChildrenStopped = TRUE;\r
1223\r
1224 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1225 Status = UnregisterNvmeNamespace (This, Controller, ChildHandleBuffer[Index]);\r
1226 if (EFI_ERROR (Status)) {\r
1227 AllChildrenStopped = FALSE;\r
1228 }\r
1229 }\r
1230\r
1231 if (!AllChildrenStopped) {\r
1232 return EFI_DEVICE_ERROR;\r
1233 }\r
1234\r
1235 return EFI_SUCCESS;\r
1236}\r
1237\r
1238/**\r
1239 This is the unload handle for the NVM Express driver.\r
1240\r
1241 Disconnect the driver specified by ImageHandle from the NVMe device in the handle database.\r
1242 Uninstall all the protocols installed in the driver.\r
1243\r
1244 @param[in] ImageHandle The drivers' driver image.\r
1245\r
1246 @retval EFI_SUCCESS The image is unloaded.\r
1247 @retval Others Failed to unload the image.\r
1248\r
1249**/\r
1250EFI_STATUS\r
1251EFIAPI\r
1252NvmExpressUnload (\r
1253 IN EFI_HANDLE ImageHandle\r
1254 )\r
1255{\r
1256 EFI_STATUS Status;\r
1257 EFI_HANDLE *DeviceHandleBuffer;\r
1258 UINTN DeviceHandleCount;\r
1259 UINTN Index;\r
eb290d02
FT
1260 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
1261 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
1262\r
1263 //\r
0a2326af
FT
1264 // Get the list of the device handles managed by this driver.\r
1265 // If there is an error getting the list, then means the driver\r
1266 // doesn't manage any device. At this way, we would only close\r
1267 // those protocols installed at image handle.\r
eb290d02 1268 //\r
0a2326af 1269 DeviceHandleBuffer = NULL;\r
eb290d02 1270 Status = gBS->LocateHandleBuffer (\r
0a2326af 1271 ByProtocol,\r
beeeb22c 1272 &gEfiNvmExpressPassThruProtocolGuid,\r
eb290d02
FT
1273 NULL,\r
1274 &DeviceHandleCount,\r
1275 &DeviceHandleBuffer\r
1276 );\r
1277\r
0a2326af
FT
1278 if (!EFI_ERROR (Status)) {\r
1279 //\r
1280 // Disconnect the driver specified by ImageHandle from all\r
1281 // the devices in the handle database.\r
1282 //\r
1283 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1284 Status = gBS->DisconnectController (\r
1285 DeviceHandleBuffer[Index],\r
1286 ImageHandle,\r
1287 NULL\r
1288 );\r
1289 if (EFI_ERROR (Status)) {\r
1290 goto EXIT;\r
1291 }\r
1292 }\r
eb290d02
FT
1293 }\r
1294\r
1295 //\r
0a2326af 1296 // Uninstall all the protocols installed in the driver entry point\r
eb290d02 1297 //\r
0a2326af
FT
1298 Status = gBS->UninstallMultipleProtocolInterfaces (\r
1299 ImageHandle,\r
1300 &gEfiDriverBindingProtocolGuid,\r
1301 &gNvmExpressDriverBinding,\r
1302 &gEfiDriverSupportedEfiVersionProtocolGuid,\r
1303 &gNvmExpressDriverSupportedEfiVersion,\r
1304 NULL\r
1305 );\r
1306\r
1307 if (EFI_ERROR (Status)) {\r
1308 goto EXIT;\r
eb290d02
FT
1309 }\r
1310\r
1311 //\r
0a2326af
FT
1312 // Note we have to one by one uninstall the following protocols.\r
1313 // It's because some of them are optionally installed based on\r
1314 // the following PCD settings.\r
1315 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable\r
1316 // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable\r
1317 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable\r
1318 // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable\r
eb290d02 1319 //\r
0a2326af
FT
1320 Status = gBS->HandleProtocol (\r
1321 ImageHandle,\r
1322 &gEfiComponentNameProtocolGuid,\r
1323 (VOID **) &ComponentName\r
1324 );\r
1325 if (!EFI_ERROR (Status)) {\r
eb290d02
FT
1326 gBS->UninstallProtocolInterface (\r
1327 ImageHandle,\r
0a2326af
FT
1328 &gEfiComponentNameProtocolGuid,\r
1329 ComponentName\r
eb290d02 1330 );\r
0a2326af 1331 }\r
eb290d02 1332\r
0a2326af
FT
1333 Status = gBS->HandleProtocol (\r
1334 ImageHandle,\r
1335 &gEfiComponentName2ProtocolGuid,\r
1336 (VOID **) &ComponentName2\r
1337 );\r
1338 if (!EFI_ERROR (Status)) {\r
1339 gBS->UninstallProtocolInterface (\r
1340 ImageHandle,\r
1341 &gEfiComponentName2ProtocolGuid,\r
1342 ComponentName2\r
1343 );\r
eb290d02
FT
1344 }\r
1345\r
0a2326af
FT
1346 Status = EFI_SUCCESS;\r
1347\r
1348EXIT:\r
eb290d02
FT
1349 //\r
1350 // Free the buffer containing the list of handles from the handle database\r
1351 //\r
1352 if (DeviceHandleBuffer != NULL) {\r
1353 gBS->FreePool (DeviceHandleBuffer);\r
1354 }\r
0a2326af 1355 return Status;\r
eb290d02
FT
1356}\r
1357\r
1358/**\r
1359 The entry point for Nvm Express driver, used to install Nvm Express driver on the ImageHandle.\r
1360\r
1361 @param ImageHandle The firmware allocated handle for this driver image.\r
1362 @param SystemTable Pointer to the EFI system table.\r
1363\r
1364 @retval EFI_SUCCESS Driver loaded.\r
1365 @retval other Driver not loaded.\r
1366\r
1367**/\r
1368EFI_STATUS\r
1369EFIAPI\r
1370NvmExpressDriverEntry (\r
1371 IN EFI_HANDLE ImageHandle,\r
1372 IN EFI_SYSTEM_TABLE *SystemTable\r
1373 )\r
1374{\r
1375 EFI_STATUS Status;\r
1376\r
1377 Status = EfiLibInstallDriverBindingComponentName2 (\r
1378 ImageHandle,\r
1379 SystemTable,\r
1380 &gNvmExpressDriverBinding,\r
1381 ImageHandle,\r
1382 &gNvmExpressComponentName,\r
1383 &gNvmExpressComponentName2\r
1384 );\r
1385 ASSERT_EFI_ERROR (Status);\r
1386\r
1387 //\r
1388 // Install EFI Driver Supported EFI Version Protocol required for\r
1389 // EFI drivers that are on PCI and other plug in cards.\r
1390 //\r
1391 gNvmExpressDriverSupportedEfiVersion.FirmwareVersion = 0x00020028;\r
1392 Status = gBS->InstallMultipleProtocolInterfaces (\r
1393 &ImageHandle,\r
1394 &gEfiDriverSupportedEfiVersionProtocolGuid,\r
1395 &gNvmExpressDriverSupportedEfiVersion,\r
1396 NULL\r
1397 );\r
1398 ASSERT_EFI_ERROR (Status);\r
1399 return Status;\r
1400}\r