Support dynamic insertion and removal of the protocol Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Nikita Leshenko <nikita.leshche...@oracle.com> Reviewed-by: Konrad Rzeszutek Wilk <konrad.w...@oracle.com> Reviewed-by: Aaron Young <aaron.yo...@oracle.com> Reviewed-by: Liran Alon <liran.a...@oracle.com> --- 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 edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel