Support dynamic insertion and removal of the protocol
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Nikita Leshenko <[email protected]>
Reviewed-by: Konrad Rzeszutek Wilk <[email protected]>
Reviewed-by: Aaron Young <[email protected]>
Reviewed-by: Liran Alon <[email protected]>
---
OvmfPkg/MptScsiDxe/MptScsi.c | 204 +++++++++++++++++++++++++++++-
OvmfPkg/MptScsiDxe/MptScsiDxe.inf | 5 +-
2 files changed, 205 insertions(+), 4 deletions(-)
diff --git a/OvmfPkg/MptScsiDxe/MptScsi.c b/OvmfPkg/MptScsiDxe/MptScsi.c
index 57a17ca0cb..6b655d9fe8 100644
--- a/OvmfPkg/MptScsiDxe/MptScsi.c
+++ b/OvmfPkg/MptScsiDxe/MptScsi.c
@@ -16,10 +16,13 @@
**/
#include <IndustryStandard/Pci.h>
+#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/PciIo.h>
+#include <Protocol/ScsiPassThruExt.h>
//
// Device offsets and constants
@@ -30,6 +33,118 @@
#define LSI_SAS1068_PCI_DEVICE_ID 0x0054
#define LSI_SAS1068E_PCI_DEVICE_ID 0x0058
+//
+// Runtime Structures
+//
+
+#define MPT_SCSI_DEV_SIGNATURE SIGNATURE_32 ('M','P','T','S')
+typedef struct {
+ UINT32 Signature;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
+ EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode;
+} MPT_SCSI_DEV;
+
+#define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
+ CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)
+
+//
+// Ext SCSI Pass Thru
+//
+
+STATIC
+EFI_STATUS
+EFIAPI
+MptScsiPassThru (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+ IN EFI_EVENT Event OPTIONAL
+ )
+{
+ DEBUG ((EFI_D_INFO, "MptScsiPassThru Direction %d In %d Out %d\n",
+ Packet->DataDirection,
+ Packet->InTransferLength, Packet->OutTransferLength));
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+MptScsiGetNextTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target,
+ IN OUT UINT64 *Lun
+ )
+{
+ DEBUG ((EFI_D_INFO, "MptScsiGetNextTargetLun %d %d\n", **Target, *Lun));
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+MptScsiGetNextTarget (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN OUT UINT8 **Target
+ )
+{
+ DEBUG ((EFI_D_INFO, "MptScsiGetNextTarget\n"));
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+MptScsiBuildDevicePath (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ DEBUG ((EFI_D_INFO, "MptScsiBuildDevicePath %d %d\n", *Target, Lun));
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+MptScsiGetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 **Target,
+ OUT UINT64 *Lun
+ )
+{
+ DEBUG ((EFI_D_INFO, "MptScsiGetTargetLun\n"));
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+MptScsiResetChannel (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
+ )
+{
+ DEBUG ((EFI_D_INFO, "MptScsiResetChannel\n"));
+ return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+MptScsiResetTargetLun (
+ IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+ IN UINT8 *Target,
+ IN UINT64 Lun
+ )
+{
+ DEBUG ((EFI_D_INFO, "MptScsiResetTargetLun\n"));
+ return EFI_UNSUPPORTED;
+}
+
//
// Driver Binding
//
@@ -94,8 +209,65 @@ MptScsiControllerStart (
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
- DEBUG ((EFI_D_INFO, "Attempted to start MptScsi\n"));
- return EFI_UNSUPPORTED;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ MPT_SCSI_DEV *Dev;
+
+ DEBUG ((EFI_D_INFO, "Starting MptScsi\n"));
+
+ //
+ // MPT_SCSI_DEV contains descriptors that are passed to the controller. The
+ // controller doesn't easily support addresses larger than 4GB, so we
allocate
+ // the struct below 4GB. (Technically we can use HostMfaHighAddr and make
sure
+ // all descriptors have the same high address but it's more complicated than
+ // just allocating below 4GB. Also, we allocate it only once per device so
the
+ // overhead of allocating a whole page is minimal.)
+ //
+ PhysicalAddress = MAX_UINT32;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (sizeof (*Dev)),
+ &PhysicalAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // PhysicalAddress is page aligned, so MPT_SCSI_DEV alignment is correct
+ Dev = (MPT_SCSI_DEV *) (UINTN) PhysicalAddress;
+ ZeroMem (Dev, sizeof (*Dev));
+ Dev->Signature = MPT_SCSI_DEV_SIGNATURE;
+
+ Dev->PassThruMode.AdapterId = MAX_UINT32; // Host adapter channel, doesn't
exist
+ Dev->PassThruMode.Attributes =
+ EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL
+ | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
+
+ Dev->PassThru.Mode = &Dev->PassThruMode;
+ Dev->PassThru.PassThru = &MptScsiPassThru;
+ Dev->PassThru.GetNextTargetLun = &MptScsiGetNextTargetLun;
+ Dev->PassThru.BuildDevicePath = &MptScsiBuildDevicePath;
+ Dev->PassThru.GetTargetLun = &MptScsiGetTargetLun;
+ Dev->PassThru.ResetChannel = &MptScsiResetChannel;
+ Dev->PassThru.ResetTargetLun = &MptScsiResetTargetLun;
+ Dev->PassThru.GetNextTarget = &MptScsiGetNextTarget;
+
+ Status = gBS->InstallProtocolInterface (
+ &ControllerHandle,
+ &gEfiExtScsiPassThruProtocolGuid, EFI_NATIVE_INTERFACE,
+ &Dev->PassThru);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ DEBUG ((EFI_D_INFO, "MptScsi Installed\n"));
+Done:
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Dev, EFI_SIZE_TO_PAGES
(sizeof (*Dev)));
+ }
+
+ return Status;
}
STATIC
@@ -108,7 +280,33 @@ MptScsiControllerStop (
IN EFI_HANDLE *ChildHandleBuffer
)
{
- return EFI_UNSUPPORTED;
+ EFI_STATUS Status;
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
+ MPT_SCSI_DEV *Dev = NULL;
+
+ DEBUG ((EFI_D_INFO, "Stopping MptScsi\n"));
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiExtScsiPassThruProtocolGuid,
+ (VOID **)&PassThru,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL); // Lookup only
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Dev = MPT_SCSI_FROM_PASS_THRU (PassThru);
+
+ gBS->UninstallProtocolInterface (
+ ControllerHandle,
+ &gEfiExtScsiPassThruProtocolGuid,
+ &Dev->PassThru);
+
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Dev, EFI_SIZE_TO_PAGES
(sizeof (*Dev)));
+
+ return Status;
}
// Higher versions will be used before lower, 0x10-0xffffffef is the version
diff --git a/OvmfPkg/MptScsiDxe/MptScsiDxe.inf
b/OvmfPkg/MptScsiDxe/MptScsiDxe.inf
index 3608cecaab..5d424606a5 100644
--- a/OvmfPkg/MptScsiDxe/MptScsiDxe.inf
+++ b/OvmfPkg/MptScsiDxe/MptScsiDxe.inf
@@ -30,10 +30,13 @@
OvmfPkg/OvmfPkg.dec
[LibraryClasses]
+ BaseMemoryLib
DebugLib
+ MemoryAllocationLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiLib
[Protocols]
- gEfiPciIoProtocolGuid ## TO_START
\ No newline at end of file
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiExtScsiPassThruProtocolGuid ## BY_START
--
2.20.1
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel