From 7efce2e59c2016f0b2572d4b79845f14a8758475 Mon Sep 17 00:00:00 2001 From: Liran Alon Date: Sat, 28 Mar 2020 23:00:49 +0300 Subject: [PATCH] OvmfPkg/PvScsiDxe: Report the number of targets and LUNs Implement EXT_SCSI_PASS_THRU.GetNextTarget() and EXT_SCSI_PASS_THRU.GetNextTargetLun(). ScsiBusDxe scans all MaxTarget * MaxLun possible devices. This can take unnecessarily long for large number of targets. To deal with this, VirtioScsiDxe has defined PCDs to limit the MaxTarget & MaxLun to desired values which gives sufficient performance. It is very important in virtio-scsi as it can have very big MaxTarget & MaxLun. Even though a common PVSCSI device has a default MaxTarget=64 and MaxLun=0, we implement similar mechanism as virtio-scsi for completeness. This may be useful in the future when PVSCSI will have bigger values for MaxTarget and MaxLun. Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567 Reviewed-by: Laszlo Ersek Signed-off-by: Liran Alon Message-Id: <20200328200100.60786-7-liran.alon@oracle.com> Reviewed-by: Nikita Leshenko --- OvmfPkg/OvmfPkg.dec | 9 +++ OvmfPkg/PvScsiDxe/PvScsi.c | 122 +++++++++++++++++++++++++++++++- OvmfPkg/PvScsiDxe/PvScsi.h | 2 + OvmfPkg/PvScsiDxe/PvScsiDxe.inf | 5 ++ 4 files changed, 136 insertions(+), 2 deletions(-) diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index 913345d49e..adb7ac2e23 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -134,6 +134,15 @@ gUefiOvmfPkgTokenSpaceGuid.PcdVirtioScsiMaxTargetLimit|31|UINT16|6 gUefiOvmfPkgTokenSpaceGuid.PcdVirtioScsiMaxLunLimit|7|UINT32|7 + ## Sets the *inclusive* number of targets and LUNs that PvScsi exposes for + # scan by ScsiBusDxe. + # As specified above for VirtioScsi, ScsiBusDxe scans all MaxTarget * MaxLun + # possible devices, which can take extremely long. Thus, the below constants + # are used so that scanning the number of devices given by their product + # is still acceptably fast. + gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit|64|UINT8|0x36 + gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit|0|UINT8|0x37 + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogBase|0x0|UINT32|0x8 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogSize|0x0|UINT32|0x9 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize|0x0|UINT32|0xa diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c index 04c08036b7..7f51ada19a 100644 --- a/OvmfPkg/PvScsiDxe/PvScsi.c +++ b/OvmfPkg/PvScsiDxe/PvScsi.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,30 @@ // #define PVSCSI_BINDING_VERSION 0x10 +// +// Ext SCSI Pass Thru utilities +// + +/** + Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and + EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized +**/ +STATIC +BOOLEAN +IsTargetInitialized ( + IN UINT8 *Target + ) +{ + UINTN Idx; + + for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) { + if (Target[Idx] != 0xFF) { + return TRUE; + } + } + return FALSE; +} + // // Ext SCSI Pass Thru // @@ -52,7 +77,54 @@ PvScsiGetNextTargetLun ( IN OUT UINT64 *Lun ) { - return EFI_UNSUPPORTED; + UINT8 *TargetPtr; + UINT8 LastTarget; + PVSCSI_DEV *Dev; + + if (Target == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // The Target input parameter is unnecessarily a pointer-to-pointer + // + TargetPtr = *Target; + + // + // If target not initialized, return first target & LUN + // + if (!IsTargetInitialized (TargetPtr)) { + ZeroMem (TargetPtr, TARGET_MAX_BYTES); + *Lun = 0; + return EFI_SUCCESS; + } + + // + // We only use first byte of target identifer + // + LastTarget = *TargetPtr; + + // + // Increment (target, LUN) pair if valid on input + // + Dev = PVSCSI_FROM_PASS_THRU (This); + if (LastTarget > Dev->MaxTarget || *Lun > Dev->MaxLun) { + return EFI_INVALID_PARAMETER; + } + + if (*Lun < Dev->MaxLun) { + ++*Lun; + return EFI_SUCCESS; + } + + if (LastTarget < Dev->MaxTarget) { + *Lun = 0; + ++LastTarget; + *TargetPtr = LastTarget; + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; } STATIC @@ -111,7 +183,47 @@ PvScsiGetNextTarget ( IN OUT UINT8 **Target ) { - return EFI_UNSUPPORTED; + UINT8 *TargetPtr; + UINT8 LastTarget; + PVSCSI_DEV *Dev; + + if (Target == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // The Target input parameter is unnecessarily a pointer-to-pointer + // + TargetPtr = *Target; + + // + // If target not initialized, return first target + // + if (!IsTargetInitialized (TargetPtr)) { + ZeroMem (TargetPtr, TARGET_MAX_BYTES); + return EFI_SUCCESS; + } + + // + // We only use first byte of target identifer + // + LastTarget = *TargetPtr; + + // + // Increment target if valid on input + // + Dev = PVSCSI_FROM_PASS_THRU (This); + if (LastTarget > Dev->MaxTarget) { + return EFI_INVALID_PARAMETER; + } + + if (LastTarget < Dev->MaxTarget) { + ++LastTarget; + *TargetPtr = LastTarget; + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; } STATIC @@ -120,6 +232,12 @@ PvScsiInit ( IN OUT PVSCSI_DEV *Dev ) { + // + // Init configuration + // + Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit); + Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit); + // // Populate the exported interface's attributes // diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h index 3940b4c200..dd3e0c68e6 100644 --- a/OvmfPkg/PvScsiDxe/PvScsi.h +++ b/OvmfPkg/PvScsiDxe/PvScsi.h @@ -19,6 +19,8 @@ typedef struct { UINT32 Signature; + UINT8 MaxTarget; + UINT8 MaxLun; EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru; EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode; } PVSCSI_DEV; diff --git a/OvmfPkg/PvScsiDxe/PvScsiDxe.inf b/OvmfPkg/PvScsiDxe/PvScsiDxe.inf index f4d452c6c3..fcffc90d46 100644 --- a/OvmfPkg/PvScsiDxe/PvScsiDxe.inf +++ b/OvmfPkg/PvScsiDxe/PvScsiDxe.inf @@ -26,6 +26,7 @@ OvmfPkg/OvmfPkg.dec [LibraryClasses] + BaseMemoryLib DebugLib MemoryAllocationLib UefiBootServicesTableLib @@ -35,3 +36,7 @@ [Protocols] gEfiExtScsiPassThruProtocolGuid ## BY_START gEfiPciIoProtocolGuid ## TO_START + +[Pcd] + gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit ## CONSUMES + gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit ## CONSUMES -- 2.39.2