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