public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller
@ 2020-03-16 15:00 liran.alon
  2020-03-16 15:00 ` [PATCH 01/17] OvmfPkg/PvScsiDxe: Create empty driver Liran Alon
                   ` (17 more replies)
  0 siblings, 18 replies; 47+ messages in thread
From: liran.alon @ 2020-03-16 15:00 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

Hi,

This series adds driver support for VMware PVSCSI controller.

This controller is supported by VMware and QEMU. This work is part of
the more general agenda of enhancing OVMF boot device support to have
feature parity with SeaBIOS (Which supports booting from VMware PVSCSI).

The BugZilla ticket for this feature is at:
https://bugzilla.tianocore.org/show_bug.cgi?id=2567

I pushed a copy of these patches to:
https://github.com/nikital/edk2/tree/pvscsi4

Regards,
-Liran



^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH 01/17] OvmfPkg/PvScsiDxe: Create empty driver
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
@ 2020-03-16 15:00 ` Liran Alon
  2020-03-24 11:15   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:00 ` [PATCH 02/17] OvmfPkg/PvScsiDxe: Install DriverBinding protocol Liran Alon
                   ` (16 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:00 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

In preparation for support booting from PvScsi devices, create a
basic scaffolding for a driver.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/OvmfPkgIa32.dsc      |  8 ++++++++
 OvmfPkg/OvmfPkgIa32.fdf      |  3 +++
 OvmfPkg/OvmfPkgIa32X64.dsc   |  8 ++++++++
 OvmfPkg/OvmfPkgIa32X64.fdf   |  3 +++
 OvmfPkg/OvmfPkgX64.dsc       |  8 ++++++++
 OvmfPkg/OvmfPkgX64.fdf       |  3 +++
 OvmfPkg/PvScsiDxe/PvScsi.c   | 24 ++++++++++++++++++++++++
 OvmfPkg/PvScsiDxe/PvScsi.inf | 27 +++++++++++++++++++++++++++
 8 files changed, 84 insertions(+)
 create mode 100644 OvmfPkg/PvScsiDxe/PvScsi.c
 create mode 100644 OvmfPkg/PvScsiDxe/PvScsi.inf

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 19728f20b34e..79b8c58e54c3 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -44,6 +44,11 @@
 
 !include NetworkPkg/NetworkDefines.dsc.inc
 
+  #
+  # Device drivers
+  #
+  DEFINE PVSCSI_ENABLE           = TRUE
+
   #
   # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to
   # one of the supported values, in place of any of the convenience macros, is
@@ -718,6 +723,9 @@
   OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
   OvmfPkg/XenBusDxe/XenBusDxe.inf
   OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
+!ifdef $(PVSCSI_ENABLE)
+  OvmfPkg/PvScsiDxe/PvScsiDxe.inf
+!endif
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
   MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
index 63607551ed75..f59a58bc2689 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.fdf
@@ -227,6 +227,9 @@ INF  OvmfPkg/VirtioRngDxe/VirtioRng.inf
 INF  OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
 INF  OvmfPkg/XenBusDxe/XenBusDxe.inf
 INF  OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
+!if $(PVSCSI_ENABLE) == TRUE
+  INF  OvmfPkg/PvScsiDxe/PvScsiDxe.inf
+!endif
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 3c0c229e3a72..744f7eb05e12 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -44,6 +44,11 @@
 
 !include NetworkPkg/NetworkDefines.dsc.inc
 
+  #
+  # Device drivers
+  #
+  DEFINE PVSCSI_ENABLE           = TRUE
+
   #
   # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to
   # one of the supported values, in place of any of the convenience macros, is
@@ -731,6 +736,9 @@
   OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
   OvmfPkg/XenBusDxe/XenBusDxe.inf
   OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
+!ifdef $(PVSCSI_ENABLE)
+  OvmfPkg/PvScsiDxe/PvScsiDxe.inf
+!endif
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
   MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
index 0488e5d95ffe..5fd21ea1b2de 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -228,6 +228,9 @@ INF  OvmfPkg/VirtioRngDxe/VirtioRng.inf
 INF  OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
 INF  OvmfPkg/XenBusDxe/XenBusDxe.inf
 INF  OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
+!if $(PVSCSI_ENABLE) == TRUE
+  INF  OvmfPkg/PvScsiDxe/PvScsiDxe.inf
+!endif
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index f6c1d8d228c6..64ed3d5ec18e 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -44,6 +44,11 @@
 
 !include NetworkPkg/NetworkDefines.dsc.inc
 
+  #
+  # Device drivers
+  #
+  DEFINE PVSCSI_ENABLE           = TRUE
+
   #
   # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to
   # one of the supported values, in place of any of the convenience macros, is
@@ -729,6 +734,9 @@
   OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
   OvmfPkg/XenBusDxe/XenBusDxe.inf
   OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
+!ifdef $(PVSCSI_ENABLE)
+  OvmfPkg/PvScsiDxe/PvScsi.inf
+!endif
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
   MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 0488e5d95ffe..c155993dc16f 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -228,6 +228,9 @@ INF  OvmfPkg/VirtioRngDxe/VirtioRng.inf
 INF  OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
 INF  OvmfPkg/XenBusDxe/XenBusDxe.inf
 INF  OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
+!if $(PVSCSI_ENABLE) == TRUE
+  INF  OvmfPkg/PvScsiDxe/PvScsi.inf
+!endif
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
new file mode 100644
index 000000000000..a3f704d60d77
--- /dev/null
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -0,0 +1,24 @@
+/** @file
+
+  This driver produces Extended SCSI Pass Thru Protocol instances for
+  pvscsi devices.
+
+  Copyright (C) 2020, Oracle and/or its affiliates.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// Entry Point
+//
+
+EFI_STATUS
+EFIAPI
+PvScsiEntryPoint (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
new file mode 100644
index 000000000000..093cc0171338
--- /dev/null
+++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
@@ -0,0 +1,27 @@
+## @file
+#
+# This driver produces Extended SCSI Pass Thru Protocol instances for
+# pvscsi devices.
+#
+# Copyright (C) 2020, Oracle and/or its affiliates.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 1.29
+  BASE_NAME                      = PvScsiDxe
+  FILE_GUID                      = 30346B14-1580-4781-879D-BA0C55AE9BB2
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = PvScsiEntryPoint
+
+[Sources]
+  PvScsi.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 02/17] OvmfPkg/PvScsiDxe: Install DriverBinding protocol
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
  2020-03-16 15:00 ` [PATCH 01/17] OvmfPkg/PvScsiDxe: Create empty driver Liran Alon
@ 2020-03-16 15:00 ` Liran Alon
  2020-03-24 11:23   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:00 ` [PATCH 03/17] OvmfPkg/PvScsiDxe: Report name of driver Liran Alon
                   ` (15 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:00 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

In order to probe and connect to the PvScsi device we need this
protocol. Currently it does nothing.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c   | 68 +++++++++++++++++++++++++++++++++++-
 OvmfPkg/PvScsiDxe/PvScsi.inf |  1 +
 2 files changed, 68 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index a3f704d60d77..bf0c743bad15 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -9,6 +9,65 @@
 
 **/
 
+#include <Library/UefiLib.h>
+
+//
+// Higher versions will be used before lower, 0x10-0xffffffef is the version
+// range for IVH (Indie Hardware Vendors)
+//
+#define PVSCSI_BINDING_VERSION      0x10
+
+//
+// Driver Binding
+//
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiDriverBindingStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN UINTN                       NumberOfChildren,
+  IN EFI_HANDLE                  *ChildHandleBuffer
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding = {
+  &PvScsiDriverBindingSupported,
+  &PvScsiDriverBindingStart,
+  &PvScsiDriverBindingStop,
+  PVSCSI_BINDING_VERSION,
+  NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2()
+  NULL  // DriverBindingHandle, filled as well
+};
+
 //
 // Entry Point
 //
@@ -20,5 +79,12 @@ PvScsiEntryPoint (
   IN EFI_SYSTEM_TABLE *SystemTable
   )
 {
-  return EFI_UNSUPPORTED;
+  return EfiLibInstallDriverBindingComponentName2 (
+           ImageHandle,
+           SystemTable,
+           &mPvScsiDriverBinding,
+           ImageHandle,
+           NULL, // TODO Component name
+           NULL  // TODO Component name
+           );
 }
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
index 093cc0171338..d1d0e963f96d 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.inf
+++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
@@ -25,3 +25,4 @@
 
 [LibraryClasses]
   UefiDriverEntryPoint
+  UefiLib
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 03/17] OvmfPkg/PvScsiDxe: Report name of driver
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
  2020-03-16 15:00 ` [PATCH 01/17] OvmfPkg/PvScsiDxe: Create empty driver Liran Alon
  2020-03-16 15:00 ` [PATCH 02/17] OvmfPkg/PvScsiDxe: Install DriverBinding protocol Liran Alon
@ 2020-03-16 15:00 ` Liran Alon
  2020-03-24 11:29   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 04/17] OvmfPkg/PvScsiDxe: Probe PCI devices and look for PvScsi Liran Alon
                   ` (14 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:00 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

Install Component Name protocols to have a nice display name for the
driver in places such as UEFI shell.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c | 63 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 61 insertions(+), 2 deletions(-)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index bf0c743bad15..0c81e645de08 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -68,6 +68,65 @@ EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding = {
   NULL  // DriverBindingHandle, filled as well
 };
 
+//
+// Component Name
+//
+
+STATIC
+EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
+  { "eng;en", L"PVSCSI Host Driver" },
+  { NULL,     NULL                  }
+};
+
+STATIC
+EFI_COMPONENT_NAME_PROTOCOL mComponentName;
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &mComponentName) // Iso639Language
+           );
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiGetDeviceName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  EFI_HANDLE                  DeviceHandle,
+  IN  EFI_HANDLE                  ChildHandle,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **ControllerName
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
+  &PvScsiGetDriverName,
+  &PvScsiGetDeviceName,
+  "eng" // SupportedLanguages, ISO 639-2 language codes
+};
+
+STATIC
+EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &PvScsiGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &PvScsiGetDeviceName,
+  "en" // SupportedLanguages, RFC 4646 language codes
+};
+
 //
 // Entry Point
 //
@@ -84,7 +143,7 @@ PvScsiEntryPoint (
            SystemTable,
            &mPvScsiDriverBinding,
            ImageHandle,
-           NULL, // TODO Component name
-           NULL  // TODO Component name
+           &mComponentName,
+           &mComponentName2
            );
 }
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 04/17] OvmfPkg/PvScsiDxe: Probe PCI devices and look for PvScsi
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (2 preceding siblings ...)
  2020-03-16 15:00 ` [PATCH 03/17] OvmfPkg/PvScsiDxe: Report name of driver Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 11:41   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 05/17] OvmfPkg/PvScsiDxe: Install stubbed EXT_SCSI_PASS_THRU Liran Alon
                   ` (13 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

PvScsiControllerSupported() is called on handles passed in
by the ConnectController() boot service and if the handle is the
PVSCSI controller, the function would return success. A success
return value will attach our driver to the device.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/Include/IndustryStandard/PvScsi.h | 21 ++++++++++
 OvmfPkg/PvScsiDxe/PvScsi.c                | 49 ++++++++++++++++++++++-
 OvmfPkg/PvScsiDxe/PvScsi.inf              |  5 +++
 3 files changed, 74 insertions(+), 1 deletion(-)
 create mode 100644 OvmfPkg/Include/IndustryStandard/PvScsi.h

diff --git a/OvmfPkg/Include/IndustryStandard/PvScsi.h b/OvmfPkg/Include/IndustryStandard/PvScsi.h
new file mode 100644
index 000000000000..004c0af84989
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/PvScsi.h
@@ -0,0 +1,21 @@
+/** @file
+
+  VMware PVSCSI Device specific type and macro definitions.
+
+  Copyright (C) 2020, Oracle and/or its affiliates.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PVSCSI_H_
+#define __PVSCSI_H_
+
+//
+// Device offsets and constants
+//
+
+#define PCI_VENDOR_ID_VMWARE            (0x15ad)
+#define PCI_DEVICE_ID_VMWARE_PVSCSI     (0x07c0)
+
+#endif // __PVSCSI_H_
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index 0c81e645de08..f1fffe962233 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -9,7 +9,11 @@
 
 **/
 
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/PvScsi.h>
+#include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
+#include <Protocol/PciIo.h>
 
 //
 // Higher versions will be used before lower, 0x10-0xffffffef is the version
@@ -30,7 +34,50 @@ PvScsiDriverBindingSupported (
   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
   )
 {
-  return EFI_UNSUPPORTED;
+  EFI_STATUS          Status;
+  EFI_PCI_IO_PROTOCOL *PciIo;
+  PCI_TYPE00          Pci;
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **)&PciIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        0,
+                        sizeof(Pci) / sizeof(UINT32),
+                        &Pci
+                        );
+  if (EFI_ERROR (Status)) {
+      goto Done;
+  }
+
+  if ((Pci.Hdr.VendorId != PCI_VENDOR_ID_VMWARE) ||
+      (Pci.Hdr.DeviceId != PCI_DEVICE_ID_VMWARE_PVSCSI)) {
+      Status = EFI_UNSUPPORTED;
+      goto Done;
+  }
+
+  Status = EFI_SUCCESS;
+
+Done:
+  gBS->CloseProtocol (
+         ControllerHandle,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         ControllerHandle
+         );
+
+  return Status;
 }
 
 STATIC
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
index d1d0e963f96d..c1f0663832ed 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.inf
+++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
@@ -22,7 +22,12 @@
 
 [Packages]
   MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
 
 [LibraryClasses]
+  UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiLib
+
+[Protocols]
+  gEfiPciIoProtocolGuid        ## TO_START
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 05/17] OvmfPkg/PvScsiDxe: Install stubbed EXT_SCSI_PASS_THRU
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (3 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 04/17] OvmfPkg/PvScsiDxe: Probe PCI devices and look for PvScsi Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 12:27   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 06/17] OvmfPkg/PvScsiDxe: Report the number of targets and LUNs Liran Alon
                   ` (12 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

Support dynamic insertion and removal of the protocol.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c   | 209 ++++++++++++++++++++++++++++++++++-
 OvmfPkg/PvScsiDxe/PvScsi.h   |  29 +++++
 OvmfPkg/PvScsiDxe/PvScsi.inf |   5 +-
 3 files changed, 240 insertions(+), 3 deletions(-)
 create mode 100644 OvmfPkg/PvScsiDxe/PvScsi.h

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index f1fffe962233..46b430a34a57 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -11,16 +11,155 @@
 
 #include <IndustryStandard/Pci.h>
 #include <IndustryStandard/PvScsi.h>
+#include <Library/MemoryAllocationLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
 #include <Protocol/PciIo.h>
 
+#include "PvScsi.h"
+
 //
 // Higher versions will be used before lower, 0x10-0xffffffef is the version
 // range for IVH (Indie Hardware Vendors)
 //
 #define PVSCSI_BINDING_VERSION      0x10
 
+//
+// Ext SCSI Pass Thru
+//
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiPassThru (
+  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
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiGetNextTargetLun (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
+  IN OUT UINT8                                      **Target,
+  IN OUT UINT64                                     *Lun
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiBuildDevicePath (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
+  IN UINT8                                          *Target,
+  IN UINT64                                         Lun,
+  IN OUT EFI_DEVICE_PATH_PROTOCOL                   **DevicePath
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiGetTargetLun (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
+  IN EFI_DEVICE_PATH_PROTOCOL                       *DevicePath,
+  OUT UINT8                                         **Target,
+  OUT UINT64                                        *Lun
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiResetChannel (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiResetTargetLun (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
+  IN UINT8                                          *Target,
+  IN UINT64                                         Lun
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+PvScsiGetNextTarget (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
+  IN OUT UINT8                                      **Target
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+STATIC
+EFI_STATUS
+PvScsiInit (
+  IN OUT PVSCSI_DEV *Dev
+  )
+{
+  //
+  // Populate the exported interface's attributes
+  //
+  Dev->PassThru.Mode             = &Dev->PassThruMode;
+  Dev->PassThru.PassThru         = &PvScsiPassThru;
+  Dev->PassThru.GetNextTargetLun = &PvScsiGetNextTargetLun;
+  Dev->PassThru.BuildDevicePath  = &PvScsiBuildDevicePath;
+  Dev->PassThru.GetTargetLun     = &PvScsiGetTargetLun;
+  Dev->PassThru.ResetChannel     = &PvScsiResetChannel;
+  Dev->PassThru.ResetTargetLun   = &PvScsiResetTargetLun;
+  Dev->PassThru.GetNextTarget    = &PvScsiGetNextTarget;
+
+  //
+  // AdapterId is a target for which no handle will be created during bus scan.
+  // Prevent any conflict with real devices.
+  //
+  Dev->PassThruMode.AdapterId = MAX_UINT32;
+
+  //
+  // Set both physical and logical attributes for non-RAID SCSI channel
+  //
+  Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
+                                 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
+
+  //
+  // No restriction on transfer buffer alignment
+  //
+  Dev->PassThruMode.IoAlign = 0;
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+PvScsiUninit (
+  IN OUT PVSCSI_DEV *Dev
+  )
+{
+  // Currently nothing to do here
+}
+
 //
 // Driver Binding
 //
@@ -89,7 +228,42 @@ PvScsiDriverBindingStart (
   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
   )
 {
-  return EFI_UNSUPPORTED;
+  PVSCSI_DEV *Dev;
+  EFI_STATUS Status;
+
+  Dev = (PVSCSI_DEV *) AllocateZeroPool (sizeof (*Dev));
+  if (Dev == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = PvScsiInit (Dev);
+  if (EFI_ERROR (Status)) {
+    goto FreePvScsi;
+  }
+
+  //
+  // Setup complete, attempt to export the driver instance's PassThru interface
+  //
+  Dev->Signature = PVSCSI_SIG;
+  Status = gBS->InstallProtocolInterface (
+                  &ControllerHandle,
+                  &gEfiExtScsiPassThruProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &Dev->PassThru
+                  );
+  if (EFI_ERROR (Status)) {
+    goto UninitDev;
+  }
+
+  return EFI_SUCCESS;
+
+UninitDev:
+  PvScsiUninit (Dev);
+
+FreePvScsi:
+  FreePool (Dev);
+
+  return Status;
 }
 
 STATIC
@@ -102,7 +276,38 @@ PvScsiDriverBindingStop (
   IN EFI_HANDLE                  *ChildHandleBuffer
   )
 {
-  return EFI_UNSUPPORTED;
+  EFI_STATUS                      Status;
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
+  PVSCSI_DEV                      *Dev;
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiExtScsiPassThruProtocolGuid,
+                  (VOID **)&PassThru,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Dev = PVSCSI_FROM_PASS_THRU (PassThru);
+
+  Status = gBS->UninstallProtocolInterface (
+                  ControllerHandle,
+                  &gEfiExtScsiPassThruProtocolGuid,
+                  &Dev->PassThru
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  PvScsiUninit (Dev);
+
+  FreePool (Dev);
+
+  return EFI_SUCCESS;
 }
 
 STATIC
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
new file mode 100644
index 000000000000..3940b4c20019
--- /dev/null
+++ b/OvmfPkg/PvScsiDxe/PvScsi.h
@@ -0,0 +1,29 @@
+/** @file
+
+  Internal definitions for the PVSCSI driver, which produces Extended SCSI
+  Pass Thru Protocol instances for pvscsi devices.
+
+  Copyright (C) 2020, Oracle and/or its affiliates.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PVSCSI_DXE_H_
+#define __PVSCSI_DXE_H_
+
+#include <Library/DebugLib.h>
+#include <Protocol/ScsiPassThruExt.h>
+
+#define PVSCSI_SIG SIGNATURE_32 ('P', 'S', 'C', 'S')
+
+typedef struct {
+  UINT32                          Signature;
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
+  EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
+} PVSCSI_DEV;
+
+#define PVSCSI_FROM_PASS_THRU(PassThruPointer) \
+  CR (PassThruPointer, PVSCSI_DEV, PassThru, PVSCSI_SIG)
+
+#endif // __PVSCSI_DXE_H_
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
index c1f0663832ed..3a8b07872ba3 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.inf
+++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
@@ -25,9 +25,12 @@
   OvmfPkg/OvmfPkg.dec
 
 [LibraryClasses]
+  DebugLib
+  MemoryAllocationLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiLib
 
 [Protocols]
-  gEfiPciIoProtocolGuid        ## TO_START
+  gEfiPciIoProtocolGuid             ## TO_START
+  gEfiExtScsiPassThruProtocolGuid   ## BY_START
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 06/17] OvmfPkg/PvScsiDxe: Report the number of targets and LUNs
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (4 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 05/17] OvmfPkg/PvScsiDxe: Install stubbed EXT_SCSI_PASS_THRU Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 13:12   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 07/17] OvmfPkg/PvScsiDxe: Translate Target & LUN to/from DevicePath Liran Alon
                   ` (11 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

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: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/OvmfPkg.dec          |   9 +++
 OvmfPkg/PvScsiDxe/PvScsi.c   | 122 ++++++++++++++++++++++++++++++++++-
 OvmfPkg/PvScsiDxe/PvScsi.h   |   2 +
 OvmfPkg/PvScsiDxe/PvScsi.inf |   5 ++
 4 files changed, 136 insertions(+), 2 deletions(-)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 4c5b6511cb97..76ce507e8bd0 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -121,6 +121,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 blow constants
+  # are used so that scanning the number of devices given by their product
+  # is still acceptably fast.
+  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit|64|UINT8|0x40
+  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit|0|UINT8|0x41
+
   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 46b430a34a57..76bb361c7c94 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -11,6 +11,7 @@
 
 #include <IndustryStandard/Pci.h>
 #include <IndustryStandard/PvScsi.h>
+#include <Library/BaseMemoryLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
@@ -24,6 +25,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
 //
@@ -51,7 +76,54 @@ PvScsiGetNextTargetLun (
   IN OUT UINT64                                     *Lun
   )
 {
-  return EFI_UNSUPPORTED;
+  UINT8      *TargetPtr;
+  UINT8      LastTarget;
+  PVSCSI_DEV *Dev;
+
+  if (Target == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // The TargetPointer 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
@@ -110,7 +182,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
@@ -119,6 +231,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 3940b4c20019..dd3e0c68e6da 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/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
index 3a8b07872ba3..96bd4e4a9a8b 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.inf
+++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
@@ -25,6 +25,7 @@
   OvmfPkg/OvmfPkg.dec
 
 [LibraryClasses]
+  BaseMemoryLib
   DebugLib
   MemoryAllocationLib
   UefiBootServicesTableLib
@@ -34,3 +35,7 @@
 [Protocols]
   gEfiPciIoProtocolGuid             ## TO_START
   gEfiExtScsiPassThruProtocolGuid   ## BY_START
+
+[Pcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit    ## CONSUMES
+  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit       ## CONSUMES
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 07/17] OvmfPkg/PvScsiDxe: Translate Target & LUN to/from DevicePath
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (5 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 06/17] OvmfPkg/PvScsiDxe: Report the number of targets and LUNs Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 13:36   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 08/17] OvmfPkg/PvScsiDxe: Open PciIo protocol for later use Liran Alon
                   ` (10 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

Implement EXT_SCSI_PASS_THRU.BuildDevicePath() and
EXT_SCSI_PASS_THRU.GetTargetLun().

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c | 60 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 58 insertions(+), 2 deletions(-)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index 76bb361c7c94..f613870e80f2 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -136,7 +136,38 @@ PvScsiBuildDevicePath (
   IN OUT EFI_DEVICE_PATH_PROTOCOL                   **DevicePath
   )
 {
-  return EFI_UNSUPPORTED;
+  UINT8             TargetValue;
+  PVSCSI_DEV        *Dev;
+  SCSI_DEVICE_PATH  *ScsiDevicePath;
+
+  if (DevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // We only use first byte of target identifer
+  //
+  TargetValue = *Target;
+
+  Dev = PVSCSI_FROM_PASS_THRU (This);
+  if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun) {
+    return EFI_NOT_FOUND;
+  }
+
+  ScsiDevicePath = AllocatePool (sizeof (*ScsiDevicePath));
+  if (ScsiDevicePath == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ScsiDevicePath->Header.Type      = MESSAGING_DEVICE_PATH;
+  ScsiDevicePath->Header.SubType   = MSG_SCSI_DP;
+  ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);
+  ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);
+  ScsiDevicePath->Pun              = TargetValue;
+  ScsiDevicePath->Lun              = (UINT16)Lun;
+
+  *DevicePath = &ScsiDevicePath->Header;
+  return EFI_SUCCESS;
 }
 
 STATIC
@@ -149,7 +180,32 @@ PvScsiGetTargetLun (
   OUT UINT64                                        *Lun
   )
 {
-  return EFI_UNSUPPORTED;
+  SCSI_DEVICE_PATH *ScsiDevicePath;
+  PVSCSI_DEV       *Dev;
+
+  if (DevicePath == NULL || Target == NULL || *Target == NULL || Lun == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (DevicePath->Type    != MESSAGING_DEVICE_PATH ||
+      DevicePath->SubType != MSG_SCSI_DP) {
+    return EFI_UNSUPPORTED;
+  }
+
+  ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
+  Dev = PVSCSI_FROM_PASS_THRU (This);
+  if (ScsiDevicePath->Pun > Dev->MaxTarget ||
+      ScsiDevicePath->Lun > Dev->MaxLun) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // We only use first byte of target identifer
+  //
+  **Target = (UINT8)ScsiDevicePath->Pun;
+  *Lun = ScsiDevicePath->Lun;
+
+  return EFI_SUCCESS;
 }
 
 STATIC
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 08/17] OvmfPkg/PvScsiDxe: Open PciIo protocol for later use
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (6 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 07/17] OvmfPkg/PvScsiDxe: Translate Target & LUN to/from DevicePath Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 13:47   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 09/17] OvmfPkg/PvScsiDxe: Backup/Restore PCI attributes on Init/UnInit Liran Alon
                   ` (9 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

This will give us an exclusive access to the PciIo of this device
after it was started and until is will be stopped.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c | 29 ++++++++++++++++++++++++++++-
 OvmfPkg/PvScsiDxe/PvScsi.h |  1 +
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index f613870e80f2..b6a83d73cead 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -410,11 +410,23 @@ PvScsiDriverBindingStart (
     return EFI_OUT_OF_RESOURCES;
   }
 
-  Status = PvScsiInit (Dev);
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **)&Dev->PciIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
   if (EFI_ERROR (Status)) {
     goto FreePvScsi;
   }
 
+  Status = PvScsiInit (Dev);
+  if (EFI_ERROR (Status)) {
+    goto ClosePciIo;
+  }
+
   //
   // Setup complete, attempt to export the driver instance's PassThru interface
   //
@@ -434,6 +446,14 @@ PvScsiDriverBindingStart (
 UninitDev:
   PvScsiUninit (Dev);
 
+ClosePciIo:
+  gBS->CloseProtocol (
+         ControllerHandle,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         ControllerHandle
+         );
+
 FreePvScsi:
   FreePool (Dev);
 
@@ -479,6 +499,13 @@ PvScsiDriverBindingStop (
 
   PvScsiUninit (Dev);
 
+  gBS->CloseProtocol (
+         ControllerHandle,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         ControllerHandle
+         );
+
   FreePool (Dev);
 
   return EFI_SUCCESS;
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
index dd3e0c68e6da..e1e5ae18ebf2 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.h
+++ b/OvmfPkg/PvScsiDxe/PvScsi.h
@@ -19,6 +19,7 @@
 
 typedef struct {
   UINT32                          Signature;
+  EFI_PCI_IO_PROTOCOL             *PciIo;
   UINT8                           MaxTarget;
   UINT8                           MaxLun;
   EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 09/17] OvmfPkg/PvScsiDxe: Backup/Restore PCI attributes on Init/UnInit
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (7 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 08/17] OvmfPkg/PvScsiDxe: Open PciIo protocol for later use Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 15:14   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 10/17] OvmfPkg/PvScsiDxe: Enable IOSpace & Bus-Mastering in PCI attributes Liran Alon
                   ` (8 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

This commit doesn't change semantics.
It is done as a preparation for future commits which will modify
PCI attributes.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c | 53 +++++++++++++++++++++++++++++++++++++-
 OvmfPkg/PvScsiDxe/PvScsi.h |  1 +
 2 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index b6a83d73cead..92e0f4a98965 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -281,18 +281,59 @@ PvScsiGetNextTarget (
   return EFI_NOT_FOUND;
 }
 
+STATIC
+EFI_STATUS
+PvScsiSetPCIAttributes (
+  IN OUT PVSCSI_DEV *Dev
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // Set saved original PCI attirubtes to invalid value
+  // such that cleanup logic could determine if it should restore
+  // PCI attributes or not
+  //
+  Dev->OriginalPciAttributes = (UINT64)(-1);
+
+  //
+  // Backup original PCI Attributes
+  //
+  Status = Dev->PciIo->Attributes (
+                         Dev->PciIo,
+                         EfiPciIoAttributeOperationGet,
+                         0,
+                         &Dev->OriginalPciAttributes
+                         );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
 STATIC
 EFI_STATUS
 PvScsiInit (
   IN OUT PVSCSI_DEV *Dev
   )
 {
+  EFI_STATUS Status;
+
   //
   // Init configuration
   //
   Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
   Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
 
+  //
+  // Set PCI Attributes
+  //
+  Status = PvScsiSetPCIAttributes (Dev);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
   //
   // Populate the exported interface's attributes
   //
@@ -331,7 +372,17 @@ PvScsiUninit (
   IN OUT PVSCSI_DEV *Dev
   )
 {
-  // Currently nothing to do here
+  //
+  // Restore PCI Attributes
+  //
+  if (Dev->OriginalPciAttributes != (UINT64)(-1)) {
+    Dev->PciIo->Attributes (
+                  Dev->PciIo,
+                  EfiPciIoAttributeOperationSet,
+                  Dev->OriginalPciAttributes,
+                  NULL
+                  );
+  }
 }
 
 //
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
index e1e5ae18ebf2..5f611dbbc98c 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.h
+++ b/OvmfPkg/PvScsiDxe/PvScsi.h
@@ -20,6 +20,7 @@
 typedef struct {
   UINT32                          Signature;
   EFI_PCI_IO_PROTOCOL             *PciIo;
+  UINT64                          OriginalPciAttributes;
   UINT8                           MaxTarget;
   UINT8                           MaxLun;
   EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 10/17] OvmfPkg/PvScsiDxe: Enable IOSpace & Bus-Mastering in PCI attributes
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (8 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 09/17] OvmfPkg/PvScsiDxe: Backup/Restore PCI attributes on Init/UnInit Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 15:22   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 11/17] OvmfPkg/PvScsiDxe: Define device interface structures and constants Liran Alon
                   ` (7 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

Enable IOSpace & Bus-Mastering PCI attributes when device is started.
Note that original PCI attributes is restored when device is stopped.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index 92e0f4a98965..ff6b50b7020f 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -309,6 +309,20 @@ PvScsiSetPCIAttributes (
     return Status;
   }
 
+  //
+  // Enable IOSpace & Bus-Mastering
+  //
+  Status = Dev->PciIo->Attributes (
+                         Dev->PciIo,
+                         EfiPciIoAttributeOperationEnable,
+                         (EFI_PCI_IO_ATTRIBUTE_MEMORY |
+                          EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
+                         NULL
+                         );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
   return EFI_SUCCESS;
 }
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 11/17] OvmfPkg/PvScsiDxe: Define device interface structures and constants
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (9 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 10/17] OvmfPkg/PvScsiDxe: Enable IOSpace & Bus-Mastering in PCI attributes Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 15:35   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init Liran Alon
                   ` (6 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

These definitions will be used by the following commits to complete the
implementation of PVSCSI device driver.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/Include/IndustryStandard/PvScsi.h | 162 ++++++++++++++++++++++
 1 file changed, 162 insertions(+)

diff --git a/OvmfPkg/Include/IndustryStandard/PvScsi.h b/OvmfPkg/Include/IndustryStandard/PvScsi.h
index 004c0af84989..7bb6e664dfcd 100644
--- a/OvmfPkg/Include/IndustryStandard/PvScsi.h
+++ b/OvmfPkg/Include/IndustryStandard/PvScsi.h
@@ -18,4 +18,166 @@
 #define PCI_VENDOR_ID_VMWARE            (0x15ad)
 #define PCI_DEVICE_ID_VMWARE_PVSCSI     (0x07c0)
 
+//
+// CDB (Command Descriptor Block) with size above this constant
+// should be considered out-of-band
+//
+#define PVSCSI_CDB_MAX_SIZE         (16)
+
+enum PVSCSI_BAR0_OFFSETS {
+  PVSCSI_REG_OFFSET_COMMAND        =    0x0,
+  PVSCSI_REG_OFFSET_COMMAND_DATA   =    0x4,
+  PVSCSI_REG_OFFSET_COMMAND_STATUS =    0x8,
+  PVSCSI_REG_OFFSET_LAST_STS_0     =  0x100,
+  PVSCSI_REG_OFFSET_LAST_STS_1     =  0x104,
+  PVSCSI_REG_OFFSET_LAST_STS_2     =  0x108,
+  PVSCSI_REG_OFFSET_LAST_STS_3     =  0x10c,
+  PVSCSI_REG_OFFSET_INTR_STATUS    = 0x100c,
+  PVSCSI_REG_OFFSET_INTR_MASK      = 0x2010,
+  PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014,
+  PVSCSI_REG_OFFSET_DEBUG          = 0x3018,
+  PVSCSI_REG_OFFSET_KICK_RW_IO     = 0x4018,
+};
+
+//
+// Define Interrupt-Status register flags
+//
+#define PVSCSI_INTR_CMPL_0      (1 << 0)
+#define PVSCSI_INTR_CMPL_1      (1 << 1)
+#define PVSCSI_INTR_CMPL_MASK   (PVSCSI_INTR_CMPL_0 | PVSCSI_INTR_CMPL_1)
+
+enum PVSCSI_COMMANDS {
+  PVSCSI_CMD_FIRST             = 0,
+  PVSCSI_CMD_ADAPTER_RESET     = 1,
+  PVSCSI_CMD_ISSUE_SCSI        = 2,
+  PVSCSI_CMD_SETUP_RINGS       = 3,
+  PVSCSI_CMD_RESET_BUS         = 4,
+  PVSCSI_CMD_RESET_DEVICE      = 5,
+  PVSCSI_CMD_ABORT_CMD         = 6,
+  PVSCSI_CMD_CONFIG            = 7,
+  PVSCSI_CMD_SETUP_MSG_RING    = 8,
+  PVSCSI_CMD_DEVICE_UNPLUG     = 9,
+  PVSCSI_CMD_LAST              = 10
+};
+
+#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES    (32)
+
+#pragma pack (1)
+typedef struct {
+  UINT32 ReqRingNumPages;
+  UINT32 CmpRingNumPages;
+  UINT64 RingsStatePPN;
+  UINT64 ReqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
+  UINT64 CmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
+} PVSCSI_CMD_DESC_SETUP_RINGS;
+#pragma pack ()
+
+#define PVSCSI_MAX_CMD_DATA_WORDS   \
+  (sizeof (PVSCSI_CMD_DESC_SETUP_RINGS) / sizeof (UINT32))
+
+#pragma pack (1)
+typedef struct {
+  UINT32 ReqProdIdx;
+  UINT32 ReqConsIdx;
+  UINT32 ReqNumEntriesLog2;
+
+  UINT32 CmpProdIdx;
+  UINT32 CmpConsIdx;
+  UINT32 CmpNumEntriesLog2;
+
+  UINT8  Pad[104];
+
+  UINT32 MsgProdIdx;
+  UINT32 MsgConsIdx;
+  UINT32 MsgNumEntriesLog2;
+} PVSCSI_RINGS_STATE;
+#pragma pack ()
+
+//
+// Define PVSCSI request descriptor tags
+//
+#define PVSCSI_SIMPLE_QUEUE_TAG            (0x20)
+
+//
+// Define PVSCSI request descriptor flags
+//
+#define PVSCSI_FLAG_CMD_WITH_SG_LIST       (1 << 0)
+#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB    (1 << 1)
+#define PVSCSI_FLAG_CMD_DIR_NONE           (1 << 2)
+#define PVSCSI_FLAG_CMD_DIR_TOHOST         (1 << 3)
+#define PVSCSI_FLAG_CMD_DIR_TODEVICE       (1 << 4)
+
+#pragma pack (1)
+typedef struct {
+  UINT64 Context;
+  UINT64 DataAddr;
+  UINT64 DataLen;
+  UINT64 SenseAddr;
+  UINT32 SenseLen;
+  UINT32 Flags;
+  UINT8  Cdb[16];
+  UINT8  CdbLen;
+  UINT8  Lun[8];
+  UINT8  Tag;
+  UINT8  Bus;
+  UINT8  Target;
+  UINT8  vCPUHint;
+  UINT8  Unused[59];
+} PVSCSI_RING_REQ_DESC;
+#pragma pack ()
+
+//
+// Host adapter status/error codes
+//
+enum PVSCSI_HOST_BUS_ADAPTER_STATUS {
+   BTSTAT_SUCCESS       = 0x00,  // CCB complete normally with no errors
+   BTSTAT_LINKED_COMMAND_COMPLETED           = 0x0a,
+   BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b,
+   BTSTAT_DATA_UNDERRUN = 0x0c,
+   BTSTAT_SELTIMEO      = 0x11,  // SCSI selection timeout
+   BTSTAT_DATARUN       = 0x12,  // Data overrun/underrun
+   BTSTAT_BUSFREE       = 0x13,  // Unexpected bus free
+   BTSTAT_INVPHASE      = 0x14,  //
+                                 // Invalid bus phase or sequence requested by
+                                 // target
+                                 //
+   BTSTAT_LUNMISMATCH   = 0x17,  // Linked CCB has different LUN from first CCB
+   BTSTAT_SENSFAILED    = 0x1b,  // Auto request sense failed
+   BTSTAT_TAGREJECT     = 0x1c,  //
+                                 // SCSI II tagged queueing message rejected by
+                                 // target
+                                 //
+   BTSTAT_BADMSG        = 0x1d,  //
+                                 // Unsupported message received by the host
+                                 // adapter
+                                 //
+   BTSTAT_HAHARDWARE    = 0x20,  // Host adapter hardware failed
+   BTSTAT_NORESPONSE    = 0x21,  //
+                                 // Target did not respond to SCSI ATN sent a
+                                 // SCSI RST
+                                 //
+   BTSTAT_SENTRST       = 0x22,  // Host adapter asserted a SCSI RST
+   BTSTAT_RECVRST       = 0x23,  // Other SCSI devices asserted a SCSI RST
+   BTSTAT_DISCONNECT    = 0x24,  //
+                                 // Target device reconnected improperly
+                                 // (w/o tag)
+                                 //
+   BTSTAT_BUSRESET      = 0x25,  // Host adapter issued BUS device reset
+   BTSTAT_ABORTQUEUE    = 0x26,  // Abort queue generated
+   BTSTAT_HASOFTWARE    = 0x27,  // Host adapter software error
+   BTSTAT_HATIMEOUT     = 0x30,  // Host adapter hardware timeout error
+   BTSTAT_SCSIPARITY    = 0x34,  // SCSI parity error detected
+};
+
+#pragma pack (1)
+typedef struct {
+  UINT64 Context;
+  UINT64 DataLen;
+  UINT32 SenseLen;
+  UINT16 HostStatus;
+  UINT16 ScsiStatus;
+  UINT32 Pad[2];
+} PVSCSI_RING_CMP_DESC;
+#pragma pack ()
+
 #endif // __PVSCSI_H_
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (10 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 11/17] OvmfPkg/PvScsiDxe: Define device interface structures and constants Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 16:00   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 13/17] OvmfPkg/PvScsiDxe: Setup requests and completions rings Liran Alon
                   ` (5 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

The following commits will complete the implementation of
device initialization.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c | 77 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index ff6b50b7020f..fb2407d2adb2 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -29,6 +29,76 @@
 // Ext SCSI Pass Thru utilities
 //
 
+
+//
+// Writes a 32-bit value into BAR0 using MMIO
+//
+STATIC
+EFI_STATUS
+PvScsiMmioWrite32 (
+  IN CONST PVSCSI_DEV   *Dev,
+  IN UINT64             Offset,
+  IN UINT32             Value
+  )
+{
+  return Dev->PciIo->Mem.Write(
+                           Dev->PciIo,
+                           EfiPciIoWidthUint32,
+                           0,   // BarIndex
+                           Offset,
+                           1,   // Count
+                           &Value
+                           );
+}
+
+//
+// Send PVSCSI command to device
+//
+STATIC
+EFI_STATUS
+PvScsiWriteCmdDesc (
+  IN CONST PVSCSI_DEV   *Dev,
+  IN UINT32             Cmd,
+  IN VOID               *Desc,
+  IN UINTN              Length
+  )
+{
+  EFI_STATUS Status;
+  UINTN      LengthInWords;
+  UINT8      *WordPtr;
+  UINT8      *DescEndPtr;
+  UINT32     Word;
+
+  LengthInWords = Length / sizeof (UINT32);
+
+  if (LengthInWords > PVSCSI_MAX_CMD_DATA_WORDS) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_COMMAND, Cmd);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  WordPtr = Desc;
+  DescEndPtr = WordPtr + Length;
+
+  while (WordPtr != DescEndPtr) {
+    //
+    // CopyMem() is used to avoid strict-aliasing issues
+    //
+    CopyMem (&Word, WordPtr, sizeof (UINT32));
+
+    Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_COMMAND_DATA, Word);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    WordPtr += sizeof (UINT32);
+  }
+
+  return EFI_SUCCESS;
+}
 //
 // Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
 // EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
@@ -348,6 +418,13 @@ PvScsiInit (
     return Status;
   }
 
+  //
+  // Reset adapter
+  //
+  Status = PvScsiWriteCmdDesc (Dev, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
   //
   // Populate the exported interface's attributes
   //
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 13/17] OvmfPkg/PvScsiDxe: Setup requests and completions rings
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (11 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 16:11   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 14/17] OvmfPkg/PvScsiDxe: Introduce DMA communication buffer Liran Alon
                   ` (4 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

These rings are shared memory buffers between host and device in which
a cyclic buffer is managed to send request descriptors from host to
device and receive completion descriptors from device to host.

Note that because device may be constrained by IOMMU or guest may be run
under AMD SEV, we make sure to map these rings to device by using
PciIo->Map().

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c | 235 +++++++++++++++++++++++++++++++++++++
 OvmfPkg/PvScsiDxe/PvScsi.h |  17 +++
 2 files changed, 252 insertions(+)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index fb2407d2adb2..c3f5d38f3d30 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -16,6 +16,7 @@
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
 #include <Protocol/PciIo.h>
+#include <Protocol/PciRootBridgeIo.h>
 
 #include "PvScsi.h"
 
@@ -396,6 +397,209 @@ PvScsiSetPCIAttributes (
   return EFI_SUCCESS;
 }
 
+STATIC
+EFI_STATUS
+PvScsiAllocatePages (
+  IN PVSCSI_DEV     *Dev,
+  IN UINTN          Pages,
+  IN OUT VOID       **HostAddress
+  )
+{
+  return Dev->PciIo->AllocateBuffer (
+                       Dev->PciIo,
+                       AllocateAnyPages,
+                       EfiBootServicesData,
+                       Pages,
+                       HostAddress,
+                       EFI_PCI_ATTRIBUTE_MEMORY_CACHED
+                       );
+}
+
+STATIC
+VOID
+PvScsiFreePages (
+  IN PVSCSI_DEV     *Dev,
+  IN UINTN          Pages,
+  IN VOID           *HostAddress
+  )
+{
+  Dev->PciIo->FreeBuffer (
+                Dev->PciIo,
+                Pages,
+                HostAddress
+                );
+}
+
+STATIC
+EFI_STATUS
+PvScsiMapBuffer (
+  IN PVSCSI_DEV                     *Dev,
+  IN EFI_PCI_IO_PROTOCOL_OPERATION  PciIoOperation,
+  IN VOID                           *HostAddress,
+  IN UINTN                          NumberOfBytes,
+  OUT PVSCSI_DMA_DESC               *DmaDesc
+  )
+{
+  EFI_STATUS Status;
+  UINTN      BytesMapped;
+
+  BytesMapped = NumberOfBytes;
+  Status = Dev->PciIo->Map (
+                         Dev->PciIo,
+                         PciIoOperation,
+                         HostAddress,
+                         &BytesMapped,
+                         &DmaDesc->DeviceAddress,
+                         &DmaDesc->Mapping
+                         );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (BytesMapped != NumberOfBytes) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Unmap;
+  }
+
+  return EFI_SUCCESS;
+
+Unmap:
+  Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
+  DmaDesc->Mapping = NULL;
+
+  return Status;
+}
+
+STATIC
+VOID
+PvScsiUnmapBuffer (
+  IN PVSCSI_DEV                 *Dev,
+  IN OUT PVSCSI_DMA_DESC        *DmaDesc)
+{
+  Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
+}
+
+STATIC
+EFI_STATUS
+PvScsiAllocateSharedPages (
+  IN PVSCSI_DEV                     *Dev,
+  IN UINTN                          Pages,
+  IN EFI_PCI_IO_PROTOCOL_OPERATION  PciIoOperation,
+  OUT VOID                          **HostAddress,
+  OUT PVSCSI_DMA_DESC               *DmaDesc
+  )
+{
+  EFI_STATUS Status;
+
+  *HostAddress = NULL;
+  DmaDesc->Mapping = NULL;
+
+  Status = PvScsiAllocatePages (Dev, Pages, HostAddress);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = PvScsiMapBuffer (
+             Dev,
+             PciIoOperation,
+             *HostAddress,
+             Pages * EFI_PAGE_SIZE,
+             DmaDesc
+             );
+  if (EFI_ERROR (Status)) {
+    goto FreePages;
+  }
+
+  return EFI_SUCCESS;
+
+FreePages:
+  PvScsiFreePages (Dev, Pages, *HostAddress);
+  *HostAddress = NULL;
+
+  return Status;
+}
+
+STATIC
+VOID
+PvScsiFreeSharedPages (
+  IN PVSCSI_DEV                     *Dev,
+  IN UINTN                          Pages,
+  IN OUT VOID                       **HostAddress,
+  IN OUT PVSCSI_DMA_DESC            *DmaDesc
+  )
+{
+  if (*HostAddress) {
+      if (DmaDesc->Mapping) {
+        PvScsiUnmapBuffer (Dev, DmaDesc);
+        DmaDesc->Mapping = NULL;
+      }
+
+      PvScsiFreePages (Dev, Pages, *HostAddress);
+      *HostAddress = NULL;
+  }
+}
+
+STATIC
+EFI_STATUS
+PvScsiInitRings (
+  IN OUT PVSCSI_DEV *Dev
+  )
+{
+  EFI_STATUS                  Status;
+  PVSCSI_CMD_DESC_SETUP_RINGS Cmd;
+
+  Status = PvScsiAllocateSharedPages (
+             Dev,
+             1,
+             EfiPciIoOperationBusMasterCommonBuffer,
+             (VOID **)&Dev->RingDesc.RingState,
+             &Dev->RingDesc.RingStateDmaDesc
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  ZeroMem (Dev->RingDesc.RingState, EFI_PAGE_SIZE);
+
+  Status = PvScsiAllocateSharedPages (
+             Dev,
+             1,
+             EfiPciIoOperationBusMasterCommonBuffer,
+             (VOID **)&Dev->RingDesc.RingReqs,
+             &Dev->RingDesc.RingReqsDmaDesc
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  ZeroMem (Dev->RingDesc.RingReqs, EFI_PAGE_SIZE);
+
+  Status = PvScsiAllocateSharedPages (
+             Dev,
+             1,
+             EfiPciIoOperationBusMasterCommonBuffer,
+             (VOID **)&Dev->RingDesc.RingCmps,
+             &Dev->RingDesc.RingCmpsDmaDesc
+             );
+  if (EFI_ERROR (Status)) {
+      return Status;
+  }
+  ZeroMem (Dev->RingDesc.RingCmps, EFI_PAGE_SIZE);
+
+  ZeroMem (&Cmd, sizeof Cmd);
+  Cmd.ReqRingNumPages = 1;
+  Cmd.CmpRingNumPages = 1;
+  Cmd.RingsStatePPN =
+        ((UINT64) Dev->RingDesc.RingStateDmaDesc.DeviceAddress) >>
+        EFI_PAGE_SHIFT;
+  Cmd.ReqRingPPNs[0] =
+        ((UINT64) Dev->RingDesc.RingReqsDmaDesc.DeviceAddress) >>
+        EFI_PAGE_SHIFT;
+  Cmd.CmpRingPPNs[0] =
+        ((UINT64) Dev->RingDesc.RingCmpsDmaDesc.DeviceAddress) >>
+        EFI_PAGE_SHIFT;
+
+  return PvScsiWriteCmdDesc(Dev, PVSCSI_CMD_SETUP_RINGS, &Cmd, sizeof Cmd);
+}
+
 STATIC
 EFI_STATUS
 PvScsiInit (
@@ -425,6 +629,15 @@ PvScsiInit (
   if (EFI_ERROR (Status)) {
     return Status;
   }
+
+  //
+  // Init PVSCSI rings
+  //
+  Status = PvScsiInitRings (Dev);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
   //
   // Populate the exported interface's attributes
   //
@@ -463,6 +676,28 @@ PvScsiUninit (
   IN OUT PVSCSI_DEV *Dev
   )
 {
+  //
+  // Free PVSCSI rings
+  //
+  PvScsiFreeSharedPages (
+    Dev,
+    1,
+    (VOID **)&Dev->RingDesc.RingCmps,
+    &Dev->RingDesc.RingCmpsDmaDesc
+    );
+  PvScsiFreeSharedPages (
+    Dev,
+    1,
+    (VOID **)&Dev->RingDesc.RingReqs,
+    &Dev->RingDesc.RingReqsDmaDesc
+    );
+  PvScsiFreeSharedPages (
+    Dev,
+    1,
+    (VOID **)&Dev->RingDesc.RingState,
+    &Dev->RingDesc.RingStateDmaDesc
+    );
+
   //
   // Restore PCI Attributes
   //
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
index 5f611dbbc98c..6d23b6e1eccf 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.h
+++ b/OvmfPkg/PvScsiDxe/PvScsi.h
@@ -15,12 +15,29 @@
 #include <Library/DebugLib.h>
 #include <Protocol/ScsiPassThruExt.h>
 
+typedef struct {
+  EFI_PHYSICAL_ADDRESS DeviceAddress;
+  VOID                 *Mapping;
+} PVSCSI_DMA_DESC;
+
+typedef struct {
+  PVSCSI_RINGS_STATE   *RingState;
+  PVSCSI_DMA_DESC      RingStateDmaDesc;
+
+  PVSCSI_RING_REQ_DESC *RingReqs;
+  PVSCSI_DMA_DESC      RingReqsDmaDesc;
+
+  PVSCSI_RING_CMP_DESC *RingCmps;
+  PVSCSI_DMA_DESC      RingCmpsDmaDesc;
+} PVSCSI_RING_DESC;
+
 #define PVSCSI_SIG SIGNATURE_32 ('P', 'S', 'C', 'S')
 
 typedef struct {
   UINT32                          Signature;
   EFI_PCI_IO_PROTOCOL             *PciIo;
   UINT64                          OriginalPciAttributes;
+  PVSCSI_RING_DESC                RingDesc;
   UINT8                           MaxTarget;
   UINT8                           MaxLun;
   EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 14/17] OvmfPkg/PvScsiDxe: Introduce DMA communication buffer
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (12 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 13/17] OvmfPkg/PvScsiDxe: Setup requests and completions rings Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 16:13   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 15/17] OvmfPkg/PvScsiDxe: Support sending SCSI request and receive response Liran Alon
                   ` (3 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

In case device is constrained by IOMMU or guest is running under AMD SEV,
input/output buffers provided to device (DataBuffer and SenseData) needs
to be explicitly mapped to device by PciIo->Map().

To avoid the overhead of mapping/unmapping the DataBuffer and SenseData
to the device for every SCSI requst (And to simplify code), introduce a
single DMA communication buffer that will be mapped to device on
initialization. When a SCSI request needs to be sent to device, the
DataBuffer and SenseData will be copied from/to the DMA communication
buffer as required. This will be done by the following commits.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c | 24 ++++++++++++++++++++++++
 OvmfPkg/PvScsiDxe/PvScsi.h | 10 ++++++++++
 2 files changed, 34 insertions(+)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index c3f5d38f3d30..e48929bf044c 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -638,6 +638,20 @@ PvScsiInit (
     return Status;
   }
 
+  //
+  // Allocate DMA communication buffer
+  //
+  Status = PvScsiAllocateSharedPages (
+             Dev,
+             EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
+             EfiPciIoOperationBusMasterCommonBuffer,
+             (VOID **)&Dev->DmaBuf,
+             &Dev->DmaBufDmaDesc
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
   //
   // Populate the exported interface's attributes
   //
@@ -676,6 +690,16 @@ PvScsiUninit (
   IN OUT PVSCSI_DEV *Dev
   )
 {
+  //
+  // Free DMA communication buffer
+  //
+  PvScsiFreeSharedPages (
+    Dev,
+    EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
+    (VOID **)&Dev->DmaBuf,
+    &Dev->DmaBufDmaDesc
+    );
+
   //
   // Free PVSCSI rings
   //
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
index 6d23b6e1eccf..7f91d70fec79 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.h
+++ b/OvmfPkg/PvScsiDxe/PvScsi.h
@@ -31,6 +31,11 @@ typedef struct {
   PVSCSI_DMA_DESC      RingCmpsDmaDesc;
 } PVSCSI_RING_DESC;
 
+typedef struct {
+  UINT8     SenseData[MAX_UINT8];
+  UINT8     Data[0x2000];
+} PVSCSI_DMA_BUFFER;
+
 #define PVSCSI_SIG SIGNATURE_32 ('P', 'S', 'C', 'S')
 
 typedef struct {
@@ -38,6 +43,8 @@ typedef struct {
   EFI_PCI_IO_PROTOCOL             *PciIo;
   UINT64                          OriginalPciAttributes;
   PVSCSI_RING_DESC                RingDesc;
+  PVSCSI_DMA_BUFFER               *DmaBuf;
+  PVSCSI_DMA_DESC                 DmaBufDmaDesc;
   UINT8                           MaxTarget;
   UINT8                           MaxLun;
   EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
@@ -47,4 +54,7 @@ typedef struct {
 #define PVSCSI_FROM_PASS_THRU(PassThruPointer) \
   CR (PassThruPointer, PVSCSI_DEV, PassThru, PVSCSI_SIG)
 
+#define PVSCSI_DMA_BUF_DEV_ADDR(Dev, MemberName) \
+  (Dev->DmaBufDmaDesc.DeviceAddress + OFFSET_OF(PVSCSI_DMA_BUFFER, MemberName))
+
 #endif // __PVSCSI_DXE_H_
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 15/17] OvmfPkg/PvScsiDxe: Support sending SCSI request and receive response
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (13 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 14/17] OvmfPkg/PvScsiDxe: Introduce DMA communication buffer Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 16:43   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 16/17] OvmfPkg/PvScsiDxe: Reset device on ExitBootServices() Liran Alon
                   ` (2 subsequent siblings)
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

Implement EXT_SCSI_PASS_THRU.PassThru().

Machines should be able to boot after this commit.
Tested with Ubuntu 16.04 guest.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/OvmfPkg.dec          |   6 +
 OvmfPkg/PvScsiDxe/PvScsi.c   | 423 ++++++++++++++++++++++++++++++++++-
 OvmfPkg/PvScsiDxe/PvScsi.h   |   1 +
 OvmfPkg/PvScsiDxe/PvScsi.inf |   5 +-
 4 files changed, 432 insertions(+), 3 deletions(-)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 76ce507e8bd0..e78c771f53e9 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -130,6 +130,12 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit|64|UINT8|0x40
   gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit|0|UINT8|0x41
 
+  ## After PvScsiDxe sends a SCSI request to the device, it waits for
+  #  the request completion in a polling loop.
+  #  This constant defines how many micro-seconds to wait between each
+  #  polling loop iteration.
+  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiWaitForCmpStallInUsecs|5|UINT32|0x42
+
   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 e48929bf044c..e7d0a23db6ab 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -30,6 +30,26 @@
 // Ext SCSI Pass Thru utilities
 //
 
+//
+// Reads a 32-bit value into BAR0 using MMIO
+//
+STATIC
+EFI_STATUS
+PvScsiMmioRead32 (
+  IN CONST PVSCSI_DEV   *Dev,
+  IN UINT64             Offset,
+  OUT UINT32            *Value
+  )
+{
+  return Dev->PciIo->Mem.Read(
+                           Dev->PciIo,
+                           EfiPciIoWidthUint32,
+                           0,   // BarIndex
+                           Offset,
+                           1,   // Count
+                           Value
+                           );
+}
 
 //
 // Writes a 32-bit value into BAR0 using MMIO
@@ -100,6 +120,343 @@ PvScsiWriteCmdDesc (
 
   return EFI_SUCCESS;
 }
+
+//
+// Returns if PVSCSI request ring is full
+//
+STATIC
+BOOLEAN
+PvScsiIsReqRingFull (
+  IN CONST PVSCSI_DEV   *Dev
+  )
+{
+  PVSCSI_RINGS_STATE *RingsState;
+  UINT64             ReqNumEntries;
+
+  RingsState = Dev->RingDesc.RingState;
+  ReqNumEntries = 1 << RingsState->ReqNumEntriesLog2;
+  return (RingsState->ReqProdIdx - RingsState->CmpConsIdx) >= ReqNumEntries;
+}
+
+//
+// Returns pointer to current request descriptor to produce
+//
+STATIC
+PVSCSI_RING_REQ_DESC *
+PvScsiGetCurrentRequest (
+  IN CONST PVSCSI_DEV   *Dev
+  )
+{
+  PVSCSI_RINGS_STATE *RingState;
+  UINT64             ReqNumEntries;
+
+  RingState = Dev->RingDesc.RingState;
+  ReqNumEntries = 1 << RingState->ReqNumEntriesLog2;
+  return Dev->RingDesc.RingReqs +
+         (RingState->ReqProdIdx & (ReqNumEntries - 1));
+}
+
+//
+// Returns pointer to current completion descriptor to consume
+//
+STATIC
+PVSCSI_RING_CMP_DESC *
+PvScsiGetCurrentResponse (
+  IN CONST PVSCSI_DEV   *Dev
+  )
+{
+  PVSCSI_RINGS_STATE *RingState;
+  UINT64             CmpNumEntries;
+
+  RingState = Dev->RingDesc.RingState;
+  CmpNumEntries = 1 << RingState->CmpNumEntriesLog2;
+  return Dev->RingDesc.RingCmps +
+         (RingState->CmpConsIdx & (CmpNumEntries - 1));
+}
+
+//
+// Wait for device to signal completion of submitted requests
+//
+STATIC
+EFI_STATUS
+PvScsiWaitForRequestCompletion (
+  IN CONST PVSCSI_DEV   *Dev
+  )
+{
+  EFI_STATUS Status;
+  UINT32     IntrStatus;
+
+  //
+  // Note: We don't yet support Timeout according to
+  // EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.Timeout.
+  //
+  // This is consistent with some other Scsi PassThru drivers
+  // such as VirtioScsi.
+  //
+  for (;;) {
+    Status = PvScsiMmioRead32 (Dev, PVSCSI_REG_OFFSET_INTR_STATUS, &IntrStatus);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // PVSCSI_INTR_CMPL_MASK is set if device completed submitted requests
+    //
+    if (IntrStatus & PVSCSI_INTR_CMPL_MASK) {
+        break;
+    }
+
+    gBS->Stall (Dev->WaitForCmpStallInUsecs);
+  }
+
+  //
+  // Acknowledge PVSCSI_INTR_CMPL_MASK in device interrupt-status register
+  //
+  return PvScsiMmioWrite32 (
+           Dev,
+           PVSCSI_REG_OFFSET_INTR_STATUS,
+           PVSCSI_INTR_CMPL_MASK
+           );
+}
+
+//
+// Populate a PVSCSI request descriptor from the Extended SCSI Pass Thru
+// Protocol packet.
+//
+STATIC
+EFI_STATUS
+PopulateRequest (
+  IN CONST PVSCSI_DEV                               *Dev,
+  IN UINT8                                          *Target,
+  IN UINT64                                         Lun,
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+  OUT PVSCSI_RING_REQ_DESC                          *Request
+  )
+{
+  UINT8 TargetValue;
+
+  //
+  // We only use first byte of target identifer
+  //
+  TargetValue = *Target;
+
+  //
+  // Check for unsupported requests
+  //
+  if (
+      // Bidirectional transfer was requested
+      (Packet->InTransferLength > 0 && Packet->OutTransferLength > 0) ||
+      (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
+      // Command Descriptor Block bigger than this constant should be considered
+      // out-of-band. We currently don't support these CDBs.
+      (Packet->CdbLength > PVSCSI_CDB_MAX_SIZE)
+      ) {
+
+    //
+    // This error code doesn't require updates to the Packet output fields
+    //
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check for invalid parameters
+  //
+  if (
+      // Addressed invalid device
+      (TargetValue > Dev->MaxTarget) || (Lun > Dev->MaxLun) ||
+      // Invalid direction (there doesn't seem to be a macro for the "no data
+      // transferred" "direction", eg. for TEST UNIT READY)
+      (Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
+      // Trying to receive, but destination pointer is NULL, or contradicting
+      // transfer direction
+      ((Packet->InTransferLength > 0) &&
+       ((Packet->InDataBuffer == NULL) ||
+        (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE)
+        )
+       ) ||
+
+      //
+      // Trying to send, but source pointer is NULL, or contradicting
+      // transfer direction
+      //
+      ((Packet->OutTransferLength > 0) &&
+       ((Packet->OutDataBuffer == NULL) ||
+        (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ)
+        )
+       )
+      ) {
+
+    //
+    // This error code doesn't require updates to the Packet output fields
+    //
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Check for input/output buffer too large for DMA communication buffer
+  //
+  if (Packet->InTransferLength > sizeof (Dev->DmaBuf->Data)) {
+    Packet->InTransferLength = sizeof (Dev->DmaBuf->Data);
+    return EFI_BAD_BUFFER_SIZE;
+  }
+  if (Packet->OutTransferLength > sizeof (Dev->DmaBuf->Data)) {
+    Packet->OutTransferLength = sizeof (Dev->DmaBuf->Data);
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  //
+  // Encode PVSCSI request
+  //
+  ZeroMem (Request, sizeof (*Request));
+
+  Request->Bus = 0;
+  Request->Target = TargetValue;
+  //
+  // This cast is safe as MaxLun is defined as UINT8
+  //
+  Request->Lun[1] = (UINT8)Lun;
+  Request->SenseLen = Packet->SenseDataLength;
+  Request->SenseAddr = (UINT64)PVSCSI_DMA_BUF_DEV_ADDR (Dev, SenseData);
+  Request->CdbLen = Packet->CdbLength;
+  CopyMem (Request->Cdb, Packet->Cdb, Packet->CdbLength);
+  Request->vCPUHint = 0;
+  Request->Tag = PVSCSI_SIMPLE_QUEUE_TAG;
+  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+    Request->Flags = PVSCSI_FLAG_CMD_DIR_TOHOST;
+    Request->DataLen = Packet->InTransferLength;
+  } else {
+    Request->Flags = PVSCSI_FLAG_CMD_DIR_TODEVICE;
+    Request->DataLen = Packet->OutTransferLength;
+    CopyMem (
+      Dev->DmaBuf->Data,
+      Packet->OutDataBuffer,
+      Packet->OutTransferLength);
+  }
+  Request->DataAddr = (UINT64)PVSCSI_DMA_BUF_DEV_ADDR (Dev, Data);
+
+  return EFI_SUCCESS;
+}
+
+//
+// Handle the PVSCSI device response:
+// - Copy returned data from DMA communication buffer.
+// - Update fields in Extended SCSI Pass Thru Protocol packet as required.
+// - Translate response code to EFI status code and host adapter status.
+//
+STATIC
+EFI_STATUS
+HandleResponse (
+  IN PVSCSI_DEV                                     *Dev,
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
+  IN CONST PVSCSI_RING_CMP_DESC                     *Response
+  )
+{
+  //
+  // Check if device returned sense data
+  //
+  if (Response->ScsiStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
+    //
+    // Fix SenseDataLength to amount of data returned
+    //
+    if (Packet->SenseDataLength > Response->SenseLen) {
+      Packet->SenseDataLength = (UINT8)Response->SenseLen;
+    }
+    //
+    // Copy sense data from DMA communication buffer
+    //
+    CopyMem (
+      Packet->SenseData,
+      Dev->DmaBuf->SenseData,
+      Packet->SenseDataLength
+      );
+  } else {
+    //
+    // Signal no sense data returned
+    //
+    Packet->SenseDataLength = 0;
+  }
+
+  //
+  // Copy device output from DMA communication buffer
+  //
+  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+    CopyMem (Packet->InDataBuffer, Dev->DmaBuf->Data, Packet->InTransferLength);
+  }
+
+  //
+  // Report target status
+  //
+  Packet->TargetStatus = Response->ScsiStatus;
+
+  //
+  // Host adapter status and function return value depend on
+  // device response's host status
+  //
+  switch (Response->HostStatus) {
+    case BTSTAT_SUCCESS:
+    case BTSTAT_LINKED_COMMAND_COMPLETED:
+    case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG:
+      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
+      return EFI_SUCCESS;
+
+    case BTSTAT_SELTIMEO:
+      Packet->HostAdapterStatus =
+                EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
+      return EFI_TIMEOUT;
+
+    case BTSTAT_DATARUN:
+    case BTSTAT_DATA_UNDERRUN:
+      //
+      // Report residual data in overrun/underrun
+      //
+      if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+        Packet->InTransferLength = Response->DataLen;
+      } else {
+        Packet->OutTransferLength = Response->DataLen;
+      }
+      Packet->HostAdapterStatus =
+                EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
+      return EFI_BAD_BUFFER_SIZE;
+
+    case BTSTAT_BUSFREE:
+      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE;
+      break;
+
+    case BTSTAT_INVPHASE:
+      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
+      break;
+
+    case BTSTAT_SENSFAILED:
+      Packet->HostAdapterStatus =
+                EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED;
+      break;
+
+    case BTSTAT_TAGREJECT:
+    case BTSTAT_BADMSG:
+      Packet->HostAdapterStatus =
+          EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT;
+      break;
+
+    case BTSTAT_BUSRESET:
+      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;
+      break;
+
+    case BTSTAT_HATIMEOUT:
+      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
+      return EFI_TIMEOUT;
+
+    case BTSTAT_SCSIPARITY:
+      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR;
+      break;
+
+    default:
+      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
+      break;
+  }
+
+  return EFI_DEVICE_ERROR;
+}
+
 //
 // Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
 // EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
@@ -135,7 +492,70 @@ PvScsiPassThru (
   IN EFI_EVENT                                      Event    OPTIONAL
   )
 {
-  return EFI_UNSUPPORTED;
+  PVSCSI_DEV            *Dev;
+  EFI_STATUS            Status;
+  PVSCSI_RING_REQ_DESC *Request;
+  PVSCSI_RING_CMP_DESC *Response;
+
+  Dev = PVSCSI_FROM_PASS_THRU (This);
+
+  if (PvScsiIsReqRingFull (Dev)) {
+    return EFI_NOT_READY;
+  }
+
+  Request = PvScsiGetCurrentRequest (Dev);
+
+  Status = PopulateRequest (Dev, Target, Lun, Packet, Request);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Writes to Request must be globally visible before making request
+  // available to device
+  //
+  MemoryFence();
+  Dev->RingDesc.RingState->ReqProdIdx++;
+
+  Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_KICK_RW_IO, 0);
+  if (EFI_ERROR (Status)) {
+    //
+    // If kicking the host fails, we must fake a host adapter error.
+    // EFI_NOT_READY would save us the effort, but it would also suggest that
+    // the caller retry.
+    //
+    goto FakeHostAdapterError;
+  }
+
+  Status = PvScsiWaitForRequestCompletion (Dev);
+  if (EFI_ERROR (Status)) {
+    //
+    // If waiting for request completion fails, we must fake a host adapter
+    // error. EFI_NOT_READY would save us the effort, but it would also suggest
+    // that the caller retry.
+    //
+    goto FakeHostAdapterError;
+  }
+
+  Response = PvScsiGetCurrentResponse (Dev);
+  Status = HandleResponse (Dev, Packet, Response);
+
+  //
+  // Reads from response must complete before releasing completion entry
+  // to device
+  //
+  MemoryFence();
+  Dev->RingDesc.RingState->CmpConsIdx++;
+
+  return Status;
+
+FakeHostAdapterError:
+    Packet->InTransferLength = 0;
+    Packet->OutTransferLength = 0;
+    Packet->SenseDataLength = 0;
+    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
+    Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
+    return EFI_DEVICE_ERROR;
 }
 
 STATIC
@@ -613,6 +1033,7 @@ PvScsiInit (
   //
   Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
   Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
+  Dev->WaitForCmpStallInUsecs = PcdGet32 (PcdPvScsiWaitForCmpStallInUsecs);
 
   //
   // Set PCI Attributes
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
index 7f91d70fec79..08e876b75930 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.h
+++ b/OvmfPkg/PvScsiDxe/PvScsi.h
@@ -47,6 +47,7 @@ typedef struct {
   PVSCSI_DMA_DESC                 DmaBufDmaDesc;
   UINT8                           MaxTarget;
   UINT8                           MaxLun;
+  UINTN                           WaitForCmpStallInUsecs;
   EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
   EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
 } PVSCSI_DEV;
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
index 96bd4e4a9a8b..e3a85eba8dac 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.inf
+++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
@@ -37,5 +37,6 @@
   gEfiExtScsiPassThruProtocolGuid   ## BY_START
 
 [Pcd]
-  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit    ## CONSUMES
-  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit       ## CONSUMES
+  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit            ## CONSUMES
+  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit               ## CONSUMES
+  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiWaitForCmpStallInUsecs    ## CONSUMES
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 16/17] OvmfPkg/PvScsiDxe: Reset device on ExitBootServices()
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (14 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 15/17] OvmfPkg/PvScsiDxe: Support sending SCSI request and receive response Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 17:04   ` [edk2-devel] " Laszlo Ersek
  2020-03-16 15:01 ` [PATCH 17/17] OvmfPkg/PvScsiDxe: Enable device 64-bit DMA addresses Liran Alon
  2020-03-23 16:33 ` [edk2-devel] [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller Laszlo Ersek
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

This causes the device to forget about the request/completion rings.
We allocated said rings in EfiBootServicesData type memory, and code
executing after ExitBootServices() is permitted to overwrite it.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c | 42 +++++++++++++++++++++++++++++++++++++-
 OvmfPkg/PvScsiDxe/PvScsi.h |  1 +
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index e7d0a23db6ab..33167c177b42 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -1156,6 +1156,30 @@ PvScsiUninit (
   }
 }
 
+//
+// Event notification called by ExitBootServices()
+//
+STATIC
+VOID
+EFIAPI
+PvScsiExitBoot (
+  IN  EFI_EVENT Event,
+  IN  VOID      *Context
+  )
+{
+  PVSCSI_DEV *Dev;
+
+  Dev = Context;
+
+  //
+  // Reset the device. This causes the device to forget about the
+  // request/completion rings. We allocated said rings in EfiBootServicesData
+  // type memory, and code executing after ExitBootServices() is permitted to
+  // overwrite it.
+  //
+  PvScsiWriteCmdDesc (Dev, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
+}
+
 //
 // Driver Binding
 //
@@ -1249,6 +1273,17 @@ PvScsiDriverBindingStart (
     goto ClosePciIo;
   }
 
+  Status = gBS->CreateEvent (
+                  EVT_SIGNAL_EXIT_BOOT_SERVICES,
+                  TPL_CALLBACK,
+                  &PvScsiExitBoot,
+                  Dev,
+                  &Dev->ExitBoot
+                  );
+  if (EFI_ERROR (Status)) {
+    goto UninitDev;
+  }
+
   //
   // Setup complete, attempt to export the driver instance's PassThru interface
   //
@@ -1260,11 +1295,14 @@ PvScsiDriverBindingStart (
                   &Dev->PassThru
                   );
   if (EFI_ERROR (Status)) {
-    goto UninitDev;
+    goto CloseExitBoot;
   }
 
   return EFI_SUCCESS;
 
+CloseExitBoot:
+  gBS->CloseEvent (Dev->ExitBoot);
+
 UninitDev:
   PvScsiUninit (Dev);
 
@@ -1319,6 +1357,8 @@ PvScsiDriverBindingStop (
     return Status;
   }
 
+  gBS->CloseEvent (Dev->ExitBoot);
+
   PvScsiUninit (Dev);
 
   gBS->CloseProtocol (
diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
index 08e876b75930..e68a7dedf71f 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.h
+++ b/OvmfPkg/PvScsiDxe/PvScsi.h
@@ -41,6 +41,7 @@ typedef struct {
 typedef struct {
   UINT32                          Signature;
   EFI_PCI_IO_PROTOCOL             *PciIo;
+  EFI_EVENT                       ExitBoot;
   UINT64                          OriginalPciAttributes;
   PVSCSI_RING_DESC                RingDesc;
   PVSCSI_DMA_BUFFER               *DmaBuf;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 17/17] OvmfPkg/PvScsiDxe: Enable device 64-bit DMA addresses
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (15 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 16/17] OvmfPkg/PvScsiDxe: Reset device on ExitBootServices() Liran Alon
@ 2020-03-16 15:01 ` Liran Alon
  2020-03-24 15:26   ` [edk2-devel] " Laszlo Ersek
  2020-03-23 16:33 ` [edk2-devel] [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller Laszlo Ersek
  17 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-16 15:01 UTC (permalink / raw)
  To: devel, lersek
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel,
	Liran Alon

Enable PCI dual-address cycle attribute to signal device supports
64-bit DMA addresses.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
Signed-off-by: Liran Alon <liran.alon@oracle.com>
---
 OvmfPkg/PvScsiDxe/PvScsi.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
index 33167c177b42..e673ed8ba6a0 100644
--- a/OvmfPkg/PvScsiDxe/PvScsi.c
+++ b/OvmfPkg/PvScsiDxe/PvScsi.c
@@ -814,6 +814,27 @@ PvScsiSetPCIAttributes (
     return Status;
   }
 
+  //
+  // Signal device supports 64-bit DMA addresses
+  //
+  Status = Dev->PciIo->Attributes (
+                         Dev->PciIo,
+                         EfiPciIoAttributeOperationEnable,
+                         EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
+                         NULL
+                         );
+  if (EFI_ERROR (Status)) {
+    //
+    // Warn user device will only be using 32-bit DMA addresses.
+    //
+    // Note that this does not prevent device/driver from working
+    // and therefore we only warn and continue as usual.
+    //
+    DEBUG ((DEBUG_WARN,
+            "%a: failed to enable 64-bit DMA addresses\n",
+            __FUNCTION__));
+  }
+
   return EFI_SUCCESS;
 }
 
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller
  2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
                   ` (16 preceding siblings ...)
  2020-03-16 15:01 ` [PATCH 17/17] OvmfPkg/PvScsiDxe: Enable device 64-bit DMA addresses Liran Alon
@ 2020-03-23 16:33 ` Laszlo Ersek
  17 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-23 16:33 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

Hi Liran,

On 03/16/20 16:00, Liran Alon wrote:
> Hi,
> 
> This series adds driver support for VMware PVSCSI controller.
> 
> This controller is supported by VMware and QEMU. This work is part of
> the more general agenda of enhancing OVMF boot device support to have
> feature parity with SeaBIOS (Which supports booting from VMware PVSCSI).
> 
> The BugZilla ticket for this feature is at:
> https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> 
> I pushed a copy of these patches to:
> https://github.com/nikital/edk2/tree/pvscsi4
> 
> Regards,
> -Liran

I'm back. Your patch series is in my review queue. I'll need some time
for dealing with the usual email backlog after being away for a few days.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 01/17] OvmfPkg/PvScsiDxe: Create empty driver
  2020-03-16 15:00 ` [PATCH 01/17] OvmfPkg/PvScsiDxe: Create empty driver Liran Alon
@ 2020-03-24 11:15   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 11:15 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:00, Liran Alon wrote:
> In preparation for support booting from PvScsi devices, create a
> basic scaffolding for a driver.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>

(1) As stated earlier, I'll have to strip the feedback tags not given on
the list. Can you strip them for me in v2 please? (Nikita can re-ack on
the list, but I'd suggest waiting with that until the series stabilizes.)

> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/OvmfPkgIa32.dsc      |  8 ++++++++
>  OvmfPkg/OvmfPkgIa32.fdf      |  3 +++
>  OvmfPkg/OvmfPkgIa32X64.dsc   |  8 ++++++++
>  OvmfPkg/OvmfPkgIa32X64.fdf   |  3 +++
>  OvmfPkg/OvmfPkgX64.dsc       |  8 ++++++++
>  OvmfPkg/OvmfPkgX64.fdf       |  3 +++
>  OvmfPkg/PvScsiDxe/PvScsi.c   | 24 ++++++++++++++++++++++++
>  OvmfPkg/PvScsiDxe/PvScsi.inf | 27 +++++++++++++++++++++++++++
>  8 files changed, 84 insertions(+)
>  create mode 100644 OvmfPkg/PvScsiDxe/PvScsi.c
>  create mode 100644 OvmfPkg/PvScsiDxe/PvScsi.inf
> 
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 19728f20b34e..79b8c58e54c3 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -44,6 +44,11 @@
>  
>  !include NetworkPkg/NetworkDefines.dsc.inc
>  
> +  #
> +  # Device drivers
> +  #
> +  DEFINE PVSCSI_ENABLE           = TRUE
> +
>    #
>    # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to
>    # one of the supported values, in place of any of the convenience macros, is
> @@ -718,6 +723,9 @@
>    OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
>    OvmfPkg/XenBusDxe/XenBusDxe.inf
>    OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
> +!ifdef $(PVSCSI_ENABLE)
> +  OvmfPkg/PvScsiDxe/PvScsiDxe.inf
> +!endif
>    MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
>    MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
>    MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf

(2) Please use the following directive instead:

!if $(PVSCSI_ENABLE) == TRUE

Because, passing "-D PVSCSI_ENABLE=FALSE" on the "build" utility's
command line would satisfy "!ifdef" (I've double-checked that with a
small ad-hoc patch right now). The "build" utility does not support an
"-U" option (for undefining a macro), like "cpp" does.

Note that this request is consistent with the existent !if and
!ifdef/!ifndef directives in the DSC files. The latter directive is only
applied to the following macros:

- FD_SIZE_1MB
- FD_SIZE_2MB
- FD_SIZE_4MB
- DEBUG_ON_SERIAL_PORT
- CSM_ENABLE

And none of those are DEFINE'd by default in the [Defines] section.
Therefore a "build" invocation can leave them undefined, or define them.
It never needs to "undo" them.

The boolean macros with default values assigned under [Defines] are
different -- we should allow "build" to disable them with a "-D
MACROBOOL=FALSE" option, and for that we should compare them against
TRUE (or FALSE) explicitly.

> diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
> index 63607551ed75..f59a58bc2689 100644
> --- a/OvmfPkg/OvmfPkgIa32.fdf
> +++ b/OvmfPkg/OvmfPkgIa32.fdf
> @@ -227,6 +227,9 @@ INF  OvmfPkg/VirtioRngDxe/VirtioRng.inf
>  INF  OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
>  INF  OvmfPkg/XenBusDxe/XenBusDxe.inf
>  INF  OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
> +!if $(PVSCSI_ENABLE) == TRUE
> +  INF  OvmfPkg/PvScsiDxe/PvScsiDxe.inf
> +!endif
>  
>  !if $(SECURE_BOOT_ENABLE) == TRUE
>    INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf

Yes, this is OK.

(3) However, please do not indent the conditional "INF" line. See other
!if directives in the same file.

(... Unfortunately, the SecureBootConfigDxe line, visible in the context
above, is precisely the one preexistent example that doesn't follow the
rule. :/ All the other !if's and !ifdef's do.)

> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index 3c0c229e3a72..744f7eb05e12 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -44,6 +44,11 @@
>  
>  !include NetworkPkg/NetworkDefines.dsc.inc
>  
> +  #
> +  # Device drivers
> +  #
> +  DEFINE PVSCSI_ENABLE           = TRUE
> +
>    #
>    # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to
>    # one of the supported values, in place of any of the convenience macros, is
> @@ -731,6 +736,9 @@
>    OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
>    OvmfPkg/XenBusDxe/XenBusDxe.inf
>    OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
> +!ifdef $(PVSCSI_ENABLE)
> +  OvmfPkg/PvScsiDxe/PvScsiDxe.inf
> +!endif
>    MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
>    MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
>    MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
> diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
> index 0488e5d95ffe..5fd21ea1b2de 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.fdf
> +++ b/OvmfPkg/OvmfPkgIa32X64.fdf
> @@ -228,6 +228,9 @@ INF  OvmfPkg/VirtioRngDxe/VirtioRng.inf
>  INF  OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
>  INF  OvmfPkg/XenBusDxe/XenBusDxe.inf
>  INF  OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
> +!if $(PVSCSI_ENABLE) == TRUE
> +  INF  OvmfPkg/PvScsiDxe/PvScsiDxe.inf
> +!endif
>  
>  !if $(SECURE_BOOT_ENABLE) == TRUE
>    INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf

(4) In all of the above DSC and FDF files (Ia32 and Ia32X64), you refer
to "PvScsiDxe.inf". But the INF file is in fact called "PvScsi.inf". The
references are correct only in the X64 DSC and FDF files, below. The
32-bit PEI phase platforms no longer build with this patch:

build.py...
 : error 000E: File/directory not found in workspace
        .../OvmfPkg/PvScsiDxe/PvScsiDxe.inf

Please do not submit untested code for review. It is de-motivating to
find bugs by code inspection that could have been trivially caught in
testing.

I guess you had built the IA32 and IA32X64 platforms too, at some point,
but then you may have renamed the INF file, and forgot to update the
references, and to rebuild as well. It is best to always build all three
platforms (no matter how small the change), in a reasonably "complete"
configuration.

> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index f6c1d8d228c6..64ed3d5ec18e 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -44,6 +44,11 @@
>  
>  !include NetworkPkg/NetworkDefines.dsc.inc
>  
> +  #
> +  # Device drivers
> +  #
> +  DEFINE PVSCSI_ENABLE           = TRUE
> +
>    #
>    # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to
>    # one of the supported values, in place of any of the convenience macros, is
> @@ -729,6 +734,9 @@
>    OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
>    OvmfPkg/XenBusDxe/XenBusDxe.inf
>    OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
> +!ifdef $(PVSCSI_ENABLE)
> +  OvmfPkg/PvScsiDxe/PvScsi.inf
> +!endif
>    MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
>    MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
>    MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
> index 0488e5d95ffe..c155993dc16f 100644
> --- a/OvmfPkg/OvmfPkgX64.fdf
> +++ b/OvmfPkg/OvmfPkgX64.fdf
> @@ -228,6 +228,9 @@ INF  OvmfPkg/VirtioRngDxe/VirtioRng.inf
>  INF  OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf
>  INF  OvmfPkg/XenBusDxe/XenBusDxe.inf
>  INF  OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf
> +!if $(PVSCSI_ENABLE) == TRUE
> +  INF  OvmfPkg/PvScsiDxe/PvScsi.inf
> +!endif
>  
>  !if $(SECURE_BOOT_ENABLE) == TRUE
>    INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> new file mode 100644
> index 000000000000..a3f704d60d77
> --- /dev/null
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -0,0 +1,24 @@
> +/** @file
> +
> +  This driver produces Extended SCSI Pass Thru Protocol instances for
> +  pvscsi devices.
> +
> +  Copyright (C) 2020, Oracle and/or its affiliates.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +//
> +// Entry Point
> +//
> +
> +EFI_STATUS
> +EFIAPI
> +PvScsiEntryPoint (
> +  IN EFI_HANDLE       ImageHandle,
> +  IN EFI_SYSTEM_TABLE *SystemTable
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}

I'd #include <Uefi/UefiSpec.h> for EFI_SYSTEM_TABLE (and that #include
would bring in the rest of EFI_STATUS, EFI_HANDLE etc). But, I fully
agree that the C file already builds fine like this, due to the
auto-generated headers and whatnot, so it's OK.

> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
> new file mode 100644
> index 000000000000..093cc0171338
> --- /dev/null
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
> @@ -0,0 +1,27 @@
> +## @file
> +#
> +# This driver produces Extended SCSI Pass Thru Protocol instances for
> +# pvscsi devices.
> +#
> +# Copyright (C) 2020, Oracle and/or its affiliates.
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 1.29
> +  BASE_NAME                      = PvScsiDxe

Not consistent with the name of the INF file ("PvScsi.inf"), but it is
certainly not a deal breaker. It's OK if you don't want to bring those
in sync.

> +  FILE_GUID                      = 30346B14-1580-4781-879D-BA0C55AE9BB2
> +  MODULE_TYPE                    = UEFI_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = PvScsiEntryPoint
> +
> +[Sources]
> +  PvScsi.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> +  UefiDriverEntryPoint
> 

Thanks,
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 02/17] OvmfPkg/PvScsiDxe: Install DriverBinding protocol
  2020-03-16 15:00 ` [PATCH 02/17] OvmfPkg/PvScsiDxe: Install DriverBinding protocol Liran Alon
@ 2020-03-24 11:23   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 11:23 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:00, Liran Alon wrote:
> In order to probe and connect to the PvScsi device we need this
> protocol. Currently it does nothing.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c   | 68 +++++++++++++++++++++++++++++++++++-
>  OvmfPkg/PvScsiDxe/PvScsi.inf |  1 +
>  2 files changed, 68 insertions(+), 1 deletion(-)
> 
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index a3f704d60d77..bf0c743bad15 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -9,6 +9,65 @@
>  
>  **/
>  
> +#include <Library/UefiLib.h>
> +
> +//
> +// Higher versions will be used before lower, 0x10-0xffffffef is the version
> +// range for IVH (Indie Hardware Vendors)

(1) typo: s/IVH/IHV/

> +//
> +#define PVSCSI_BINDING_VERSION      0x10
> +
> +//
> +// Driver Binding
> +//
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiDriverBindingSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  ControllerHandle,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiDriverBindingStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  ControllerHandle,
> +  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiDriverBindingStop (
> +  IN EFI_DRIVER_BINDING_PROTOCOL *This,
> +  IN EFI_HANDLE                  ControllerHandle,
> +  IN UINTN                       NumberOfChildren,
> +  IN EFI_HANDLE                  *ChildHandleBuffer
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding = {

(2) For object declarations, we generally keep STATIC on the same line
as the type name.

> +  &PvScsiDriverBindingSupported,
> +  &PvScsiDriverBindingStart,
> +  &PvScsiDriverBindingStop,
> +  PVSCSI_BINDING_VERSION,
> +  NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2()
> +  NULL  // DriverBindingHandle, filled as well
> +};
> +
>  //
>  // Entry Point
>  //
> @@ -20,5 +79,12 @@ PvScsiEntryPoint (
>    IN EFI_SYSTEM_TABLE *SystemTable
>    )
>  {
> -  return EFI_UNSUPPORTED;
> +  return EfiLibInstallDriverBindingComponentName2 (
> +           ImageHandle,
> +           SystemTable,
> +           &mPvScsiDriverBinding,
> +           ImageHandle,
> +           NULL, // TODO Component name
> +           NULL  // TODO Component name
> +           );
>  }
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
> index 093cc0171338..d1d0e963f96d 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.inf
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
> @@ -25,3 +25,4 @@
>  
>  [LibraryClasses]
>    UefiDriverEntryPoint
> +  UefiLib
> 

With (1) and (2) addressed:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

(Please strip Nikita's R-b in v2, or please ask Nikita to post the R-b
in response to this v1 patch.)

Thanks,
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 03/17] OvmfPkg/PvScsiDxe: Report name of driver
  2020-03-16 15:00 ` [PATCH 03/17] OvmfPkg/PvScsiDxe: Report name of driver Liran Alon
@ 2020-03-24 11:29   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 11:29 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:00, Liran Alon wrote:
> Install Component Name protocols to have a nice display name for the
> driver in places such as UEFI shell.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c | 63 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 61 insertions(+), 2 deletions(-)
> 
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index bf0c743bad15..0c81e645de08 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -68,6 +68,65 @@ EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding = {
>    NULL  // DriverBindingHandle, filled as well
>  };
>  
> +//
> +// Component Name
> +//
> +
> +STATIC
> +EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
> +  { "eng;en", L"PVSCSI Host Driver" },
> +  { NULL,     NULL                  }
> +};
> +
> +STATIC
> +EFI_COMPONENT_NAME_PROTOCOL mComponentName;
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> +  IN  CHAR8                       *Language,
> +  OUT CHAR16                      **DriverName
> +  )
> +{
> +  return LookupUnicodeString2 (
> +           Language,
> +           This->SupportedLanguages,
> +           mDriverNameTable,
> +           DriverName,
> +           (BOOLEAN)(This == &mComponentName) // Iso639Language
> +           );
> +}
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiGetDeviceName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
> +  IN  EFI_HANDLE                  DeviceHandle,
> +  IN  EFI_HANDLE                  ChildHandle,
> +  IN  CHAR8                       *Language,
> +  OUT CHAR16                      **ControllerName
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
> +  &PvScsiGetDriverName,
> +  &PvScsiGetDeviceName,
> +  "eng" // SupportedLanguages, ISO 639-2 language codes
> +};
> +
> +STATIC
> +EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
> +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &PvScsiGetDriverName,
> +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &PvScsiGetDeviceName,
> +  "en" // SupportedLanguages, RFC 4646 language codes
> +};
> +
>  //
>  // Entry Point
>  //
> @@ -84,7 +143,7 @@ PvScsiEntryPoint (
>             SystemTable,
>             &mPvScsiDriverBinding,
>             ImageHandle,
> -           NULL, // TODO Component name
> -           NULL  // TODO Component name
> +           &mComponentName,
> +           &mComponentName2
>             );
>  }
> 

Reviewed-by: Laszlo Ersek <lersek@redhat.com>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 04/17] OvmfPkg/PvScsiDxe: Probe PCI devices and look for PvScsi
  2020-03-16 15:01 ` [PATCH 04/17] OvmfPkg/PvScsiDxe: Probe PCI devices and look for PvScsi Liran Alon
@ 2020-03-24 11:41   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 11:41 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:01, Liran Alon wrote:
> PvScsiControllerSupported() is called on handles passed in
> by the ConnectController() boot service and if the handle is the
> PVSCSI controller, the function would return success. A success
> return value will attach our driver to the device.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/Include/IndustryStandard/PvScsi.h | 21 ++++++++++
>  OvmfPkg/PvScsiDxe/PvScsi.c                | 49 ++++++++++++++++++++++-
>  OvmfPkg/PvScsiDxe/PvScsi.inf              |  5 +++
>  3 files changed, 74 insertions(+), 1 deletion(-)
>  create mode 100644 OvmfPkg/Include/IndustryStandard/PvScsi.h
> 
> diff --git a/OvmfPkg/Include/IndustryStandard/PvScsi.h b/OvmfPkg/Include/IndustryStandard/PvScsi.h
> new file mode 100644
> index 000000000000..004c0af84989
> --- /dev/null
> +++ b/OvmfPkg/Include/IndustryStandard/PvScsi.h
> @@ -0,0 +1,21 @@
> +/** @file
> +
> +  VMware PVSCSI Device specific type and macro definitions.
> +
> +  Copyright (C) 2020, Oracle and/or its affiliates.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __PVSCSI_H_
> +#define __PVSCSI_H_
> +
> +//
> +// Device offsets and constants
> +//
> +
> +#define PCI_VENDOR_ID_VMWARE            (0x15ad)
> +#define PCI_DEVICE_ID_VMWARE_PVSCSI     (0x07c0)
> +
> +#endif // __PVSCSI_H_
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index 0c81e645de08..f1fffe962233 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -9,7 +9,11 @@
>  
>  **/
>  
> +#include <IndustryStandard/Pci.h>
> +#include <IndustryStandard/PvScsi.h>
> +#include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiLib.h>
> +#include <Protocol/PciIo.h>
>  
>  //
>  // Higher versions will be used before lower, 0x10-0xffffffef is the version
> @@ -30,7 +34,50 @@ PvScsiDriverBindingSupported (
>    IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
>    )
>  {
> -  return EFI_UNSUPPORTED;
> +  EFI_STATUS          Status;
> +  EFI_PCI_IO_PROTOCOL *PciIo;
> +  PCI_TYPE00          Pci;
> +
> +  Status = gBS->OpenProtocol (
> +                  ControllerHandle,
> +                  &gEfiPciIoProtocolGuid,
> +                  (VOID **)&PciIo,
> +                  This->DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = PciIo->Pci.Read (
> +                        PciIo,
> +                        EfiPciIoWidthUint32,
> +                        0,
> +                        sizeof(Pci) / sizeof(UINT32),

(1) Please insert a space character before each opening parenthesis.

> +                        &Pci
> +                        );
> +  if (EFI_ERROR (Status)) {
> +      goto Done;

(2) Wrong indentation.

> +  }
> +
> +  if ((Pci.Hdr.VendorId != PCI_VENDOR_ID_VMWARE) ||
> +      (Pci.Hdr.DeviceId != PCI_DEVICE_ID_VMWARE_PVSCSI)) {
> +      Status = EFI_UNSUPPORTED;
> +      goto Done;

(3) Wrong indentation.

> +  }
> +
> +  Status = EFI_SUCCESS;
> +
> +Done:
> +  gBS->CloseProtocol (
> +         ControllerHandle,
> +         &gEfiPciIoProtocolGuid,
> +         This->DriverBindingHandle,
> +         ControllerHandle
> +         );
> +
> +  return Status;
>  }
>  
>  STATIC
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
> index d1d0e963f96d..c1f0663832ed 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.inf
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
> @@ -22,7 +22,12 @@
>  
>  [Packages]
>    MdePkg/MdePkg.dec
> +  OvmfPkg/OvmfPkg.dec
>  
>  [LibraryClasses]
> +  UefiBootServicesTableLib
>    UefiDriverEntryPoint
>    UefiLib
> +
> +[Protocols]
> +  gEfiPciIoProtocolGuid        ## TO_START
> 

With (1) through (3) addressed:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 05/17] OvmfPkg/PvScsiDxe: Install stubbed EXT_SCSI_PASS_THRU
  2020-03-16 15:01 ` [PATCH 05/17] OvmfPkg/PvScsiDxe: Install stubbed EXT_SCSI_PASS_THRU Liran Alon
@ 2020-03-24 12:27   ` Laszlo Ersek
  2020-03-24 12:47     ` Laszlo Ersek
  0 siblings, 1 reply; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 12:27 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:01, Liran Alon wrote:
> Support dynamic insertion and removal of the protocol.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c   | 209 ++++++++++++++++++++++++++++++++++-
>  OvmfPkg/PvScsiDxe/PvScsi.h   |  29 +++++
>  OvmfPkg/PvScsiDxe/PvScsi.inf |   5 +-
>  3 files changed, 240 insertions(+), 3 deletions(-)
>  create mode 100644 OvmfPkg/PvScsiDxe/PvScsi.h
> 
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index f1fffe962233..46b430a34a57 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -11,16 +11,155 @@
>  
>  #include <IndustryStandard/Pci.h>
>  #include <IndustryStandard/PvScsi.h>
> +#include <Library/MemoryAllocationLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiLib.h>
>  #include <Protocol/PciIo.h>
>  
> +#include "PvScsi.h"
> +
>  //
>  // Higher versions will be used before lower, 0x10-0xffffffef is the version
>  // range for IVH (Indie Hardware Vendors)
>  //
>  #define PVSCSI_BINDING_VERSION      0x10
>  
> +//
> +// Ext SCSI Pass Thru
> +//
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiPassThru (
> +  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
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiGetNextTargetLun (
> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
> +  IN OUT UINT8                                      **Target,
> +  IN OUT UINT64                                     *Lun
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiBuildDevicePath (
> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
> +  IN UINT8                                          *Target,
> +  IN UINT64                                         Lun,
> +  IN OUT EFI_DEVICE_PATH_PROTOCOL                   **DevicePath
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiGetTargetLun (
> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
> +  IN EFI_DEVICE_PATH_PROTOCOL                       *DevicePath,
> +  OUT UINT8                                         **Target,
> +  OUT UINT64                                        *Lun
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiResetChannel (
> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiResetTargetLun (
> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
> +  IN UINT8                                          *Target,
> +  IN UINT64                                         Lun
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +PvScsiGetNextTarget (
> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
> +  IN OUT UINT8                                      **Target
> +  )
> +{
> +  return EFI_UNSUPPORTED;
> +}
> +
> +STATIC
> +EFI_STATUS
> +PvScsiInit (
> +  IN OUT PVSCSI_DEV *Dev
> +  )
> +{
> +  //
> +  // Populate the exported interface's attributes
> +  //
> +  Dev->PassThru.Mode             = &Dev->PassThruMode;
> +  Dev->PassThru.PassThru         = &PvScsiPassThru;
> +  Dev->PassThru.GetNextTargetLun = &PvScsiGetNextTargetLun;
> +  Dev->PassThru.BuildDevicePath  = &PvScsiBuildDevicePath;
> +  Dev->PassThru.GetTargetLun     = &PvScsiGetTargetLun;
> +  Dev->PassThru.ResetChannel     = &PvScsiResetChannel;
> +  Dev->PassThru.ResetTargetLun   = &PvScsiResetTargetLun;
> +  Dev->PassThru.GetNextTarget    = &PvScsiGetNextTarget;
> +
> +  //
> +  // AdapterId is a target for which no handle will be created during bus scan.
> +  // Prevent any conflict with real devices.
> +  //
> +  Dev->PassThruMode.AdapterId = MAX_UINT32;
> +
> +  //
> +  // Set both physical and logical attributes for non-RAID SCSI channel
> +  //
> +  Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
> +                                 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
> +
> +  //
> +  // No restriction on transfer buffer alignment
> +  //
> +  Dev->PassThruMode.IoAlign = 0;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +STATIC
> +VOID
> +PvScsiUninit (
> +  IN OUT PVSCSI_DEV *Dev
> +  )
> +{
> +  // Currently nothing to do here
> +}
> +
>  //
>  // Driver Binding
>  //
> @@ -89,7 +228,42 @@ PvScsiDriverBindingStart (
>    IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
>    )
>  {
> -  return EFI_UNSUPPORTED;
> +  PVSCSI_DEV *Dev;
> +  EFI_STATUS Status;
> +
> +  Dev = (PVSCSI_DEV *) AllocateZeroPool (sizeof (*Dev));
> +  if (Dev == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = PvScsiInit (Dev);
> +  if (EFI_ERROR (Status)) {
> +    goto FreePvScsi;
> +  }
> +
> +  //
> +  // Setup complete, attempt to export the driver instance's PassThru interface
> +  //
> +  Dev->Signature = PVSCSI_SIG;
> +  Status = gBS->InstallProtocolInterface (
> +                  &ControllerHandle,
> +                  &gEfiExtScsiPassThruProtocolGuid,
> +                  EFI_NATIVE_INTERFACE,
> +                  &Dev->PassThru
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    goto UninitDev;
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +UninitDev:
> +  PvScsiUninit (Dev);
> +
> +FreePvScsi:
> +  FreePool (Dev);
> +
> +  return Status;
>  }
>  
>  STATIC
> @@ -102,7 +276,38 @@ PvScsiDriverBindingStop (
>    IN EFI_HANDLE                  *ChildHandleBuffer
>    )
>  {
> -  return EFI_UNSUPPORTED;
> +  EFI_STATUS                      Status;
> +  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
> +  PVSCSI_DEV                      *Dev;
> +
> +  Status = gBS->OpenProtocol (
> +                  ControllerHandle,
> +                  &gEfiExtScsiPassThruProtocolGuid,
> +                  (VOID **)&PassThru,
> +                  This->DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Dev = PVSCSI_FROM_PASS_THRU (PassThru);
> +
> +  Status = gBS->UninstallProtocolInterface (
> +                  ControllerHandle,
> +                  &gEfiExtScsiPassThruProtocolGuid,
> +                  &Dev->PassThru
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  PvScsiUninit (Dev);
> +
> +  FreePool (Dev);
> +
> +  return EFI_SUCCESS;
>  }
>  
>  STATIC
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
> new file mode 100644
> index 000000000000..3940b4c20019
> --- /dev/null
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.h
> @@ -0,0 +1,29 @@
> +/** @file
> +
> +  Internal definitions for the PVSCSI driver, which produces Extended SCSI
> +  Pass Thru Protocol instances for pvscsi devices.
> +
> +  Copyright (C) 2020, Oracle and/or its affiliates.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __PVSCSI_DXE_H_
> +#define __PVSCSI_DXE_H_
> +
> +#include <Library/DebugLib.h>
> +#include <Protocol/ScsiPassThruExt.h>
> +
> +#define PVSCSI_SIG SIGNATURE_32 ('P', 'S', 'C', 'S')
> +
> +typedef struct {
> +  UINT32                          Signature;
> +  EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
> +  EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
> +} PVSCSI_DEV;
> +
> +#define PVSCSI_FROM_PASS_THRU(PassThruPointer) \
> +  CR (PassThruPointer, PVSCSI_DEV, PassThru, PVSCSI_SIG)
> +
> +#endif // __PVSCSI_DXE_H_
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
> index c1f0663832ed..3a8b07872ba3 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.inf
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
> @@ -25,9 +25,12 @@
>    OvmfPkg/OvmfPkg.dec
>  
>  [LibraryClasses]
> +  DebugLib
> +  MemoryAllocationLib
>    UefiBootServicesTableLib
>    UefiDriverEntryPoint
>    UefiLib
>  
>  [Protocols]
> -  gEfiPciIoProtocolGuid        ## TO_START
> +  gEfiPciIoProtocolGuid             ## TO_START
> +  gEfiExtScsiPassThruProtocolGuid   ## BY_START
> 

(1) In the [Sources] section of the INF file, please list the new header
file ("PvScsi.h").

With that:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks,
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 05/17] OvmfPkg/PvScsiDxe: Install stubbed EXT_SCSI_PASS_THRU
  2020-03-24 12:27   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-24 12:47     ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 12:47 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/24/20 13:27, Laszlo Ersek wrote:
> On 03/16/20 16:01, Liran Alon wrote:
>> Support dynamic insertion and removal of the protocol.
>>
>> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
>> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
>> Signed-off-by: Liran Alon <liran.alon@oracle.com>
>> ---
>>  OvmfPkg/PvScsiDxe/PvScsi.c   | 209 ++++++++++++++++++++++++++++++++++-
>>  OvmfPkg/PvScsiDxe/PvScsi.h   |  29 +++++
>>  OvmfPkg/PvScsiDxe/PvScsi.inf |   5 +-
>>  3 files changed, 240 insertions(+), 3 deletions(-)
>>  create mode 100644 OvmfPkg/PvScsiDxe/PvScsi.h
>>
>> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
>> index f1fffe962233..46b430a34a57 100644
>> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
>> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
>> @@ -11,16 +11,155 @@
>>  
>>  #include <IndustryStandard/Pci.h>
>>  #include <IndustryStandard/PvScsi.h>
>> +#include <Library/MemoryAllocationLib.h>
>>  #include <Library/UefiBootServicesTableLib.h>
>>  #include <Library/UefiLib.h>
>>  #include <Protocol/PciIo.h>
>>  
>> +#include "PvScsi.h"
>> +
>>  //
>>  // Higher versions will be used before lower, 0x10-0xffffffef is the version
>>  // range for IVH (Indie Hardware Vendors)
>>  //
>>  #define PVSCSI_BINDING_VERSION      0x10
>>  
>> +//
>> +// Ext SCSI Pass Thru
>> +//
>> +
>> +STATIC
>> +EFI_STATUS
>> +EFIAPI
>> +PvScsiPassThru (
>> +  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
>> +  )
>> +{
>> +  return EFI_UNSUPPORTED;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +EFIAPI
>> +PvScsiGetNextTargetLun (
>> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
>> +  IN OUT UINT8                                      **Target,
>> +  IN OUT UINT64                                     *Lun
>> +  )
>> +{
>> +  return EFI_UNSUPPORTED;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +EFIAPI
>> +PvScsiBuildDevicePath (
>> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
>> +  IN UINT8                                          *Target,
>> +  IN UINT64                                         Lun,
>> +  IN OUT EFI_DEVICE_PATH_PROTOCOL                   **DevicePath
>> +  )
>> +{
>> +  return EFI_UNSUPPORTED;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +EFIAPI
>> +PvScsiGetTargetLun (
>> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
>> +  IN EFI_DEVICE_PATH_PROTOCOL                       *DevicePath,
>> +  OUT UINT8                                         **Target,
>> +  OUT UINT64                                        *Lun
>> +  )
>> +{
>> +  return EFI_UNSUPPORTED;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +EFIAPI
>> +PvScsiResetChannel (
>> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This
>> +  )
>> +{
>> +  return EFI_UNSUPPORTED;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +EFIAPI
>> +PvScsiResetTargetLun (
>> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
>> +  IN UINT8                                          *Target,
>> +  IN UINT64                                         Lun
>> +  )
>> +{
>> +  return EFI_UNSUPPORTED;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +EFIAPI
>> +PvScsiGetNextTarget (
>> +  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,
>> +  IN OUT UINT8                                      **Target
>> +  )
>> +{
>> +  return EFI_UNSUPPORTED;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +PvScsiInit (
>> +  IN OUT PVSCSI_DEV *Dev
>> +  )
>> +{
>> +  //
>> +  // Populate the exported interface's attributes
>> +  //
>> +  Dev->PassThru.Mode             = &Dev->PassThruMode;
>> +  Dev->PassThru.PassThru         = &PvScsiPassThru;
>> +  Dev->PassThru.GetNextTargetLun = &PvScsiGetNextTargetLun;
>> +  Dev->PassThru.BuildDevicePath  = &PvScsiBuildDevicePath;
>> +  Dev->PassThru.GetTargetLun     = &PvScsiGetTargetLun;
>> +  Dev->PassThru.ResetChannel     = &PvScsiResetChannel;
>> +  Dev->PassThru.ResetTargetLun   = &PvScsiResetTargetLun;
>> +  Dev->PassThru.GetNextTarget    = &PvScsiGetNextTarget;
>> +
>> +  //
>> +  // AdapterId is a target for which no handle will be created during bus scan.
>> +  // Prevent any conflict with real devices.
>> +  //
>> +  Dev->PassThruMode.AdapterId = MAX_UINT32;
>> +
>> +  //
>> +  // Set both physical and logical attributes for non-RAID SCSI channel
>> +  //
>> +  Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
>> +                                 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
>> +
>> +  //
>> +  // No restriction on transfer buffer alignment
>> +  //
>> +  Dev->PassThruMode.IoAlign = 0;
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +STATIC
>> +VOID
>> +PvScsiUninit (
>> +  IN OUT PVSCSI_DEV *Dev
>> +  )
>> +{
>> +  // Currently nothing to do here
>> +}
>> +
>>  //
>>  // Driver Binding
>>  //
>> @@ -89,7 +228,42 @@ PvScsiDriverBindingStart (
>>    IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
>>    )
>>  {
>> -  return EFI_UNSUPPORTED;
>> +  PVSCSI_DEV *Dev;
>> +  EFI_STATUS Status;
>> +
>> +  Dev = (PVSCSI_DEV *) AllocateZeroPool (sizeof (*Dev));
>> +  if (Dev == NULL) {
>> +    return EFI_OUT_OF_RESOURCES;
>> +  }
>> +
>> +  Status = PvScsiInit (Dev);
>> +  if (EFI_ERROR (Status)) {
>> +    goto FreePvScsi;
>> +  }
>> +
>> +  //
>> +  // Setup complete, attempt to export the driver instance's PassThru interface
>> +  //
>> +  Dev->Signature = PVSCSI_SIG;
>> +  Status = gBS->InstallProtocolInterface (
>> +                  &ControllerHandle,
>> +                  &gEfiExtScsiPassThruProtocolGuid,
>> +                  EFI_NATIVE_INTERFACE,
>> +                  &Dev->PassThru
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    goto UninitDev;
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +
>> +UninitDev:
>> +  PvScsiUninit (Dev);
>> +
>> +FreePvScsi:
>> +  FreePool (Dev);
>> +
>> +  return Status;
>>  }
>>  
>>  STATIC
>> @@ -102,7 +276,38 @@ PvScsiDriverBindingStop (
>>    IN EFI_HANDLE                  *ChildHandleBuffer
>>    )
>>  {
>> -  return EFI_UNSUPPORTED;
>> +  EFI_STATUS                      Status;
>> +  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
>> +  PVSCSI_DEV                      *Dev;
>> +
>> +  Status = gBS->OpenProtocol (
>> +                  ControllerHandle,
>> +                  &gEfiExtScsiPassThruProtocolGuid,
>> +                  (VOID **)&PassThru,
>> +                  This->DriverBindingHandle,
>> +                  ControllerHandle,
>> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  Dev = PVSCSI_FROM_PASS_THRU (PassThru);
>> +
>> +  Status = gBS->UninstallProtocolInterface (
>> +                  ControllerHandle,
>> +                  &gEfiExtScsiPassThruProtocolGuid,
>> +                  &Dev->PassThru
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  PvScsiUninit (Dev);
>> +
>> +  FreePool (Dev);
>> +
>> +  return EFI_SUCCESS;
>>  }
>>  
>>  STATIC
>> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
>> new file mode 100644
>> index 000000000000..3940b4c20019
>> --- /dev/null
>> +++ b/OvmfPkg/PvScsiDxe/PvScsi.h
>> @@ -0,0 +1,29 @@
>> +/** @file
>> +
>> +  Internal definitions for the PVSCSI driver, which produces Extended SCSI
>> +  Pass Thru Protocol instances for pvscsi devices.
>> +
>> +  Copyright (C) 2020, Oracle and/or its affiliates.
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef __PVSCSI_DXE_H_
>> +#define __PVSCSI_DXE_H_
>> +
>> +#include <Library/DebugLib.h>
>> +#include <Protocol/ScsiPassThruExt.h>
>> +
>> +#define PVSCSI_SIG SIGNATURE_32 ('P', 'S', 'C', 'S')
>> +
>> +typedef struct {
>> +  UINT32                          Signature;
>> +  EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
>> +  EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
>> +} PVSCSI_DEV;
>> +
>> +#define PVSCSI_FROM_PASS_THRU(PassThruPointer) \
>> +  CR (PassThruPointer, PVSCSI_DEV, PassThru, PVSCSI_SIG)
>> +
>> +#endif // __PVSCSI_DXE_H_
>> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
>> index c1f0663832ed..3a8b07872ba3 100644
>> --- a/OvmfPkg/PvScsiDxe/PvScsi.inf
>> +++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
>> @@ -25,9 +25,12 @@
>>    OvmfPkg/OvmfPkg.dec
>>  
>>  [LibraryClasses]
>> +  DebugLib
>> +  MemoryAllocationLib
>>    UefiBootServicesTableLib
>>    UefiDriverEntryPoint
>>    UefiLib
>>  
>>  [Protocols]
>> -  gEfiPciIoProtocolGuid        ## TO_START
>> +  gEfiPciIoProtocolGuid             ## TO_START
>> +  gEfiExtScsiPassThruProtocolGuid   ## BY_START
>>
> 
> (1) In the [Sources] section of the INF file, please list the new header
> file ("PvScsi.h").

(2) Please keep the list of protocols lexicographically sorted. (I
understand that you may have intended to place BY_START logically under
TO_START -- that looks simple enough initially, but with time it can get
messy. With normal sorting, there's never any doubt though.)

> 
> With that:
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>

This stands.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 06/17] OvmfPkg/PvScsiDxe: Report the number of targets and LUNs
  2020-03-16 15:01 ` [PATCH 06/17] OvmfPkg/PvScsiDxe: Report the number of targets and LUNs Liran Alon
@ 2020-03-24 13:12   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 13:12 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:01, Liran Alon wrote:
> 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: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/OvmfPkg.dec          |   9 +++
>  OvmfPkg/PvScsiDxe/PvScsi.c   | 122 ++++++++++++++++++++++++++++++++++-
>  OvmfPkg/PvScsiDxe/PvScsi.h   |   2 +
>  OvmfPkg/PvScsiDxe/PvScsi.inf |   5 ++
>  4 files changed, 136 insertions(+), 2 deletions(-)
> 
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index 4c5b6511cb97..76ce507e8bd0 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -121,6 +121,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 blow constants
> +  # are used so that scanning the number of devices given by their product
> +  # is still acceptably fast.
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit|64|UINT8|0x40
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit|0|UINT8|0x41
> +

Three cosmetic requests:

(1) s/blow/below/


(2) in the comment block, starting with the second line, please use a

  "#  "

prefix, rather than

  "# "

so that the actual text line up with the first line.


(3) As tokens for the new PCDs, please use 0x36 and 0x37, for keeping
the OVMF token space densely populated.


Regarding the UINT8 type for PcdPvScsiMaxTargetLimit -- the QEMU source
indeed seems to #define PVSCSI_MAX_DEVS as 64, so I guess a UINT8 should
suffice.

>    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 46b430a34a57..76bb361c7c94 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -11,6 +11,7 @@
>  
>  #include <IndustryStandard/Pci.h>
>  #include <IndustryStandard/PvScsi.h>
> +#include <Library/BaseMemoryLib.h>
>  #include <Library/MemoryAllocationLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiLib.h>
> @@ -24,6 +25,30 @@
>  //
>  #define PVSCSI_BINDING_VERSION      0x10
>  
> +//
> +// Ext SCSI Pass Thru utilities
> +//

OK.

> +
> +//
> +// Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
> +// EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
> +//

(4) For leading function comment blocks, please use the following style:

/**
  Blah.
**/

> +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
>  //
> @@ -51,7 +76,54 @@ PvScsiGetNextTargetLun (
>    IN OUT UINT64                                     *Lun
>    )
>  {
> -  return EFI_UNSUPPORTED;
> +  UINT8      *TargetPtr;
> +  UINT8      LastTarget;
> +  PVSCSI_DEV *Dev;
> +
> +  if (Target == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // The TargetPointer input parameter is unnecessarily a pointer-to-pointer
> +  //
> +  TargetPtr = *Target;

(5) Please update the comment: in this function, the subject parameter
is called "Target", not "TargetPointer".

> +
> +  //
> +  // 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
> @@ -110,7 +182,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;

Got the comment right, here :)

> +
> +  //
> +  // 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
> @@ -119,6 +231,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 3940b4c20019..dd3e0c68e6da 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/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
> index 3a8b07872ba3..96bd4e4a9a8b 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.inf
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
> @@ -25,6 +25,7 @@
>    OvmfPkg/OvmfPkg.dec
>  
>  [LibraryClasses]
> +  BaseMemoryLib
>    DebugLib
>    MemoryAllocationLib
>    UefiBootServicesTableLib
> @@ -34,3 +35,7 @@
>  [Protocols]
>    gEfiPciIoProtocolGuid             ## TO_START
>    gEfiExtScsiPassThruProtocolGuid   ## BY_START
> +
> +[Pcd]
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit    ## CONSUMES
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit       ## CONSUMES
> 

(6) Please keep the list of PCDs alphabetically sorted, in this section.


With (1) through (6) addressed:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks,
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 07/17] OvmfPkg/PvScsiDxe: Translate Target & LUN to/from DevicePath
  2020-03-16 15:01 ` [PATCH 07/17] OvmfPkg/PvScsiDxe: Translate Target & LUN to/from DevicePath Liran Alon
@ 2020-03-24 13:36   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 13:36 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:01, Liran Alon wrote:
> Implement EXT_SCSI_PASS_THRU.BuildDevicePath() and
> EXT_SCSI_PASS_THRU.GetTargetLun().
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c | 60 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 58 insertions(+), 2 deletions(-)
> 
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index 76bb361c7c94..f613870e80f2 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -136,7 +136,38 @@ PvScsiBuildDevicePath (
>    IN OUT EFI_DEVICE_PATH_PROTOCOL                   **DevicePath
>    )
>  {
> -  return EFI_UNSUPPORTED;
> +  UINT8             TargetValue;
> +  PVSCSI_DEV        *Dev;
> +  SCSI_DEVICE_PATH  *ScsiDevicePath;
> +
> +  if (DevicePath == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // We only use first byte of target identifer
> +  //
> +  TargetValue = *Target;
> +
> +  Dev = PVSCSI_FROM_PASS_THRU (This);
> +  if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  ScsiDevicePath = AllocatePool (sizeof (*ScsiDevicePath));
> +  if (ScsiDevicePath == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  ScsiDevicePath->Header.Type      = MESSAGING_DEVICE_PATH;
> +  ScsiDevicePath->Header.SubType   = MSG_SCSI_DP;
> +  ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);
> +  ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);
> +  ScsiDevicePath->Pun              = TargetValue;
> +  ScsiDevicePath->Lun              = (UINT16)Lun;
> +
> +  *DevicePath = &ScsiDevicePath->Header;
> +  return EFI_SUCCESS;
>  }
>  
>  STATIC
> @@ -149,7 +180,32 @@ PvScsiGetTargetLun (
>    OUT UINT64                                        *Lun
>    )
>  {
> -  return EFI_UNSUPPORTED;
> +  SCSI_DEVICE_PATH *ScsiDevicePath;
> +  PVSCSI_DEV       *Dev;
> +
> +  if (DevicePath == NULL || Target == NULL || *Target == NULL || Lun == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (DevicePath->Type    != MESSAGING_DEVICE_PATH ||
> +      DevicePath->SubType != MSG_SCSI_DP) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
> +  Dev = PVSCSI_FROM_PASS_THRU (This);
> +  if (ScsiDevicePath->Pun > Dev->MaxTarget ||
> +      ScsiDevicePath->Lun > Dev->MaxLun) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // We only use first byte of target identifer
> +  //
> +  **Target = (UINT8)ScsiDevicePath->Pun;

(1) Please add a ZeroMem() call here, for nulling all the other
(TARGET_MAX_BYTES - 1) bytes in the target array. I think:

  ZeroMem (*Target + 1, TARGET_MAX_BYTES - 1);

For two reasons:

- We should be consistent in the target arrays that we output, and the
functions implemented in the previous patch zero out the unused bytes
(which is nice). We should produce similar target arrays here.

- When investigating SCSI problems, sometimes debug patches have to be
written for the generic (device model-independent) SCSI drivers in edk2.
In those cases, we may hexdump the entire target array. And
indeterminate byte values in the target array should not leak into such
logs -- they could complicate textual comparisons etc.

> +  *Lun = ScsiDevicePath->Lun;
> +
> +  return EFI_SUCCESS;
>  }
>  
>  STATIC
> 

With (1) addressed:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 08/17] OvmfPkg/PvScsiDxe: Open PciIo protocol for later use
  2020-03-16 15:01 ` [PATCH 08/17] OvmfPkg/PvScsiDxe: Open PciIo protocol for later use Liran Alon
@ 2020-03-24 13:47   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 13:47 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:01, Liran Alon wrote:
> This will give us an exclusive access to the PciIo of this device
> after it was started and until is will be stopped.

(1) typo: s/is will be/it will be/

> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c | 29 ++++++++++++++++++++++++++++-
>  OvmfPkg/PvScsiDxe/PvScsi.h |  1 +
>  2 files changed, 29 insertions(+), 1 deletion(-)
> 
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index f613870e80f2..b6a83d73cead 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -410,11 +410,23 @@ PvScsiDriverBindingStart (
>      return EFI_OUT_OF_RESOURCES;
>    }
>  
> -  Status = PvScsiInit (Dev);
> +  Status = gBS->OpenProtocol (
> +                  ControllerHandle,
> +                  &gEfiPciIoProtocolGuid,
> +                  (VOID **)&Dev->PciIo,
> +                  This->DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
>    if (EFI_ERROR (Status)) {
>      goto FreePvScsi;
>    }
>  
> +  Status = PvScsiInit (Dev);
> +  if (EFI_ERROR (Status)) {
> +    goto ClosePciIo;
> +  }
> +
>    //
>    // Setup complete, attempt to export the driver instance's PassThru interface
>    //
> @@ -434,6 +446,14 @@ PvScsiDriverBindingStart (
>  UninitDev:
>    PvScsiUninit (Dev);
>  
> +ClosePciIo:
> +  gBS->CloseProtocol (
> +         ControllerHandle,
> +         &gEfiPciIoProtocolGuid,
> +         This->DriverBindingHandle,
> +         ControllerHandle
> +         );
> +
>  FreePvScsi:
>    FreePool (Dev);
>  
> @@ -479,6 +499,13 @@ PvScsiDriverBindingStop (
>  
>    PvScsiUninit (Dev);
>  
> +  gBS->CloseProtocol (
> +         ControllerHandle,
> +         &gEfiPciIoProtocolGuid,
> +         This->DriverBindingHandle,
> +         ControllerHandle
> +         );
> +
>    FreePool (Dev);
>  
>    return EFI_SUCCESS;
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
> index dd3e0c68e6da..e1e5ae18ebf2 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.h
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.h
> @@ -19,6 +19,7 @@
>  
>  typedef struct {
>    UINT32                          Signature;
> +  EFI_PCI_IO_PROTOCOL             *PciIo;
>    UINT8                           MaxTarget;
>    UINT8                           MaxLun;
>    EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
> 

With (1) fixed up:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks,
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 09/17] OvmfPkg/PvScsiDxe: Backup/Restore PCI attributes on Init/UnInit
  2020-03-16 15:01 ` [PATCH 09/17] OvmfPkg/PvScsiDxe: Backup/Restore PCI attributes on Init/UnInit Liran Alon
@ 2020-03-24 15:14   ` Laszlo Ersek
  2020-03-24 15:35     ` Liran Alon
  0 siblings, 1 reply; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 15:14 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:01, Liran Alon wrote:
> This commit doesn't change semantics.
> It is done as a preparation for future commits which will modify
> PCI attributes.
>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c | 53 +++++++++++++++++++++++++++++++++++++-
>  OvmfPkg/PvScsiDxe/PvScsi.h |  1 +
>  2 files changed, 53 insertions(+), 1 deletion(-)
>
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index b6a83d73cead..92e0f4a98965 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -281,18 +281,59 @@ PvScsiGetNextTarget (
>    return EFI_NOT_FOUND;
>  }
>
> +STATIC
> +EFI_STATUS
> +PvScsiSetPCIAttributes (

(1) Minor wart: should be spelled "PvScsiSetPciAttributes".

> +  IN OUT PVSCSI_DEV *Dev
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  //
> +  // Set saved original PCI attirubtes to invalid value
> +  // such that cleanup logic could determine if it should restore
> +  // PCI attributes or not
> +  //
> +  Dev->OriginalPciAttributes = (UINT64)(-1);
> +
> +  //
> +  // Backup original PCI Attributes
> +  //
> +  Status = Dev->PciIo->Attributes (
> +                         Dev->PciIo,
> +                         EfiPciIoAttributeOperationGet,
> +                         0,
> +                         &Dev->OriginalPciAttributes
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }

No, this is again going in the wrong direction.

(3) Even if we wanted to go in this direction (and we don't), we should
store the  "invalid value" *after* determining failure status. Because,
I can't find any guarantee in the spec that Attributes() does not modify
"Result" on error.

(4) I don't like the assumption that "all-bits-set" is going to be an
invalid attribute mask forever.

(5) Most importantly, we're again mixing error handling styles. This
problem will be more apparent in later patches in the series, but this
is where it starts.

Saving the original PCI attributes, setting the new attributes, and
restoring the original ones, are *not* optional actions. They are
mandatory. Therefore we do not need "tracker" variables or even tracker
values. Whenever any one of those actions can be performed, then it
*must* be performed -- and that fact is deducible purely from the
control flow.

Looking at the "PvScsi.c" source file at the end of this series, this is
the (partial) call tree that I see:

  PvScsiDriverBindingStart
   PvScsiInit
     PvScsiSetPCIAttributes
     PvScsiWriteCmdDesc (PVSCSI_CMD_ADAPTER_RESET)
     PvScsiInitRings
     PvScsiAllocateSharedPages

Unfortunately, the PvScsiInit() function fails to roll back any of those
construction steps on error. In particular:

- the shared pages are not released,
- the rings are not un-inited,
- the original attributes are not restored.

This causes a bunch of leaks. Also, confusion on the normal teardown
path (initiated from Stop()), as evidenced by the "sentinel" value for
"OriginalPciAttributes".

You need to follow the exact same cascading error handling pattern in
*every* construction function that you follow in
PvScsiDriverBindingStart(). PvScsiInit() *in itself* should be atomic,
meaning that *either* all of its actions should succeed, *or* it should
roll back all partically completed construction steps.

For example, if the PvScsiAllocateSharedPages() call fails in
PvScsiInit(), then the rings need to be uninited, and the original PCI
attributes need to be restored, before we exit PvScsiInit() with a
failure status. Because, in this case (i.e., when PvScsiInit() fails),
PvScsiDriverBindingStart() will also take the error path, and we will
never touch the PCI attributes or the rings ever again.

*Consequently* (and I'm getting to my main point here, at long last), in
the PvScsiUninit() function, you can *unconditionally* restore the
original PCI attributes, because you know that, at that location, the
original attributes will have been saved. Whenever that is not the case,
then PvScsiUninit() is not reached!

This is not complicated. Simply follow the pattern rigorously in *every*
function:

- construct and allocate resources gradually,

- if the very first such step fails, return directly,

- if any one of the subsequent steps fails, jump to an error handling
  label matching the last successful allocation / construction step,

- error handling labels should mirror the construction steps in reverse
  order, and they should release the corresponding (partially
  allocated/constructed) resources,

- every function should be atomic: fully successful, or completely
  rolled back,

- any given "teardown" function should be almost identical to the error
  path of the corresponding "init" function, with two small differences:
  (a) there should be no labels, (b) the final construction step of the
  "init" function should be rolled back too, namely as the first action
  in the "teardown" function.

The beauty of this approach is that you don't even have to *think* about
managing resources. It is entirely mechanical.

Of course there are exceptions to this pattern, such as:
- ownership transfer,
- optionally used resources.

They do need special handling, but they are exceptions, not the norm.

So, let me proceed to pin-pointing the problem in this specific patch --
see bullet (6) below:

> +
> +  return EFI_SUCCESS;
> +}
> +
>  STATIC
>  EFI_STATUS
>  PvScsiInit (
>    IN OUT PVSCSI_DEV *Dev
>    )
>  {
> +  EFI_STATUS Status;
> +
>    //
>    // Init configuration
>    //
>    Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
>    Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
>
> +  //
> +  // Set PCI Attributes
> +  //
> +  Status = PvScsiSetPCIAttributes (Dev);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +

Note that, if PvScsiSetPCIAttributes() fails -- and so we couldn't save
a valid value to the "OriginalPciAttributes" field --, we return from
PvScsiInit() with an error code, here.

That causes PvScsiDriverBindingStart() to jump to the "ClosePciIo"
label, and ultimately propagate the error status outwards. The driver's
interaction with the controller handle is done, then.

Subsequently, PvScsiUninit() will *never* be reached, because the system
is never going to invoke PvScsiDriverBindingStop(), given that Start()
failed in the first place. Therefore:

>    //
>    // Populate the exported interface's attributes
>    //
> @@ -331,7 +372,17 @@ PvScsiUninit (
>    IN OUT PVSCSI_DEV *Dev
>    )
>  {
> -  // Currently nothing to do here
> +  //
> +  // Restore PCI Attributes
> +  //
> +  if (Dev->OriginalPciAttributes != (UINT64)(-1)) {

(6) This condition is superfluous here. Whenever it is reached, it
always evaluates to 1.

Specifically:

- If PvScsiUninit() is being called from under the "UninitDev" label in
  PvScsiDriverBindingStart(), then PvScsiInit() has succeeded. That
  means PvScsiSetPCIAttributes() was successful too.

- If PvScsiUninit() is being called from PvScsiDriverBindingStop(), then
  PvScsiDriverBindingStart() succeeded. That implies PvScsiInit()
  succeeded too.


Additionally, I think you are needlessly complicating the driver by
pushing the PCI attribute manipulation down to a helper function
(PvScsiSetPCIAttributes) *without* mirroring that helper function with
another helper function on the "teardown" path.

Because this way, the PCI attribute restoration is flattened into
PvScsiUninit() -- and that *does* make things harder to reason about,
because you don't have a matching path to mirror, from PvScsiInit().

Let me emphasize: the needless complication is not that
PvScsiSetPciAttributes() exists. The complication is that a counterpart
function does not exist.

In summary, I recommend the following (incremental) updates to this
patch, expressed as code:

> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index 92e0f4a98965..2732aaa9b471 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -283,19 +283,12 @@ PvScsiGetNextTarget (
>
>  STATIC
>  EFI_STATUS
> -PvScsiSetPCIAttributes (
> +PvScsiSetPciAttributes (
>    IN OUT PVSCSI_DEV *Dev
>    )
>  {
>    EFI_STATUS Status;
>
> -  //
> -  // Set saved original PCI attirubtes to invalid value
> -  // such that cleanup logic could determine if it should restore
> -  // PCI attributes or not
> -  //
> -  Dev->OriginalPciAttributes = (UINT64)(-1);
> -
>    //
>    // Backup original PCI Attributes
>    //
> @@ -312,6 +305,20 @@ PvScsiSetPCIAttributes (
>    return EFI_SUCCESS;
>  }
>
> +STATIC
> +VOID
> +PvScsiRestorePciAttributes (
> +  IN PVSCSI_DEV *Dev
> +  )
> +{
> +  Dev->PciIo->Attributes (
> +                Dev->PciIo,
> +                EfiPciIoAttributeOperationSet,
> +                Dev->OriginalPciAttributes,
> +                NULL
> +                );
> +}
> +
>  STATIC
>  EFI_STATUS
>  PvScsiInit (
> @@ -329,10 +336,15 @@ PvScsiInit (
>    //
>    // Set PCI Attributes
>    //
> -  Status = PvScsiSetPCIAttributes (Dev);
> +  Status = PvScsiSetPciAttributes (Dev);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> +  //
> +  // NOTE: if any steps fail below, we need to introduce a new error handling
> +  // label called "RestorePciAttributes", and call PvScsiRestorePciAttributes()
> +  // there.
> +  //
>
>    //
>    // Populate the exported interface's attributes
> @@ -372,17 +384,7 @@ PvScsiUninit (
>    IN OUT PVSCSI_DEV *Dev
>    )
>  {
> -  //
> -  // Restore PCI Attributes
> -  //
> -  if (Dev->OriginalPciAttributes != (UINT64)(-1)) {
> -    Dev->PciIo->Attributes (
> -                  Dev->PciIo,
> -                  EfiPciIoAttributeOperationSet,
> -                  Dev->OriginalPciAttributes,
> -                  NULL
> -                  );
> -  }
> +  PvScsiRestorePciAttributes (Dev);
>  }
>
>  //

Because, that will make for the following *cumulative* patch (replacing
the current patch):

> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
> index e1e5ae18ebf2..5f611dbbc98c 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.h
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.h
> @@ -20,6 +20,7 @@
>  typedef struct {
>    UINT32                          Signature;
>    EFI_PCI_IO_PROTOCOL             *PciIo;
> +  UINT64                          OriginalPciAttributes;
>    UINT8                           MaxTarget;
>    UINT8                           MaxLun;
>    EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index b6a83d73cead..2732aaa9b471 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -281,18 +281,71 @@ PvScsiGetNextTarget (
>    return EFI_NOT_FOUND;
>  }
>
> +STATIC
> +EFI_STATUS
> +PvScsiSetPciAttributes (
> +  IN OUT PVSCSI_DEV *Dev
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  //
> +  // Backup original PCI Attributes
> +  //
> +  Status = Dev->PciIo->Attributes (
> +                         Dev->PciIo,
> +                         EfiPciIoAttributeOperationGet,
> +                         0,
> +                         &Dev->OriginalPciAttributes
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +STATIC
> +VOID
> +PvScsiRestorePciAttributes (
> +  IN PVSCSI_DEV *Dev
> +  )
> +{
> +  Dev->PciIo->Attributes (
> +                Dev->PciIo,
> +                EfiPciIoAttributeOperationSet,
> +                Dev->OriginalPciAttributes,
> +                NULL
> +                );
> +}
> +
>  STATIC
>  EFI_STATUS
>  PvScsiInit (
>    IN OUT PVSCSI_DEV *Dev
>    )
>  {
> +  EFI_STATUS Status;
> +
>    //
>    // Init configuration
>    //
>    Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
>    Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
>
> +  //
> +  // Set PCI Attributes
> +  //
> +  Status = PvScsiSetPciAttributes (Dev);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +  //
> +  // NOTE: if any steps fail below, we need to introduce a new error handling
> +  // label called "RestorePciAttributes", and call PvScsiRestorePciAttributes()
> +  // there.
> +  //
> +
>    //
>    // Populate the exported interface's attributes
>    //
> @@ -331,7 +384,7 @@ PvScsiUninit (
>    IN OUT PVSCSI_DEV *Dev
>    )
>  {
> -  // Currently nothing to do here
> +  PvScsiRestorePciAttributes (Dev);
>  }
>
>  //

Note the key pattern: whenever we add a new construction / allocation
step to any "init" function (such as PvScsiInit()), we add the matching
"undo" step in *two* spots:

- on the error path in the same "init" function, in case a subsequent
  step fails,

- in the "teardown" counterpart of the "init" function (such as
  PvScsiUninit()).

I'm going to stop reviewing this iteration now; please rework the rest
of the series for v2 with this resource management pattern.

Thanks!
Laszlo

On 03/16/20 16:01, Liran Alon wrote:

> +    Dev->PciIo->Attributes (
> +                  Dev->PciIo,
> +                  EfiPciIoAttributeOperationSet,
> +                  Dev->OriginalPciAttributes,
> +                  NULL
> +                  );
> +  }
>  }
>
>  //
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
> index e1e5ae18ebf2..5f611dbbc98c 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.h
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.h
> @@ -20,6 +20,7 @@
>  typedef struct {
>    UINT32                          Signature;
>    EFI_PCI_IO_PROTOCOL             *PciIo;
> +  UINT64                          OriginalPciAttributes;
>    UINT8                           MaxTarget;
>    UINT8                           MaxLun;
>    EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
>


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 10/17] OvmfPkg/PvScsiDxe: Enable IOSpace & Bus-Mastering in PCI attributes
  2020-03-16 15:01 ` [PATCH 10/17] OvmfPkg/PvScsiDxe: Enable IOSpace & Bus-Mastering in PCI attributes Liran Alon
@ 2020-03-24 15:22   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 15:22 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

Okay I can make a quick comment on this patch too, and on patch#17 too.

(And I appreciate *very much* that you have broken up this work into
small patches like this, because it allows me to do a thorough review
with reasonable effort!)

On 03/16/20 16:01, Liran Alon wrote:
> Enable IOSpace & Bus-Mastering PCI attributes when device is started.
> Note that original PCI attributes is restored when device is stopped.

(1) typo: s/attributes is/attributes are/

> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index 92e0f4a98965..ff6b50b7020f 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -309,6 +309,20 @@ PvScsiSetPCIAttributes (
>      return Status;
>    }
>  
> +  //
> +  // Enable IOSpace & Bus-Mastering
> +  //
> +  Status = Dev->PciIo->Attributes (
> +                         Dev->PciIo,
> +                         EfiPciIoAttributeOperationEnable,
> +                         (EFI_PCI_IO_ATTRIBUTE_MEMORY |
> +                          EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
> +                         NULL
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
>    return EFI_SUCCESS;
>  }
>  
> 

(2) The patch looks OK, but the "IOSpace" comment is wrong. "IOSpace"
would be appropriate for EFI_PCI_IO_ATTRIBUTE_IO (IO ports). Please say
"MMIO space" in the comment.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 17/17] OvmfPkg/PvScsiDxe: Enable device 64-bit DMA addresses
  2020-03-16 15:01 ` [PATCH 17/17] OvmfPkg/PvScsiDxe: Enable device 64-bit DMA addresses Liran Alon
@ 2020-03-24 15:26   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 15:26 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:01, Liran Alon wrote:
> Enable PCI dual-address cycle attribute to signal device supports
> 64-bit DMA addresses.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index 33167c177b42..e673ed8ba6a0 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -814,6 +814,27 @@ PvScsiSetPCIAttributes (
>      return Status;
>    }
>  
> +  //
> +  // Signal device supports 64-bit DMA addresses
> +  //
> +  Status = Dev->PciIo->Attributes (
> +                         Dev->PciIo,
> +                         EfiPciIoAttributeOperationEnable,
> +                         EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
> +                         NULL
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    //
> +    // Warn user device will only be using 32-bit DMA addresses.
> +    //
> +    // Note that this does not prevent device/driver from working
> +    // and therefore we only warn and continue as usual.
> +    //
> +    DEBUG ((DEBUG_WARN,
> +            "%a: failed to enable 64-bit DMA addresses\n",
> +            __FUNCTION__));
> +  }
> +
>    return EFI_SUCCESS;
>  }
>  
> 

I've consulted the UEFI spec, and it indeed makes sense to attempt
enabling this attribute in a separate step. So, good idea.

Regarding the DEBUG message:

(1) The indentation of the 2nd and 3rd argument is incorrect. Please pick:

    DEBUG ((DEBUG_WARN, "%a: failed to enable 64-bit DMA addresses\n",
      __FUNCTION__));

or:

    DEBUG ((
      DEBUG_WARN,
      "%a: failed to enable 64-bit DMA addresses\n",
      __FUNCTION__
      ));

Thanks!
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 11/17] OvmfPkg/PvScsiDxe: Define device interface structures and constants
  2020-03-16 15:01 ` [PATCH 11/17] OvmfPkg/PvScsiDxe: Define device interface structures and constants Liran Alon
@ 2020-03-24 15:35   ` Laszlo Ersek
  2020-03-24 16:34     ` Laszlo Ersek
  0 siblings, 1 reply; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 15:35 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:01, Liran Alon wrote:
> These definitions will be used by the following commits to complete the
> implementation of PVSCSI device driver.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/Include/IndustryStandard/PvScsi.h | 162 ++++++++++++++++++++++
>  1 file changed, 162 insertions(+)
> 
> diff --git a/OvmfPkg/Include/IndustryStandard/PvScsi.h b/OvmfPkg/Include/IndustryStandard/PvScsi.h
> index 004c0af84989..7bb6e664dfcd 100644
> --- a/OvmfPkg/Include/IndustryStandard/PvScsi.h
> +++ b/OvmfPkg/Include/IndustryStandard/PvScsi.h
> @@ -18,4 +18,166 @@
>  #define PCI_VENDOR_ID_VMWARE            (0x15ad)
>  #define PCI_DEVICE_ID_VMWARE_PVSCSI     (0x07c0)
>  
> +//
> +// CDB (Command Descriptor Block) with size above this constant
> +// should be considered out-of-band
> +//
> +#define PVSCSI_CDB_MAX_SIZE         (16)
> +
> +enum PVSCSI_BAR0_OFFSETS {
> +  PVSCSI_REG_OFFSET_COMMAND        =    0x0,
> +  PVSCSI_REG_OFFSET_COMMAND_DATA   =    0x4,
> +  PVSCSI_REG_OFFSET_COMMAND_STATUS =    0x8,
> +  PVSCSI_REG_OFFSET_LAST_STS_0     =  0x100,
> +  PVSCSI_REG_OFFSET_LAST_STS_1     =  0x104,
> +  PVSCSI_REG_OFFSET_LAST_STS_2     =  0x108,
> +  PVSCSI_REG_OFFSET_LAST_STS_3     =  0x10c,
> +  PVSCSI_REG_OFFSET_INTR_STATUS    = 0x100c,
> +  PVSCSI_REG_OFFSET_INTR_MASK      = 0x2010,
> +  PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014,
> +  PVSCSI_REG_OFFSET_DEBUG          = 0x3018,
> +  PVSCSI_REG_OFFSET_KICK_RW_IO     = 0x4018,
> +};

(1) In the edk2 coding style, we introduce typedefs (too). So that, in
case we need a variable of this type, we don't have to write

  enum PVSCSI_BAR0_OFFSETS MyVar;

just

  PVSCSI_BAR0_OFFSETS MyVar;

For example:

typedef enum {
  Blah
} PVSCSI_BAR0_OFFSETS;


(2) Enumeration constants are spelled in CamelCase.

Example: EfiPciIoAttributeOperationGet. (See the
EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION typedef in
"MdePkg/Include/Protocol/PciIo.h".)

> +
> +//
> +// Define Interrupt-Status register flags
> +//
> +#define PVSCSI_INTR_CMPL_0      (1 << 0)
> +#define PVSCSI_INTR_CMPL_1      (1 << 1)

(3) I suggest using the BIT0 and BIT1 macros, rather than open-coding
the shifts.

> +#define PVSCSI_INTR_CMPL_MASK   (PVSCSI_INTR_CMPL_0 | PVSCSI_INTR_CMPL_1)
> +
> +enum PVSCSI_COMMANDS {
> +  PVSCSI_CMD_FIRST             = 0,
> +  PVSCSI_CMD_ADAPTER_RESET     = 1,
> +  PVSCSI_CMD_ISSUE_SCSI        = 2,
> +  PVSCSI_CMD_SETUP_RINGS       = 3,
> +  PVSCSI_CMD_RESET_BUS         = 4,
> +  PVSCSI_CMD_RESET_DEVICE      = 5,
> +  PVSCSI_CMD_ABORT_CMD         = 6,
> +  PVSCSI_CMD_CONFIG            = 7,
> +  PVSCSI_CMD_SETUP_MSG_RING    = 8,
> +  PVSCSI_CMD_DEVICE_UNPLUG     = 9,
> +  PVSCSI_CMD_LAST              = 10
> +};

(4) Same as (1) and (2).

> +
> +#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES    (32)
> +
> +#pragma pack (1)
> +typedef struct {
> +  UINT32 ReqRingNumPages;
> +  UINT32 CmpRingNumPages;
> +  UINT64 RingsStatePPN;
> +  UINT64 ReqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
> +  UINT64 CmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
> +} PVSCSI_CMD_DESC_SETUP_RINGS;
> +#pragma pack ()
> +
> +#define PVSCSI_MAX_CMD_DATA_WORDS   \
> +  (sizeof (PVSCSI_CMD_DESC_SETUP_RINGS) / sizeof (UINT32))
> +
> +#pragma pack (1)
> +typedef struct {
> +  UINT32 ReqProdIdx;
> +  UINT32 ReqConsIdx;
> +  UINT32 ReqNumEntriesLog2;
> +
> +  UINT32 CmpProdIdx;
> +  UINT32 CmpConsIdx;
> +  UINT32 CmpNumEntriesLog2;
> +
> +  UINT8  Pad[104];
> +
> +  UINT32 MsgProdIdx;
> +  UINT32 MsgConsIdx;
> +  UINT32 MsgNumEntriesLog2;
> +} PVSCSI_RINGS_STATE;
> +#pragma pack ()
> +
> +//
> +// Define PVSCSI request descriptor tags
> +//
> +#define PVSCSI_SIMPLE_QUEUE_TAG            (0x20)
> +
> +//
> +// Define PVSCSI request descriptor flags
> +//
> +#define PVSCSI_FLAG_CMD_WITH_SG_LIST       (1 << 0)
> +#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB    (1 << 1)
> +#define PVSCSI_FLAG_CMD_DIR_NONE           (1 << 2)
> +#define PVSCSI_FLAG_CMD_DIR_TOHOST         (1 << 3)
> +#define PVSCSI_FLAG_CMD_DIR_TODEVICE       (1 << 4)

(5) Same as (3).

> +
> +#pragma pack (1)
> +typedef struct {
> +  UINT64 Context;
> +  UINT64 DataAddr;
> +  UINT64 DataLen;
> +  UINT64 SenseAddr;
> +  UINT32 SenseLen;
> +  UINT32 Flags;
> +  UINT8  Cdb[16];
> +  UINT8  CdbLen;
> +  UINT8  Lun[8];
> +  UINT8  Tag;
> +  UINT8  Bus;
> +  UINT8  Target;
> +  UINT8  vCPUHint;
> +  UINT8  Unused[59];
> +} PVSCSI_RING_REQ_DESC;
> +#pragma pack ()
> +
> +//
> +// Host adapter status/error codes
> +//
> +enum PVSCSI_HOST_BUS_ADAPTER_STATUS {
> +   BTSTAT_SUCCESS       = 0x00,  // CCB complete normally with no errors
> +   BTSTAT_LINKED_COMMAND_COMPLETED           = 0x0a,
> +   BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b,
> +   BTSTAT_DATA_UNDERRUN = 0x0c,
> +   BTSTAT_SELTIMEO      = 0x11,  // SCSI selection timeout
> +   BTSTAT_DATARUN       = 0x12,  // Data overrun/underrun
> +   BTSTAT_BUSFREE       = 0x13,  // Unexpected bus free
> +   BTSTAT_INVPHASE      = 0x14,  //
> +                                 // Invalid bus phase or sequence requested by
> +                                 // target
> +                                 //
> +   BTSTAT_LUNMISMATCH   = 0x17,  // Linked CCB has different LUN from first CCB
> +   BTSTAT_SENSFAILED    = 0x1b,  // Auto request sense failed
> +   BTSTAT_TAGREJECT     = 0x1c,  //
> +                                 // SCSI II tagged queueing message rejected by
> +                                 // target
> +                                 //
> +   BTSTAT_BADMSG        = 0x1d,  //
> +                                 // Unsupported message received by the host
> +                                 // adapter
> +                                 //
> +   BTSTAT_HAHARDWARE    = 0x20,  // Host adapter hardware failed
> +   BTSTAT_NORESPONSE    = 0x21,  //
> +                                 // Target did not respond to SCSI ATN sent a
> +                                 // SCSI RST
> +                                 //
> +   BTSTAT_SENTRST       = 0x22,  // Host adapter asserted a SCSI RST
> +   BTSTAT_RECVRST       = 0x23,  // Other SCSI devices asserted a SCSI RST
> +   BTSTAT_DISCONNECT    = 0x24,  //
> +                                 // Target device reconnected improperly
> +                                 // (w/o tag)
> +                                 //
> +   BTSTAT_BUSRESET      = 0x25,  // Host adapter issued BUS device reset
> +   BTSTAT_ABORTQUEUE    = 0x26,  // Abort queue generated
> +   BTSTAT_HASOFTWARE    = 0x27,  // Host adapter software error
> +   BTSTAT_HATIMEOUT     = 0x30,  // Host adapter hardware timeout error
> +   BTSTAT_SCSIPARITY    = 0x34,  // SCSI parity error detected
> +};

(6) Same as (1) and (2).

(7) Please use a PvScsi prefix in these enum constants too.

> +
> +#pragma pack (1)
> +typedef struct {
> +  UINT64 Context;
> +  UINT64 DataLen;
> +  UINT32 SenseLen;
> +  UINT16 HostStatus;
> +  UINT16 ScsiStatus;
> +  UINT32 Pad[2];
> +} PVSCSI_RING_CMP_DESC;
> +#pragma pack ()
> +
>  #endif // __PVSCSI_H_
> 

Thanks!
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 09/17] OvmfPkg/PvScsiDxe: Backup/Restore PCI attributes on Init/UnInit
  2020-03-24 15:14   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-24 15:35     ` Liran Alon
  2020-03-25  1:48       ` Laszlo Ersek
  0 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-24 15:35 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel


On 24/03/2020 17:14, Laszlo Ersek wrote:
> On 03/16/20 16:01, Liran Alon wrote:
> I'm going to stop reviewing this iteration now; please rework the rest
> of the series for v2 with this resource management pattern.
>
> Thanks!
> Laszlo

Thanks for the very detailed review!

I have read all your comments and understood them. I am working on 
creating a v2 patch-series with all these fixed.
As the Init/UnInit logic is the only place in which this resource 
management pattern is done, and as patch-series is split
to small well-defined quite independent patches, can I request that you 
will complete review of all v1 patches?

I will understand if you are too busy for this, but it will allow me to 
take into account all your aggregated comments on v1
to hopefully create a perfect v2 patch-series. As I've tried taking into 
account all the comments you gave on Nikita's series.

Thanks!
-Liran



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init
  2020-03-16 15:01 ` [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init Liran Alon
@ 2020-03-24 16:00   ` Laszlo Ersek
  2020-03-25  1:11     ` Liran Alon
  0 siblings, 1 reply; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 16:00 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

a bit more superficial comments, for now:

On 03/16/20 16:01, Liran Alon wrote:
> The following commits will complete the implementation of
> device initialization.
>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c | 77 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 77 insertions(+)
>
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index ff6b50b7020f..fb2407d2adb2 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -29,6 +29,76 @@
>  // Ext SCSI Pass Thru utilities
>  //
>
> +
> +//
> +// Writes a 32-bit value into BAR0 using MMIO
> +//

(1) Please use the /** **/ comment style for top-level function comment
blocks.

> +STATIC
> +EFI_STATUS
> +PvScsiMmioWrite32 (
> +  IN CONST PVSCSI_DEV   *Dev,
> +  IN UINT64             Offset,
> +  IN UINT32             Value
> +  )
> +{
> +  return Dev->PciIo->Mem.Write(
> +                           Dev->PciIo,
> +                           EfiPciIoWidthUint32,
> +                           0,   // BarIndex

(2) Style improvement: please use the PCI_BAR_IDX0 macro.

> +                           Offset,
> +                           1,   // Count
> +                           &Value
> +                           );
> +}
> +
> +//
> +// Send PVSCSI command to device
> +//

(3) Same as (1).

> +STATIC
> +EFI_STATUS
> +PvScsiWriteCmdDesc (
> +  IN CONST PVSCSI_DEV   *Dev,
> +  IN UINT32             Cmd,
> +  IN VOID               *Desc,
> +  IN UINTN              Length
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINTN      LengthInWords;
> +  UINT8      *WordPtr;
> +  UINT8      *DescEndPtr;
> +  UINT32     Word;
> +
> +  LengthInWords = Length / sizeof (UINT32);

(4) What guarantees that "Length" is a whole multiple of sizeof
(UINT32)?

In this review I have not insisted on including full-blown interface
contracts in the top-level function comment blocks (with @param[in] and
@retval etc). But, for this function, it really is unclear.

> +
> +  if (LengthInWords > PVSCSI_MAX_CMD_DATA_WORDS) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_COMMAND, Cmd);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  WordPtr = Desc;
> +  DescEndPtr = WordPtr + Length;
> +
> +  while (WordPtr != DescEndPtr) {
> +    //
> +    // CopyMem() is used to avoid strict-aliasing issues
> +    //

(5) In edk2, we -- completely intentionally -- disable the enforcement
of the effective type rules / strict aliasing rules. See
"-fno-strict-aliasing" in "BaseTools/Conf/tools_def.template".

> +    CopyMem (&Word, WordPtr, sizeof (UINT32));
> +
> +    Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_COMMAND_DATA, Word);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    WordPtr += sizeof (UINT32);
> +  }
> +
> +  return EFI_SUCCESS;
> +}

(6) I think the open-coded loop is suboptimal -- the PciIo protocol
seems to offer EfiPciIoWidthFifoUint32 for exactly this purpose (=
advance in the memory buffer, while accessing the same offset in the
BAR).

Have you perhaps tried that?

(I can imagine that you ruled it out, due to "Desc" being unaligned. The
UEFI spec does say, "The caller is responsible for any alignment and I/O
width issues which the bus, device, platform, or type of I/O might
require.)

>  //
>  // Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
>  // EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
> @@ -348,6 +418,13 @@ PvScsiInit (
>      return Status;
>    }
>
> +  //
> +  // Reset adapter
> +  //
> +  Status = PvScsiWriteCmdDesc (Dev, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
>    //
>    // Populate the exported interface's attributes
>    //
>

OK, so this ties back to my comments on resource management, under
patch#9.

Let me quote the PvScsiInit() function in full, after the present patch
is applied:

> STATIC
> EFI_STATUS
> PvScsiInit (
>   IN OUT PVSCSI_DEV *Dev
>   )
> {
>   EFI_STATUS Status;
>
>   //
>   // Init configuration
>   //
>   Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
>   Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
>
>   //
>   // Set PCI Attributes
>   //
>   Status = PvScsiSetPCIAttributes (Dev);
>   if (EFI_ERROR (Status)) {
>     return Status;
>   }
>
>   //
>   // Reset adapter
>   //
>   Status = PvScsiWriteCmdDesc (Dev, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
>   if (EFI_ERROR (Status)) {
>     return Status;
>   }

(7) So this is precisely the spot where we have to jump to a new error
handling label -- called "RestorePciAttributes" --, to be introduced at
the end of the function. And we need to call
PvScsiRestorePciAttributes() there.

Otherwise, the original PCI attributes will never be restored.

Thanks!
Laszlo

On 03/16/20 16:01, Liran Alon wrote:
>   //
>   // Populate the exported interface's attributes
>   //
>   Dev->PassThru.Mode             = &Dev->PassThruMode;
>   Dev->PassThru.PassThru         = &PvScsiPassThru;
>   Dev->PassThru.GetNextTargetLun = &PvScsiGetNextTargetLun;
>   Dev->PassThru.BuildDevicePath  = &PvScsiBuildDevicePath;
>   Dev->PassThru.GetTargetLun     = &PvScsiGetTargetLun;
>   Dev->PassThru.ResetChannel     = &PvScsiResetChannel;
>   Dev->PassThru.ResetTargetLun   = &PvScsiResetTargetLun;
>   Dev->PassThru.GetNextTarget    = &PvScsiGetNextTarget;
>
>   //
>   // AdapterId is a target for which no handle will be created during bus scan.
>   // Prevent any conflict with real devices.
>   //
>   Dev->PassThruMode.AdapterId = MAX_UINT32;
>
>   //
>   // Set both physical and logical attributes for non-RAID SCSI channel
>   //
>   Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
>                                  EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
>
>   //
>   // No restriction on transfer buffer alignment
>   //
>   Dev->PassThruMode.IoAlign = 0;
>
>   return EFI_SUCCESS;
> }


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 13/17] OvmfPkg/PvScsiDxe: Setup requests and completions rings
  2020-03-16 15:01 ` [PATCH 13/17] OvmfPkg/PvScsiDxe: Setup requests and completions rings Liran Alon
@ 2020-03-24 16:11   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 16:11 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

really trivial style comments, for now (I intend to look at this in more
detail in v2):

On 03/16/20 16:01, Liran Alon wrote:
> These rings are shared memory buffers between host and device in which
> a cyclic buffer is managed to send request descriptors from host to
> device and receive completion descriptors from device to host.
> 
> Note that because device may be constrained by IOMMU or guest may be run
> under AMD SEV, we make sure to map these rings to device by using
> PciIo->Map().
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c | 235 +++++++++++++++++++++++++++++++++++++
>  OvmfPkg/PvScsiDxe/PvScsi.h |  17 +++
>  2 files changed, 252 insertions(+)
> 
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index fb2407d2adb2..c3f5d38f3d30 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -16,6 +16,7 @@
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiLib.h>
>  #include <Protocol/PciIo.h>
> +#include <Protocol/PciRootBridgeIo.h>
>  
>  #include "PvScsi.h"
>  
> @@ -396,6 +397,209 @@ PvScsiSetPCIAttributes (
>    return EFI_SUCCESS;
>  }
>  
> +STATIC
> +EFI_STATUS
> +PvScsiAllocatePages (
> +  IN PVSCSI_DEV     *Dev,
> +  IN UINTN          Pages,
> +  IN OUT VOID       **HostAddress
> +  )
> +{
> +  return Dev->PciIo->AllocateBuffer (
> +                       Dev->PciIo,
> +                       AllocateAnyPages,
> +                       EfiBootServicesData,
> +                       Pages,
> +                       HostAddress,
> +                       EFI_PCI_ATTRIBUTE_MEMORY_CACHED
> +                       );
> +}
> +
> +STATIC
> +VOID
> +PvScsiFreePages (
> +  IN PVSCSI_DEV     *Dev,
> +  IN UINTN          Pages,
> +  IN VOID           *HostAddress
> +  )
> +{
> +  Dev->PciIo->FreeBuffer (
> +                Dev->PciIo,
> +                Pages,
> +                HostAddress
> +                );
> +}
> +
> +STATIC
> +EFI_STATUS
> +PvScsiMapBuffer (
> +  IN PVSCSI_DEV                     *Dev,
> +  IN EFI_PCI_IO_PROTOCOL_OPERATION  PciIoOperation,
> +  IN VOID                           *HostAddress,
> +  IN UINTN                          NumberOfBytes,
> +  OUT PVSCSI_DMA_DESC               *DmaDesc
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINTN      BytesMapped;
> +
> +  BytesMapped = NumberOfBytes;
> +  Status = Dev->PciIo->Map (
> +                         Dev->PciIo,
> +                         PciIoOperation,
> +                         HostAddress,
> +                         &BytesMapped,
> +                         &DmaDesc->DeviceAddress,
> +                         &DmaDesc->Mapping
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  if (BytesMapped != NumberOfBytes) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Unmap;
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +Unmap:
> +  Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
> +  DmaDesc->Mapping = NULL;
> +
> +  return Status;
> +}
> +
> +STATIC
> +VOID
> +PvScsiUnmapBuffer (
> +  IN PVSCSI_DEV                 *Dev,
> +  IN OUT PVSCSI_DMA_DESC        *DmaDesc)
> +{
> +  Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);
> +}
> +
> +STATIC
> +EFI_STATUS
> +PvScsiAllocateSharedPages (
> +  IN PVSCSI_DEV                     *Dev,
> +  IN UINTN                          Pages,
> +  IN EFI_PCI_IO_PROTOCOL_OPERATION  PciIoOperation,
> +  OUT VOID                          **HostAddress,
> +  OUT PVSCSI_DMA_DESC               *DmaDesc
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  *HostAddress = NULL;
> +  DmaDesc->Mapping = NULL;
> +
> +  Status = PvScsiAllocatePages (Dev, Pages, HostAddress);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Status = PvScsiMapBuffer (
> +             Dev,
> +             PciIoOperation,
> +             *HostAddress,
> +             Pages * EFI_PAGE_SIZE,

(1) Please use EFI_PAGES_TO_SIZE(); it's more idiomatic. (The argument
should have type UINTN -- "Pages" is already UINTN, so that's good.)

> +             DmaDesc
> +             );
> +  if (EFI_ERROR (Status)) {
> +    goto FreePages;
> +  }
> +
> +  return EFI_SUCCESS;
> +
> +FreePages:
> +  PvScsiFreePages (Dev, Pages, *HostAddress);
> +  *HostAddress = NULL;
> +
> +  return Status;
> +}
> +
> +STATIC
> +VOID
> +PvScsiFreeSharedPages (
> +  IN PVSCSI_DEV                     *Dev,
> +  IN UINTN                          Pages,
> +  IN OUT VOID                       **HostAddress,
> +  IN OUT PVSCSI_DMA_DESC            *DmaDesc
> +  )
> +{
> +  if (*HostAddress) {
> +      if (DmaDesc->Mapping) {
> +        PvScsiUnmapBuffer (Dev, DmaDesc);
> +        DmaDesc->Mapping = NULL;
> +      }
> +
> +      PvScsiFreePages (Dev, Pages, *HostAddress);
> +      *HostAddress = NULL;
> +  }
> +}
> +
> +STATIC
> +EFI_STATUS
> +PvScsiInitRings (
> +  IN OUT PVSCSI_DEV *Dev
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  PVSCSI_CMD_DESC_SETUP_RINGS Cmd;
> +
> +  Status = PvScsiAllocateSharedPages (
> +             Dev,
> +             1,
> +             EfiPciIoOperationBusMasterCommonBuffer,
> +             (VOID **)&Dev->RingDesc.RingState,
> +             &Dev->RingDesc.RingStateDmaDesc
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +  ZeroMem (Dev->RingDesc.RingState, EFI_PAGE_SIZE);
> +
> +  Status = PvScsiAllocateSharedPages (
> +             Dev,
> +             1,
> +             EfiPciIoOperationBusMasterCommonBuffer,
> +             (VOID **)&Dev->RingDesc.RingReqs,
> +             &Dev->RingDesc.RingReqsDmaDesc
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +  ZeroMem (Dev->RingDesc.RingReqs, EFI_PAGE_SIZE);
> +
> +  Status = PvScsiAllocateSharedPages (
> +             Dev,
> +             1,
> +             EfiPciIoOperationBusMasterCommonBuffer,
> +             (VOID **)&Dev->RingDesc.RingCmps,
> +             &Dev->RingDesc.RingCmpsDmaDesc
> +             );
> +  if (EFI_ERROR (Status)) {
> +      return Status;
> +  }
> +  ZeroMem (Dev->RingDesc.RingCmps, EFI_PAGE_SIZE);
> +
> +  ZeroMem (&Cmd, sizeof Cmd);
> +  Cmd.ReqRingNumPages = 1;
> +  Cmd.CmpRingNumPages = 1;
> +  Cmd.RingsStatePPN =
> +        ((UINT64) Dev->RingDesc.RingStateDmaDesc.DeviceAddress) >>
> +        EFI_PAGE_SHIFT;
> +  Cmd.ReqRingPPNs[0] =
> +        ((UINT64) Dev->RingDesc.RingReqsDmaDesc.DeviceAddress) >>
> +        EFI_PAGE_SHIFT;
> +  Cmd.CmpRingPPNs[0] =
> +        ((UINT64) Dev->RingDesc.RingCmpsDmaDesc.DeviceAddress) >>
> +        EFI_PAGE_SHIFT;

(2) Edk2 allows the << and >> operators when the LHS operand is not
wider than UINTN. For shifting UINT64, please call the LShiftU64() and
RShiftU64() functions from BaseLib.

> +
> +  return PvScsiWriteCmdDesc(Dev, PVSCSI_CMD_SETUP_RINGS, &Cmd, sizeof Cmd);
> +}
> +
>  STATIC
>  EFI_STATUS
>  PvScsiInit (
> @@ -425,6 +629,15 @@ PvScsiInit (
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> +
> +  //
> +  // Init PVSCSI rings
> +  //
> +  Status = PvScsiInitRings (Dev);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +

(3) Again, we should jump to "RestorePciAttributes" here.

(More careful review postponed to v2.)

Thanks
Laszlo

>    //
>    // Populate the exported interface's attributes
>    //
> @@ -463,6 +676,28 @@ PvScsiUninit (
>    IN OUT PVSCSI_DEV *Dev
>    )
>  {
> +  //
> +  // Free PVSCSI rings
> +  //
> +  PvScsiFreeSharedPages (
> +    Dev,
> +    1,
> +    (VOID **)&Dev->RingDesc.RingCmps,
> +    &Dev->RingDesc.RingCmpsDmaDesc
> +    );
> +  PvScsiFreeSharedPages (
> +    Dev,
> +    1,
> +    (VOID **)&Dev->RingDesc.RingReqs,
> +    &Dev->RingDesc.RingReqsDmaDesc
> +    );
> +  PvScsiFreeSharedPages (
> +    Dev,
> +    1,
> +    (VOID **)&Dev->RingDesc.RingState,
> +    &Dev->RingDesc.RingStateDmaDesc
> +    );
> +
>    //
>    // Restore PCI Attributes
>    //
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
> index 5f611dbbc98c..6d23b6e1eccf 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.h
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.h
> @@ -15,12 +15,29 @@
>  #include <Library/DebugLib.h>
>  #include <Protocol/ScsiPassThruExt.h>
>  
> +typedef struct {
> +  EFI_PHYSICAL_ADDRESS DeviceAddress;
> +  VOID                 *Mapping;
> +} PVSCSI_DMA_DESC;
> +
> +typedef struct {
> +  PVSCSI_RINGS_STATE   *RingState;
> +  PVSCSI_DMA_DESC      RingStateDmaDesc;
> +
> +  PVSCSI_RING_REQ_DESC *RingReqs;
> +  PVSCSI_DMA_DESC      RingReqsDmaDesc;
> +
> +  PVSCSI_RING_CMP_DESC *RingCmps;
> +  PVSCSI_DMA_DESC      RingCmpsDmaDesc;
> +} PVSCSI_RING_DESC;
> +
>  #define PVSCSI_SIG SIGNATURE_32 ('P', 'S', 'C', 'S')
>  
>  typedef struct {
>    UINT32                          Signature;
>    EFI_PCI_IO_PROTOCOL             *PciIo;
>    UINT64                          OriginalPciAttributes;
> +  PVSCSI_RING_DESC                RingDesc;
>    UINT8                           MaxTarget;
>    UINT8                           MaxLun;
>    EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
> 


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 14/17] OvmfPkg/PvScsiDxe: Introduce DMA communication buffer
  2020-03-16 15:01 ` [PATCH 14/17] OvmfPkg/PvScsiDxe: Introduce DMA communication buffer Liran Alon
@ 2020-03-24 16:13   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 16:13 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:01, Liran Alon wrote:
> In case device is constrained by IOMMU or guest is running under AMD SEV,
> input/output buffers provided to device (DataBuffer and SenseData) needs
> to be explicitly mapped to device by PciIo->Map().
> 
> To avoid the overhead of mapping/unmapping the DataBuffer and SenseData
> to the device for every SCSI requst (And to simplify code), introduce a
> single DMA communication buffer that will be mapped to device on
> initialization. When a SCSI request needs to be sent to device, the
> DataBuffer and SenseData will be copied from/to the DMA communication
> buffer as required. This will be done by the following commits.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c | 24 ++++++++++++++++++++++++
>  OvmfPkg/PvScsiDxe/PvScsi.h | 10 ++++++++++
>  2 files changed, 34 insertions(+)
> 
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index c3f5d38f3d30..e48929bf044c 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -638,6 +638,20 @@ PvScsiInit (
>      return Status;
>    }
>  
> +  //
> +  // Allocate DMA communication buffer
> +  //
> +  Status = PvScsiAllocateSharedPages (
> +             Dev,
> +             EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
> +             EfiPciIoOperationBusMasterCommonBuffer,
> +             (VOID **)&Dev->DmaBuf,
> +             &Dev->DmaBufDmaDesc
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +

(1) Superficial review:

in my set of "resource management comments", just pointing out that here
we both fail to restore the original PCI attributes, and leak the rings.

More careful review of this patch slated for v2.

Thanks
Laszlo

>    //
>    // Populate the exported interface's attributes
>    //
> @@ -676,6 +690,16 @@ PvScsiUninit (
>    IN OUT PVSCSI_DEV *Dev
>    )
>  {
> +  //
> +  // Free DMA communication buffer
> +  //
> +  PvScsiFreeSharedPages (
> +    Dev,
> +    EFI_SIZE_TO_PAGES (sizeof (*Dev->DmaBuf)),
> +    (VOID **)&Dev->DmaBuf,
> +    &Dev->DmaBufDmaDesc
> +    );
> +
>    //
>    // Free PVSCSI rings
>    //
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
> index 6d23b6e1eccf..7f91d70fec79 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.h
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.h
> @@ -31,6 +31,11 @@ typedef struct {
>    PVSCSI_DMA_DESC      RingCmpsDmaDesc;
>  } PVSCSI_RING_DESC;
>  
> +typedef struct {
> +  UINT8     SenseData[MAX_UINT8];
> +  UINT8     Data[0x2000];
> +} PVSCSI_DMA_BUFFER;
> +
>  #define PVSCSI_SIG SIGNATURE_32 ('P', 'S', 'C', 'S')
>  
>  typedef struct {
> @@ -38,6 +43,8 @@ typedef struct {
>    EFI_PCI_IO_PROTOCOL             *PciIo;
>    UINT64                          OriginalPciAttributes;
>    PVSCSI_RING_DESC                RingDesc;
> +  PVSCSI_DMA_BUFFER               *DmaBuf;
> +  PVSCSI_DMA_DESC                 DmaBufDmaDesc;
>    UINT8                           MaxTarget;
>    UINT8                           MaxLun;
>    EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
> @@ -47,4 +54,7 @@ typedef struct {
>  #define PVSCSI_FROM_PASS_THRU(PassThruPointer) \
>    CR (PassThruPointer, PVSCSI_DEV, PassThru, PVSCSI_SIG)
>  
> +#define PVSCSI_DMA_BUF_DEV_ADDR(Dev, MemberName) \
> +  (Dev->DmaBufDmaDesc.DeviceAddress + OFFSET_OF(PVSCSI_DMA_BUFFER, MemberName))
> +
>  #endif // __PVSCSI_DXE_H_
> 


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 11/17] OvmfPkg/PvScsiDxe: Define device interface structures and constants
  2020-03-24 15:35   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-24 16:34     ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 16:34 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/24/20 16:35, Laszlo Ersek wrote:
> On 03/16/20 16:01, Liran Alon wrote:
>> These definitions will be used by the following commits to complete the
>> implementation of PVSCSI device driver.
>>
>> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
>> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
>> Signed-off-by: Liran Alon <liran.alon@oracle.com>
>> ---
>>  OvmfPkg/Include/IndustryStandard/PvScsi.h | 162 ++++++++++++++++++++++
>>  1 file changed, 162 insertions(+)
>>
>> diff --git a/OvmfPkg/Include/IndustryStandard/PvScsi.h b/OvmfPkg/Include/IndustryStandard/PvScsi.h
>> index 004c0af84989..7bb6e664dfcd 100644
>> --- a/OvmfPkg/Include/IndustryStandard/PvScsi.h
>> +++ b/OvmfPkg/Include/IndustryStandard/PvScsi.h
>> @@ -18,4 +18,166 @@
>>  #define PCI_VENDOR_ID_VMWARE            (0x15ad)
>>  #define PCI_DEVICE_ID_VMWARE_PVSCSI     (0x07c0)
>>  
>> +//
>> +// CDB (Command Descriptor Block) with size above this constant
>> +// should be considered out-of-band
>> +//
>> +#define PVSCSI_CDB_MAX_SIZE         (16)
>> +
>> +enum PVSCSI_BAR0_OFFSETS {
>> +  PVSCSI_REG_OFFSET_COMMAND        =    0x0,
>> +  PVSCSI_REG_OFFSET_COMMAND_DATA   =    0x4,
>> +  PVSCSI_REG_OFFSET_COMMAND_STATUS =    0x8,
>> +  PVSCSI_REG_OFFSET_LAST_STS_0     =  0x100,
>> +  PVSCSI_REG_OFFSET_LAST_STS_1     =  0x104,
>> +  PVSCSI_REG_OFFSET_LAST_STS_2     =  0x108,
>> +  PVSCSI_REG_OFFSET_LAST_STS_3     =  0x10c,
>> +  PVSCSI_REG_OFFSET_INTR_STATUS    = 0x100c,
>> +  PVSCSI_REG_OFFSET_INTR_MASK      = 0x2010,
>> +  PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014,
>> +  PVSCSI_REG_OFFSET_DEBUG          = 0x3018,
>> +  PVSCSI_REG_OFFSET_KICK_RW_IO     = 0x4018,
>> +};
> 
> (1) In the edk2 coding style, we introduce typedefs (too). So that, in
> case we need a variable of this type, we don't have to write
> 
>   enum PVSCSI_BAR0_OFFSETS MyVar;
> 
> just
> 
>   PVSCSI_BAR0_OFFSETS MyVar;
> 
> For example:
> 
> typedef enum {
>   Blah
> } PVSCSI_BAR0_OFFSETS;
> 
> 
> (2) Enumeration constants are spelled in CamelCase.
> 
> Example: EfiPciIoAttributeOperationGet. (See the
> EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION typedef in
> "MdePkg/Include/Protocol/PciIo.h".)
> 
>> +
>> +//
>> +// Define Interrupt-Status register flags
>> +//
>> +#define PVSCSI_INTR_CMPL_0      (1 << 0)
>> +#define PVSCSI_INTR_CMPL_1      (1 << 1)
> 
> (3) I suggest using the BIT0 and BIT1 macros, rather than open-coding
> the shifts.
> 
>> +#define PVSCSI_INTR_CMPL_MASK   (PVSCSI_INTR_CMPL_0 | PVSCSI_INTR_CMPL_1)
>> +
>> +enum PVSCSI_COMMANDS {
>> +  PVSCSI_CMD_FIRST             = 0,
>> +  PVSCSI_CMD_ADAPTER_RESET     = 1,
>> +  PVSCSI_CMD_ISSUE_SCSI        = 2,
>> +  PVSCSI_CMD_SETUP_RINGS       = 3,
>> +  PVSCSI_CMD_RESET_BUS         = 4,
>> +  PVSCSI_CMD_RESET_DEVICE      = 5,
>> +  PVSCSI_CMD_ABORT_CMD         = 6,
>> +  PVSCSI_CMD_CONFIG            = 7,
>> +  PVSCSI_CMD_SETUP_MSG_RING    = 8,
>> +  PVSCSI_CMD_DEVICE_UNPLUG     = 9,
>> +  PVSCSI_CMD_LAST              = 10
>> +};
> 
> (4) Same as (1) and (2).
> 
>> +
>> +#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES    (32)
>> +
>> +#pragma pack (1)
>> +typedef struct {
>> +  UINT32 ReqRingNumPages;
>> +  UINT32 CmpRingNumPages;
>> +  UINT64 RingsStatePPN;
>> +  UINT64 ReqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
>> +  UINT64 CmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES];
>> +} PVSCSI_CMD_DESC_SETUP_RINGS;
>> +#pragma pack ()
>> +
>> +#define PVSCSI_MAX_CMD_DATA_WORDS   \
>> +  (sizeof (PVSCSI_CMD_DESC_SETUP_RINGS) / sizeof (UINT32))
>> +
>> +#pragma pack (1)
>> +typedef struct {
>> +  UINT32 ReqProdIdx;
>> +  UINT32 ReqConsIdx;
>> +  UINT32 ReqNumEntriesLog2;
>> +
>> +  UINT32 CmpProdIdx;
>> +  UINT32 CmpConsIdx;
>> +  UINT32 CmpNumEntriesLog2;
>> +
>> +  UINT8  Pad[104];
>> +
>> +  UINT32 MsgProdIdx;
>> +  UINT32 MsgConsIdx;
>> +  UINT32 MsgNumEntriesLog2;
>> +} PVSCSI_RINGS_STATE;
>> +#pragma pack ()
>> +
>> +//
>> +// Define PVSCSI request descriptor tags
>> +//
>> +#define PVSCSI_SIMPLE_QUEUE_TAG            (0x20)
>> +
>> +//
>> +// Define PVSCSI request descriptor flags
>> +//
>> +#define PVSCSI_FLAG_CMD_WITH_SG_LIST       (1 << 0)
>> +#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB    (1 << 1)
>> +#define PVSCSI_FLAG_CMD_DIR_NONE           (1 << 2)
>> +#define PVSCSI_FLAG_CMD_DIR_TOHOST         (1 << 3)
>> +#define PVSCSI_FLAG_CMD_DIR_TODEVICE       (1 << 4)
> 
> (5) Same as (3).
> 
>> +
>> +#pragma pack (1)
>> +typedef struct {
>> +  UINT64 Context;
>> +  UINT64 DataAddr;
>> +  UINT64 DataLen;
>> +  UINT64 SenseAddr;
>> +  UINT32 SenseLen;
>> +  UINT32 Flags;
>> +  UINT8  Cdb[16];
>> +  UINT8  CdbLen;
>> +  UINT8  Lun[8];
>> +  UINT8  Tag;
>> +  UINT8  Bus;
>> +  UINT8  Target;
>> +  UINT8  vCPUHint;

(8) This should be spelled "VcpuHint", because:

- CamelCase
- the 2nd and further letters in sub-acronyms are lowercased in edk2.

Thanks
Laszlo

>> +  UINT8  Unused[59];
>> +} PVSCSI_RING_REQ_DESC;
>> +#pragma pack ()
>> +
>> +//
>> +// Host adapter status/error codes
>> +//
>> +enum PVSCSI_HOST_BUS_ADAPTER_STATUS {
>> +   BTSTAT_SUCCESS       = 0x00,  // CCB complete normally with no errors
>> +   BTSTAT_LINKED_COMMAND_COMPLETED           = 0x0a,
>> +   BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b,
>> +   BTSTAT_DATA_UNDERRUN = 0x0c,
>> +   BTSTAT_SELTIMEO      = 0x11,  // SCSI selection timeout
>> +   BTSTAT_DATARUN       = 0x12,  // Data overrun/underrun
>> +   BTSTAT_BUSFREE       = 0x13,  // Unexpected bus free
>> +   BTSTAT_INVPHASE      = 0x14,  //
>> +                                 // Invalid bus phase or sequence requested by
>> +                                 // target
>> +                                 //
>> +   BTSTAT_LUNMISMATCH   = 0x17,  // Linked CCB has different LUN from first CCB
>> +   BTSTAT_SENSFAILED    = 0x1b,  // Auto request sense failed
>> +   BTSTAT_TAGREJECT     = 0x1c,  //
>> +                                 // SCSI II tagged queueing message rejected by
>> +                                 // target
>> +                                 //
>> +   BTSTAT_BADMSG        = 0x1d,  //
>> +                                 // Unsupported message received by the host
>> +                                 // adapter
>> +                                 //
>> +   BTSTAT_HAHARDWARE    = 0x20,  // Host adapter hardware failed
>> +   BTSTAT_NORESPONSE    = 0x21,  //
>> +                                 // Target did not respond to SCSI ATN sent a
>> +                                 // SCSI RST
>> +                                 //
>> +   BTSTAT_SENTRST       = 0x22,  // Host adapter asserted a SCSI RST
>> +   BTSTAT_RECVRST       = 0x23,  // Other SCSI devices asserted a SCSI RST
>> +   BTSTAT_DISCONNECT    = 0x24,  //
>> +                                 // Target device reconnected improperly
>> +                                 // (w/o tag)
>> +                                 //
>> +   BTSTAT_BUSRESET      = 0x25,  // Host adapter issued BUS device reset
>> +   BTSTAT_ABORTQUEUE    = 0x26,  // Abort queue generated
>> +   BTSTAT_HASOFTWARE    = 0x27,  // Host adapter software error
>> +   BTSTAT_HATIMEOUT     = 0x30,  // Host adapter hardware timeout error
>> +   BTSTAT_SCSIPARITY    = 0x34,  // SCSI parity error detected
>> +};
> 
> (6) Same as (1) and (2).
> 
> (7) Please use a PvScsi prefix in these enum constants too.
> 
>> +
>> +#pragma pack (1)
>> +typedef struct {
>> +  UINT64 Context;
>> +  UINT64 DataLen;
>> +  UINT32 SenseLen;
>> +  UINT16 HostStatus;
>> +  UINT16 ScsiStatus;
>> +  UINT32 Pad[2];
>> +} PVSCSI_RING_CMP_DESC;
>> +#pragma pack ()
>> +
>>  #endif // __PVSCSI_H_
>>
> 
> Thanks!
> Laszlo
> 


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 15/17] OvmfPkg/PvScsiDxe: Support sending SCSI request and receive response
  2020-03-16 15:01 ` [PATCH 15/17] OvmfPkg/PvScsiDxe: Support sending SCSI request and receive response Liran Alon
@ 2020-03-24 16:43   ` Laszlo Ersek
  2020-03-25  1:17     ` Liran Alon
  0 siblings, 1 reply; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 16:43 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

There are many style problems with this patch.

I'm going to focus on those, for now. I might not catch everything in a
single review run, though (there are quite a few warts), so please don't
be annoyed if I end up pointing out further style problems under v2.

On 03/16/20 16:01, Liran Alon wrote:
> Implement EXT_SCSI_PASS_THRU.PassThru().
> 
> Machines should be able to boot after this commit.
> Tested with Ubuntu 16.04 guest.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/OvmfPkg.dec          |   6 +
>  OvmfPkg/PvScsiDxe/PvScsi.c   | 423 ++++++++++++++++++++++++++++++++++-
>  OvmfPkg/PvScsiDxe/PvScsi.h   |   1 +
>  OvmfPkg/PvScsiDxe/PvScsi.inf |   5 +-
>  4 files changed, 432 insertions(+), 3 deletions(-)
> 
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index 76ce507e8bd0..e78c771f53e9 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -130,6 +130,12 @@
>    gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit|64|UINT8|0x40
>    gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit|0|UINT8|0x41
>  
> +  ## After PvScsiDxe sends a SCSI request to the device, it waits for
> +  #  the request completion in a polling loop.
> +  #  This constant defines how many micro-seconds to wait between each
> +  #  polling loop iteration.
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiWaitForCmpStallInUsecs|5|UINT32|0x42

(1) Please keep the token space condensed.

> +
>    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 e48929bf044c..e7d0a23db6ab 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -30,6 +30,26 @@
>  // Ext SCSI Pass Thru utilities
>  //
>  
> +//
> +// Reads a 32-bit value into BAR0 using MMIO
> +//

(2) Please stick with the /** **/ comment style here.

> +STATIC
> +EFI_STATUS
> +PvScsiMmioRead32 (
> +  IN CONST PVSCSI_DEV   *Dev,
> +  IN UINT64             Offset,
> +  OUT UINT32            *Value
> +  )
> +{
> +  return Dev->PciIo->Mem.Read(
> +                           Dev->PciIo,
> +                           EfiPciIoWidthUint32,
> +                           0,   // BarIndex

(3) Please use PCI_BAR_IDX0.

> +                           Offset,
> +                           1,   // Count
> +                           Value
> +                           );
> +}
>  
>  //
>  // Writes a 32-bit value into BAR0 using MMIO
> @@ -100,6 +120,343 @@ PvScsiWriteCmdDesc (
>  
>    return EFI_SUCCESS;
>  }
> +
> +//
> +// Returns if PVSCSI request ring is full
> +//

(4) Same as (2).

Please rework the rest of the function-level comments accordingly.

> +STATIC
> +BOOLEAN
> +PvScsiIsReqRingFull (
> +  IN CONST PVSCSI_DEV   *Dev
> +  )
> +{
> +  PVSCSI_RINGS_STATE *RingsState;
> +  UINT64             ReqNumEntries;
> +
> +  RingsState = Dev->RingDesc.RingState;
> +  ReqNumEntries = 1 << RingsState->ReqNumEntriesLog2;

(5) Wrong for two reasons:

(5a) Based on ReqNumEntries having type UINT64, the shift count may
presumably be larger than 31. But the constant "1" has type "signed int"
(mapping to INT32 in edk2), and so we should never left-shift that by
even 31 positions (we should never shift bits into the sign bit). Let
alone by more than 31 positions.

In other words, the constant should be 1ULL.

(5b) Please use RShiftU64() from BaseLib.

> +  return (RingsState->ReqProdIdx - RingsState->CmpConsIdx) >= ReqNumEntries;
> +}
> +
> +//
> +// Returns pointer to current request descriptor to produce
> +//
> +STATIC
> +PVSCSI_RING_REQ_DESC *
> +PvScsiGetCurrentRequest (
> +  IN CONST PVSCSI_DEV   *Dev
> +  )
> +{
> +  PVSCSI_RINGS_STATE *RingState;
> +  UINT64             ReqNumEntries;
> +
> +  RingState = Dev->RingDesc.RingState;
> +  ReqNumEntries = 1 << RingState->ReqNumEntriesLog2;

(6) Same as (5).

Please rework further occurrences similarly.

> +  return Dev->RingDesc.RingReqs +
> +         (RingState->ReqProdIdx & (ReqNumEntries - 1));
> +}
> +
> +//
> +// Returns pointer to current completion descriptor to consume
> +//
> +STATIC
> +PVSCSI_RING_CMP_DESC *
> +PvScsiGetCurrentResponse (
> +  IN CONST PVSCSI_DEV   *Dev
> +  )
> +{
> +  PVSCSI_RINGS_STATE *RingState;
> +  UINT64             CmpNumEntries;
> +
> +  RingState = Dev->RingDesc.RingState;
> +  CmpNumEntries = 1 << RingState->CmpNumEntriesLog2;
> +  return Dev->RingDesc.RingCmps +
> +         (RingState->CmpConsIdx & (CmpNumEntries - 1));
> +}
> +
> +//
> +// Wait for device to signal completion of submitted requests
> +//
> +STATIC
> +EFI_STATUS
> +PvScsiWaitForRequestCompletion (
> +  IN CONST PVSCSI_DEV   *Dev
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINT32     IntrStatus;
> +
> +  //
> +  // Note: We don't yet support Timeout according to
> +  // EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.Timeout.
> +  //
> +  // This is consistent with some other Scsi PassThru drivers
> +  // such as VirtioScsi.
> +  //
> +  for (;;) {
> +    Status = PvScsiMmioRead32 (Dev, PVSCSI_REG_OFFSET_INTR_STATUS, &IntrStatus);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    //
> +    // PVSCSI_INTR_CMPL_MASK is set if device completed submitted requests
> +    //
> +    if (IntrStatus & PVSCSI_INTR_CMPL_MASK) {

(7) When checking bitmasks in a logical context, please use an explicit
"!= 0" comparison.

(Remember that "==" and "!=" bind more strongly than binary "&" does,
thus, you'll need extra parens.)

> +        break;
> +    }
> +
> +    gBS->Stall (Dev->WaitForCmpStallInUsecs);
> +  }
> +
> +  //
> +  // Acknowledge PVSCSI_INTR_CMPL_MASK in device interrupt-status register
> +  //
> +  return PvScsiMmioWrite32 (
> +           Dev,
> +           PVSCSI_REG_OFFSET_INTR_STATUS,
> +           PVSCSI_INTR_CMPL_MASK
> +           );
> +}
> +
> +//
> +// Populate a PVSCSI request descriptor from the Extended SCSI Pass Thru
> +// Protocol packet.
> +//
> +STATIC
> +EFI_STATUS
> +PopulateRequest (
> +  IN CONST PVSCSI_DEV                               *Dev,
> +  IN UINT8                                          *Target,
> +  IN UINT64                                         Lun,
> +  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
> +  OUT PVSCSI_RING_REQ_DESC                          *Request
> +  )
> +{
> +  UINT8 TargetValue;
> +
> +  //
> +  // We only use first byte of target identifer
> +  //
> +  TargetValue = *Target;
> +
> +  //
> +  // Check for unsupported requests
> +  //
> +  if (
> +      // Bidirectional transfer was requested

(8) Please prepend and append "empty" // lines.

Please rework the rest of the comments similarly. Edk2 permits //
comments without leading and trailing empty // lines only in case the //
comment is to the right of actual code on the same line, and the comment
applies to only that line.

> +      (Packet->InTransferLength > 0 && Packet->OutTransferLength > 0) ||
> +      (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
> +      // Command Descriptor Block bigger than this constant should be considered
> +      // out-of-band. We currently don't support these CDBs.
> +      (Packet->CdbLength > PVSCSI_CDB_MAX_SIZE)
> +      ) {
> +
> +    //
> +    // This error code doesn't require updates to the Packet output fields
> +    //
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Check for invalid parameters
> +  //
> +  if (
> +      // Addressed invalid device
> +      (TargetValue > Dev->MaxTarget) || (Lun > Dev->MaxLun) ||
> +      // Invalid direction (there doesn't seem to be a macro for the "no data
> +      // transferred" "direction", eg. for TEST UNIT READY)
> +      (Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
> +      // Trying to receive, but destination pointer is NULL, or contradicting
> +      // transfer direction
> +      ((Packet->InTransferLength > 0) &&
> +       ((Packet->InDataBuffer == NULL) ||
> +        (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE)
> +        )
> +       ) ||
> +
> +      //
> +      // Trying to send, but source pointer is NULL, or contradicting
> +      // transfer direction
> +      //
> +      ((Packet->OutTransferLength > 0) &&
> +       ((Packet->OutDataBuffer == NULL) ||
> +        (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ)
> +        )
> +       )
> +      ) {
> +
> +    //
> +    // This error code doesn't require updates to the Packet output fields
> +    //
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Check for input/output buffer too large for DMA communication buffer
> +  //
> +  if (Packet->InTransferLength > sizeof (Dev->DmaBuf->Data)) {
> +    Packet->InTransferLength = sizeof (Dev->DmaBuf->Data);
> +    return EFI_BAD_BUFFER_SIZE;
> +  }
> +  if (Packet->OutTransferLength > sizeof (Dev->DmaBuf->Data)) {
> +    Packet->OutTransferLength = sizeof (Dev->DmaBuf->Data);
> +    return EFI_BAD_BUFFER_SIZE;
> +  }
> +
> +  //
> +  // Encode PVSCSI request
> +  //
> +  ZeroMem (Request, sizeof (*Request));
> +
> +  Request->Bus = 0;
> +  Request->Target = TargetValue;
> +  //
> +  // This cast is safe as MaxLun is defined as UINT8
> +  //
> +  Request->Lun[1] = (UINT8)Lun;
> +  Request->SenseLen = Packet->SenseDataLength;
> +  Request->SenseAddr = (UINT64)PVSCSI_DMA_BUF_DEV_ADDR (Dev, SenseData);
> +  Request->CdbLen = Packet->CdbLength;
> +  CopyMem (Request->Cdb, Packet->Cdb, Packet->CdbLength);
> +  Request->vCPUHint = 0;
> +  Request->Tag = PVSCSI_SIMPLE_QUEUE_TAG;
> +  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
> +    Request->Flags = PVSCSI_FLAG_CMD_DIR_TOHOST;
> +    Request->DataLen = Packet->InTransferLength;
> +  } else {
> +    Request->Flags = PVSCSI_FLAG_CMD_DIR_TODEVICE;
> +    Request->DataLen = Packet->OutTransferLength;
> +    CopyMem (
> +      Dev->DmaBuf->Data,
> +      Packet->OutDataBuffer,
> +      Packet->OutTransferLength);

(9) Please pick one of the following styles:

    CopyMem (
      Dev->DmaBuf->Data,
      Packet->OutDataBuffer,
      Packet->OutTransferLength
      );

or

    CopyMem (Dev->DmaBuf->Data, Packet->OutDataBuffer,
      Packet->OutTransferLength);


> +  }
> +  Request->DataAddr = (UINT64)PVSCSI_DMA_BUF_DEV_ADDR (Dev, Data);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +//
> +// Handle the PVSCSI device response:
> +// - Copy returned data from DMA communication buffer.
> +// - Update fields in Extended SCSI Pass Thru Protocol packet as required.
> +// - Translate response code to EFI status code and host adapter status.
> +//
> +STATIC
> +EFI_STATUS
> +HandleResponse (
> +  IN PVSCSI_DEV                                     *Dev,
> +  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
> +  IN CONST PVSCSI_RING_CMP_DESC                     *Response
> +  )
> +{
> +  //
> +  // Check if device returned sense data
> +  //
> +  if (Response->ScsiStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {
> +    //
> +    // Fix SenseDataLength to amount of data returned
> +    //
> +    if (Packet->SenseDataLength > Response->SenseLen) {
> +      Packet->SenseDataLength = (UINT8)Response->SenseLen;
> +    }
> +    //
> +    // Copy sense data from DMA communication buffer
> +    //
> +    CopyMem (
> +      Packet->SenseData,
> +      Dev->DmaBuf->SenseData,
> +      Packet->SenseDataLength
> +      );
> +  } else {
> +    //
> +    // Signal no sense data returned
> +    //
> +    Packet->SenseDataLength = 0;
> +  }
> +
> +  //
> +  // Copy device output from DMA communication buffer
> +  //
> +  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
> +    CopyMem (Packet->InDataBuffer, Dev->DmaBuf->Data, Packet->InTransferLength);
> +  }
> +
> +  //
> +  // Report target status
> +  //
> +  Packet->TargetStatus = Response->ScsiStatus;
> +
> +  //
> +  // Host adapter status and function return value depend on
> +  // device response's host status
> +  //
> +  switch (Response->HostStatus) {
> +    case BTSTAT_SUCCESS:
> +    case BTSTAT_LINKED_COMMAND_COMPLETED:
> +    case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG:
> +      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
> +      return EFI_SUCCESS;
> +
> +    case BTSTAT_SELTIMEO:
> +      Packet->HostAdapterStatus =
> +                EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
> +      return EFI_TIMEOUT;
> +
> +    case BTSTAT_DATARUN:
> +    case BTSTAT_DATA_UNDERRUN:
> +      //
> +      // Report residual data in overrun/underrun
> +      //
> +      if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
> +        Packet->InTransferLength = Response->DataLen;
> +      } else {
> +        Packet->OutTransferLength = Response->DataLen;
> +      }
> +      Packet->HostAdapterStatus =
> +                EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
> +      return EFI_BAD_BUFFER_SIZE;
> +
> +    case BTSTAT_BUSFREE:
> +      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE;
> +      break;
> +
> +    case BTSTAT_INVPHASE:
> +      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;
> +      break;
> +
> +    case BTSTAT_SENSFAILED:
> +      Packet->HostAdapterStatus =
> +                EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED;
> +      break;
> +
> +    case BTSTAT_TAGREJECT:
> +    case BTSTAT_BADMSG:
> +      Packet->HostAdapterStatus =
> +          EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT;
> +      break;
> +
> +    case BTSTAT_BUSRESET:
> +      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;
> +      break;
> +
> +    case BTSTAT_HATIMEOUT:
> +      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
> +      return EFI_TIMEOUT;
> +
> +    case BTSTAT_SCSIPARITY:
> +      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR;
> +      break;
> +
> +    default:
> +      Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
> +      break;
> +  }
> +
> +  return EFI_DEVICE_ERROR;
> +}
> +
>  //
>  // Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and
>  // EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized
> @@ -135,7 +492,70 @@ PvScsiPassThru (
>    IN EFI_EVENT                                      Event    OPTIONAL
>    )
>  {
> -  return EFI_UNSUPPORTED;
> +  PVSCSI_DEV            *Dev;
> +  EFI_STATUS            Status;
> +  PVSCSI_RING_REQ_DESC *Request;
> +  PVSCSI_RING_CMP_DESC *Response;
> +
> +  Dev = PVSCSI_FROM_PASS_THRU (This);
> +
> +  if (PvScsiIsReqRingFull (Dev)) {
> +    return EFI_NOT_READY;
> +  }
> +
> +  Request = PvScsiGetCurrentRequest (Dev);
> +
> +  Status = PopulateRequest (Dev, Target, Lun, Packet, Request);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Writes to Request must be globally visible before making request
> +  // available to device
> +  //
> +  MemoryFence();

(10) Missing space before the opening paren.

Please check the rest of the code for the same style issue.


> +  Dev->RingDesc.RingState->ReqProdIdx++;
> +
> +  Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_KICK_RW_IO, 0);
> +  if (EFI_ERROR (Status)) {
> +    //
> +    // If kicking the host fails, we must fake a host adapter error.
> +    // EFI_NOT_READY would save us the effort, but it would also suggest that
> +    // the caller retry.
> +    //
> +    goto FakeHostAdapterError;
> +  }

(11) Hmmm. Not really happy about this. It doesn't feel like actual
error handling (= resource release / rollback); we're just factoring out
response composition. That's OK per se, but then it belongs to a helper
function, not a "function epilogue" here.

> +
> +  Status = PvScsiWaitForRequestCompletion (Dev);
> +  if (EFI_ERROR (Status)) {
> +    //
> +    // If waiting for request completion fails, we must fake a host adapter
> +    // error. EFI_NOT_READY would save us the effort, but it would also suggest
> +    // that the caller retry.
> +    //
> +    goto FakeHostAdapterError;
> +  }
> +
> +  Response = PvScsiGetCurrentResponse (Dev);
> +  Status = HandleResponse (Dev, Packet, Response);
> +
> +  //
> +  // Reads from response must complete before releasing completion entry
> +  // to device
> +  //
> +  MemoryFence();
> +  Dev->RingDesc.RingState->CmpConsIdx++;
> +
> +  return Status;
> +
> +FakeHostAdapterError:
> +    Packet->InTransferLength = 0;
> +    Packet->OutTransferLength = 0;
> +    Packet->SenseDataLength = 0;
> +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
> +    Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
> +    return EFI_DEVICE_ERROR;

(12) also, wrong indentation.

Thanks
Laszlo

>  }
>  
>  STATIC
> @@ -613,6 +1033,7 @@ PvScsiInit (
>    //
>    Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);
>    Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);
> +  Dev->WaitForCmpStallInUsecs = PcdGet32 (PcdPvScsiWaitForCmpStallInUsecs);
>  
>    //
>    // Set PCI Attributes
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
> index 7f91d70fec79..08e876b75930 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.h
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.h
> @@ -47,6 +47,7 @@ typedef struct {
>    PVSCSI_DMA_DESC                 DmaBufDmaDesc;
>    UINT8                           MaxTarget;
>    UINT8                           MaxLun;
> +  UINTN                           WaitForCmpStallInUsecs;
>    EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
>    EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
>  } PVSCSI_DEV;
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.inf b/OvmfPkg/PvScsiDxe/PvScsi.inf
> index 96bd4e4a9a8b..e3a85eba8dac 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.inf
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.inf
> @@ -37,5 +37,6 @@
>    gEfiExtScsiPassThruProtocolGuid   ## BY_START
>  
>  [Pcd]
> -  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit    ## CONSUMES
> -  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit       ## CONSUMES
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxTargetLimit            ## CONSUMES
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiMaxLunLimit               ## CONSUMES
> +  gUefiOvmfPkgTokenSpaceGuid.PcdPvScsiWaitForCmpStallInUsecs    ## CONSUMES
> 


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 16/17] OvmfPkg/PvScsiDxe: Reset device on ExitBootServices()
  2020-03-16 15:01 ` [PATCH 16/17] OvmfPkg/PvScsiDxe: Reset device on ExitBootServices() Liran Alon
@ 2020-03-24 17:04   ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-24 17:04 UTC (permalink / raw)
  To: devel, liran.alon
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/16/20 16:01, Liran Alon wrote:
> This causes the device to forget about the request/completion rings.
> We allocated said rings in EfiBootServicesData type memory, and code
> executing after ExitBootServices() is permitted to overwrite it.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2567
> Reviewed-by: Nikita Leshenko <nikita.leshchenko@oracle.com>
> Signed-off-by: Liran Alon <liran.alon@oracle.com>
> ---
>  OvmfPkg/PvScsiDxe/PvScsi.c | 42 +++++++++++++++++++++++++++++++++++++-
>  OvmfPkg/PvScsiDxe/PvScsi.h |  1 +
>  2 files changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.c b/OvmfPkg/PvScsiDxe/PvScsi.c
> index e7d0a23db6ab..33167c177b42 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.c
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.c
> @@ -1156,6 +1156,30 @@ PvScsiUninit (
>    }
>  }
>  
> +//
> +// Event notification called by ExitBootServices()
> +//

(1) Comment style -- please use:

/**
  Blah.
**/

> +STATIC
> +VOID
> +EFIAPI
> +PvScsiExitBoot (
> +  IN  EFI_EVENT Event,
> +  IN  VOID      *Context
> +  )
> +{
> +  PVSCSI_DEV *Dev;
> +
> +  Dev = Context;
> +
> +  //
> +  // Reset the device. This causes the device to forget about the
> +  // request/completion rings. We allocated said rings in EfiBootServicesData
> +  // type memory, and code executing after ExitBootServices() is permitted to
> +  // overwrite it.
> +  //
> +  PvScsiWriteCmdDesc (Dev, PVSCSI_CMD_ADAPTER_RESET, NULL, 0);
> +}
> +

(2) Please log a DEBUG_VERBOSE message here, something like:

  DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));

Notification functions for EVT_SIGNAL_EXIT_BOOT_SERVICES are very
important, and sometimes obscure bugs can be tracked down somewhat more
easily if the firmware log captures the order in which the handlers are
queued / executed.

>  //
>  // Driver Binding
>  //
> @@ -1249,6 +1273,17 @@ PvScsiDriverBindingStart (
>      goto ClosePciIo;
>    }
>  
> +  Status = gBS->CreateEvent (
> +                  EVT_SIGNAL_EXIT_BOOT_SERVICES,
> +                  TPL_CALLBACK,
> +                  &PvScsiExitBoot,
> +                  Dev,
> +                  &Dev->ExitBoot
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    goto UninitDev;
> +  }
> +
>    //
>    // Setup complete, attempt to export the driver instance's PassThru interface
>    //
> @@ -1260,11 +1295,14 @@ PvScsiDriverBindingStart (
>                    &Dev->PassThru
>                    );
>    if (EFI_ERROR (Status)) {
> -    goto UninitDev;
> +    goto CloseExitBoot;
>    }
>  
>    return EFI_SUCCESS;
>  
> +CloseExitBoot:
> +  gBS->CloseEvent (Dev->ExitBoot);
> +
>  UninitDev:
>    PvScsiUninit (Dev);
>  
> @@ -1319,6 +1357,8 @@ PvScsiDriverBindingStop (
>      return Status;
>    }
>  
> +  gBS->CloseEvent (Dev->ExitBoot);
> +
>    PvScsiUninit (Dev);
>  
>    gBS->CloseProtocol (
> diff --git a/OvmfPkg/PvScsiDxe/PvScsi.h b/OvmfPkg/PvScsiDxe/PvScsi.h
> index 08e876b75930..e68a7dedf71f 100644
> --- a/OvmfPkg/PvScsiDxe/PvScsi.h
> +++ b/OvmfPkg/PvScsiDxe/PvScsi.h
> @@ -41,6 +41,7 @@ typedef struct {
>  typedef struct {
>    UINT32                          Signature;
>    EFI_PCI_IO_PROTOCOL             *PciIo;
> +  EFI_EVENT                       ExitBoot;
>    UINT64                          OriginalPciAttributes;
>    PVSCSI_RING_DESC                RingDesc;
>    PVSCSI_DMA_BUFFER               *DmaBuf;
> 

These parts look fine.

With (1) and (2) addressed:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks,
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init
  2020-03-24 16:00   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-25  1:11     ` Liran Alon
  2020-03-25 16:31       ` Laszlo Ersek
  0 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-25  1:11 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel


On 24/03/2020 18:00, Laszlo Ersek wrote:
> On 03/16/20 16:01, Liran Alon wrote:
>> +STATIC
>> +EFI_STATUS
>> +PvScsiWriteCmdDesc (
>> +  IN CONST PVSCSI_DEV   *Dev,
>> +  IN UINT32             Cmd,
>> +  IN VOID               *Desc,
>> +  IN UINTN              Length
>> +  )
>> +{
>> +  EFI_STATUS Status;
>> +  UINTN      LengthInWords;
>> +  UINT8      *WordPtr;
>> +  UINT8      *DescEndPtr;
>> +  UINT32     Word;
>> +
>> +  LengthInWords = Length / sizeof (UINT32);
> (4) What guarantees that "Length" is a whole multiple of sizeof
> (UINT32)?

Nothing.
Besides the fact that all commands passed to this function are indeed 
multiple of sizeof (UINT32).

> In this review I have not insisted on including full-blown interface
> contracts in the top-level function comment blocks (with @param[in] and
> @retval etc).
Thanks for that. I think too it would be an overkill with little value.
> But, for this function, it really is unclear.
Will it be sufficient for you if I just replace the prototype with 
something like the following?

/**
   Send PVSCSI command to device
**/
STATIC
EFI_STATUS
PvScsiWriteCmdDesc (
    IN CONST PVSCSI_DEV   *Dev,
    IN UINT32                     Cmd,
    IN VOID                         *Desc,
    IN UINTN                       LengthInWords     // Note: Word is UINT32
    )
>> +
>> +  if (LengthInWords > PVSCSI_MAX_CMD_DATA_WORDS) {
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_COMMAND, Cmd);
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  WordPtr = Desc;
>> +  DescEndPtr = WordPtr + Length;
>> +
>> +  while (WordPtr != DescEndPtr) {
>> +    //
>> +    // CopyMem() is used to avoid strict-aliasing issues
>> +    //
> (5) In edk2, we -- completely intentionally -- disable the enforcement
> of the effective type rules / strict aliasing rules. See
> "-fno-strict-aliasing" in "BaseTools/Conf/tools_def.template".
>
>> +    CopyMem (&Word, WordPtr, sizeof (UINT32));
>> +
>> +    Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_COMMAND_DATA, Word);
>> +    if (EFI_ERROR (Status)) {
>> +      return Status;
>> +    }
>> +
>> +    WordPtr += sizeof (UINT32);
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
> (6) I think the open-coded loop is suboptimal -- the PciIo protocol
> seems to offer EfiPciIoWidthFifoUint32 for exactly this purpose (=
> advance in the memory buffer, while accessing the same offset in the
> BAR).
>
> Have you perhaps tried that?
I actually haven't noticed EfiPciIoWidthFifoUint32 until you mentioned it.
As it seems there isn't even a single line of code in EDK2 that use it. :)
In fact, the only code that use one of the EfiPciIoWidthFifo* is 
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c.
> (I can imagine that you ruled it out, due to "Desc" being unaligned. The
> UEFI spec does say, "The caller is responsible for any alignment and I/O
> width issues which the bus, device, platform, or type of I/O might
> require.)
Why is this an issue?
It's easy to document with one-line comment at end of Desc parameter 
deceleration that it must be aligned.
It's also not difficult to modify callers as only a single caller 
actually pass a descriptor (The caller PvScsiInitRings()).
To avoid further style comments, what is the coding convention in EDK2 
to align the "PVSCSI_CMD_DESC_SETUP_RINGS Cmd;" var properly?
In addition, I assume I don't need to add any validation of alignment to 
PvScsiWriteCmdDesc().

-Liran


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 15/17] OvmfPkg/PvScsiDxe: Support sending SCSI request and receive response
  2020-03-24 16:43   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-25  1:17     ` Liran Alon
  0 siblings, 0 replies; 47+ messages in thread
From: Liran Alon @ 2020-03-25  1:17 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel


On 24/03/2020 18:43, Laszlo Ersek wrote:
> On 03/16/20 16:01, Liran Alon wrote:
>> +STATIC
>> +BOOLEAN
>> +PvScsiIsReqRingFull (
>> +  IN CONST PVSCSI_DEV   *Dev
>> +  )
>> +{
>> +  PVSCSI_RINGS_STATE *RingsState;
>> +  UINT64             ReqNumEntries;
>> +
>> +  RingsState = Dev->RingDesc.RingState;
>> +  ReqNumEntries = 1 << RingsState->ReqNumEntriesLog2;
> (5) Wrong for two reasons:
>
> (5a) Based on ReqNumEntries having type UINT64, the shift count may
> presumably be larger than 31. But the constant "1" has type "signed int"
> (mapping to INT32 in edk2), and so we should never left-shift that by
> even 31 positions (we should never shift bits into the sign bit). Let
> alone by more than 31 positions.
>
> In other words, the constant should be 1ULL.
>
> (5b) Please use RShiftU64() from BaseLib.
Actually, I have noticed that ReqNumEntries should just be UINT32 and "1 
<<" should be changed to "1U <<".
So I made these changes for v2. Thanks.
>> @@ -135,7 +492,70 @@ PvScsiPassThru (
>>     IN EFI_EVENT                                      Event    OPTIONAL
>>     )
>>   {
...
>> +  Dev->RingDesc.RingState->ReqProdIdx++;
>> +
>> +  Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_KICK_RW_IO, 0);
>> +  if (EFI_ERROR (Status)) {
>> +    //
>> +    // If kicking the host fails, we must fake a host adapter error.
>> +    // EFI_NOT_READY would save us the effort, but it would also suggest that
>> +    // the caller retry.
>> +    //
>> +    goto FakeHostAdapterError;
>> +  }
> (11) Hmmm. Not really happy about this. It doesn't feel like actual
> error handling (= resource release / rollback); we're just factoring out
> response composition. That's OK per se, but then it belongs to a helper
> function, not a "function epilogue" here.

Ok. I will move it to a helper function in v2.

-Liran



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 09/17] OvmfPkg/PvScsiDxe: Backup/Restore PCI attributes on Init/UnInit
  2020-03-24 15:35     ` Liran Alon
@ 2020-03-25  1:48       ` Laszlo Ersek
  2020-03-25 10:32         ` Liran Alon
  0 siblings, 1 reply; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-25  1:48 UTC (permalink / raw)
  To: Liran Alon, devel
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/24/20 16:35, Liran Alon wrote:
> 
> On 24/03/2020 17:14, Laszlo Ersek wrote:
>> On 03/16/20 16:01, Liran Alon wrote:
>> I'm going to stop reviewing this iteration now; please rework the rest
>> of the series for v2 with this resource management pattern.
>>
>> Thanks!
>> Laszlo
> 
> Thanks for the very detailed review!
> 
> I have read all your comments and understood them. I am working on
> creating a v2 patch-series with all these fixed.
> As the Init/UnInit logic is the only place in which this resource
> management pattern is done, and as patch-series is split
> to small well-defined quite independent patches, can I request that you
> will complete review of all v1 patches?
> 
> I will understand if you are too busy for this, but it will allow me to
> take into account all your aggregated comments on v1
> to hopefully create a perfect v2 patch-series. As I've tried taking into
> account all the comments you gave on Nikita's series.

I ended up doing a superficial run over the rest of the series, before
arriving at this email of yours.

Unfortunately, in the most "meaty" patches, there are many style issues,
and they kept throwing me off. It's difficult to ping-pong between style
remarks and semantics. Basically, in those patches, I'm asking for style
fixes now, so I have a chance at a more substantial review with v2.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 09/17] OvmfPkg/PvScsiDxe: Backup/Restore PCI attributes on Init/UnInit
  2020-03-25  1:48       ` Laszlo Ersek
@ 2020-03-25 10:32         ` Liran Alon
  0 siblings, 0 replies; 47+ messages in thread
From: Liran Alon @ 2020-03-25 10:32 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel


On 25/03/2020 3:48, Laszlo Ersek wrote:
> On 03/24/20 16:35, Liran Alon wrote:
>> On 24/03/2020 17:14, Laszlo Ersek wrote:
>>> On 03/16/20 16:01, Liran Alon wrote:
>>> I'm going to stop reviewing this iteration now; please rework the rest
>>> of the series for v2 with this resource management pattern.
>>>
>>> Thanks!
>>> Laszlo
>> Thanks for the very detailed review!
>>
>> I have read all your comments and understood them. I am working on
>> creating a v2 patch-series with all these fixed.
>> As the Init/UnInit logic is the only place in which this resource
>> management pattern is done, and as patch-series is split
>> to small well-defined quite independent patches, can I request that you
>> will complete review of all v1 patches?
>>
>> I will understand if you are too busy for this, but it will allow me to
>> take into account all your aggregated comments on v1
>> to hopefully create a perfect v2 patch-series. As I've tried taking into
>> account all the comments you gave on Nikita's series.
> I ended up doing a superficial run over the rest of the series, before
> arriving at this email of yours.
>
> Unfortunately, in the most "meaty" patches, there are many style issues,
> and they kept throwing me off. It's difficult to ping-pong between style
> remarks and semantics. Basically, in those patches, I'm asking for style
> fixes now, so I have a chance at a more substantial review with v2.
>
> Thanks
> Laszlo
>
Thanks for reviewing also the other patches for style issues as-well. 
This is what I requested.
This will assist me in submitting a much more ready v2 submission.
I'm currently working on it and hope to have a v2 submission later today 
with all your fixes and suggestions applied.

Highly appreciate your detailed review comments.

Thanks,
-Liran



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init
  2020-03-25  1:11     ` Liran Alon
@ 2020-03-25 16:31       ` Laszlo Ersek
  2020-03-25 16:40         ` Liran Alon
  0 siblings, 1 reply; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-25 16:31 UTC (permalink / raw)
  To: Liran Alon, devel
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/25/20 02:11, Liran Alon wrote:
>
> On 24/03/2020 18:00, Laszlo Ersek wrote:
>> On 03/16/20 16:01, Liran Alon wrote:
>>> +STATIC
>>> +EFI_STATUS
>>> +PvScsiWriteCmdDesc (
>>> +  IN CONST PVSCSI_DEV   *Dev,
>>> +  IN UINT32             Cmd,
>>> +  IN VOID               *Desc,
>>> +  IN UINTN              Length
>>> +  )
>>> +{
>>> +  EFI_STATUS Status;
>>> +  UINTN      LengthInWords;
>>> +  UINT8      *WordPtr;
>>> +  UINT8      *DescEndPtr;
>>> +  UINT32     Word;
>>> +
>>> +  LengthInWords = Length / sizeof (UINT32);
>> (4) What guarantees that "Length" is a whole multiple of sizeof
>> (UINT32)?
>
> Nothing.
> Besides the fact that all commands passed to this function are indeed
> multiple of sizeof (UINT32).
>
>> In this review I have not insisted on including full-blown interface
>> contracts in the top-level function comment blocks (with @param[in]
>> and @retval etc).

> Thanks for that. I think too it would be an overkill with little
> value.

>> But, for this function, it really is unclear.

> Will it be sufficient for you if I just replace the prototype with
> something like the following?
>
> /**
>   Send PVSCSI command to device
> **/
> STATIC
> EFI_STATUS
> PvScsiWriteCmdDesc (
>    IN CONST PVSCSI_DEV   *Dev,
>    IN UINT32                     Cmd,
>    IN VOID                         *Desc,
>    IN UINTN                       LengthInWords     // Note: Word is UINT32
>    )

The comment "// Note: ..." on a particular parameter is really
non-idiomatic. So please either (a) rename "LengthInWords" so that
"UINT32" is obvious from it, or (for this one particular function) (b)
please do add a full-blown function-level comment, with @param[in] and
@return / @retval markers.

>>> +
>>> +  if (LengthInWords > PVSCSI_MAX_CMD_DATA_WORDS) {
>>> +    return EFI_INVALID_PARAMETER;
>>> +  }
>>> +
>>> +  Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_COMMAND, Cmd);
>>> +  if (EFI_ERROR (Status)) {
>>> +    return Status;
>>> +  }
>>> +
>>> +  WordPtr = Desc;
>>> +  DescEndPtr = WordPtr + Length;
>>> +
>>> +  while (WordPtr != DescEndPtr) {
>>> +    //
>>> +    // CopyMem() is used to avoid strict-aliasing issues
>>> +    //

>> (5) In edk2, we -- completely intentionally -- disable the
>> enforcement of the effective type rules / strict aliasing rules. See
>> "-fno-strict-aliasing" in "BaseTools/Conf/tools_def.template".

>>
>>> +    CopyMem (&Word, WordPtr, sizeof (UINT32));
>>> +
>>> +    Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_COMMAND_DATA,
>>> Word);
>>> +    if (EFI_ERROR (Status)) {
>>> +      return Status;
>>> +    }
>>> +
>>> +    WordPtr += sizeof (UINT32);
>>> +  }
>>> +
>>> +  return EFI_SUCCESS;
>>> +}

>> (6) I think the open-coded loop is suboptimal -- the PciIo protocol
>> seems to offer EfiPciIoWidthFifoUint32 for exactly this purpose (=
>> advance in the memory buffer, while accessing the same offset in the
>> BAR).
>>
>> Have you perhaps tried that?

> I actually haven't noticed EfiPciIoWidthFifoUint32 until you mentioned
> it.
> As it seems there isn't even a single line of code in EDK2 that use
> it. :)

"MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c" seems to use it,
doesn't it? From commit 9bfaa3da1ee5 ("MdeModulePkg/SdMmcPciHcDxe: Fix
PIO transfer mode", 2020-03-05).

> In fact, the only code that use one of the EfiPciIoWidthFifo* is
> MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c.

>> (I can imagine that you ruled it out, due to "Desc" being unaligned.
>> The UEFI spec does say, "The caller is responsible for any alignment
>> and I/O width issues which the bus, device, platform, or type of I/O
>> might require.)

> Why is this an issue?

If it's not an issue for you, it's definitely not an issue for me. :) I
didn't know how difficult it would be for you to satisfy such an
alignment requirement, at all the call sites.

> It's easy to document with one-line comment at end of Desc parameter
> deceleration that it must be aligned.

Documenting the requirement is good, but *if* you do that, you can
*only* do it with a @param[in] marker.

> It's also not difficult to modify callers as only a single caller
> actually pass a descriptor (The caller PvScsiInitRings()).

OK.

> To avoid further style comments, what is the coding convention in EDK2
> to align the "PVSCSI_CMD_DESC_SETUP_RINGS Cmd;" var properly?

The best I can recommend off-hand is:

union {
  PVSCSI_CMD_DESC_SETUP_RINGS Cmd;
  UINT32                      Uint32;
} AlignAtUint32;

Perhaps someone else can recommend something less awkward.

Note: PVSCSI_CMD_DESC_SETUP_RINGS is a packed structure (and I do agree
that's good, if at least for documentation purposes). If it weren't
packed, then the following passage from the UEFI spec would apply:

    2.3.1 Data Types

    Table 5 lists the common data types that are used in the interface
    definitions, and Table 6 lists their modifiers. Unless otherwise
    specified all data types are naturally aligned. Structures are
    aligned on boundaries equal to the largest internal datum of the
    structure and internal data are implicitly padded to achieve natural
    alignment.

Because PVSCSI_CMD_DESC_SETUP_RINGS only contains members with types
listed in Table 5 (namely, UINT32 and UINT64), the above language would
normally guarantee the proper alignment. *But*, because the structure is
packed, I don't think we can rely on the spec's description (cf. "unless
otherwise specified").

So, in theory, there are two options:

- drop the packing (and rely on the natural alignment providing what you
  need anyway),

- keep the packing, and use other methods to guarantee struct-level
  alignment (such as the above union).

I prefer keeping the packing, if for nothing else then for documentation
purposes (it says "wire format" loud and clear). If you use the union
above, I'll be OK with it.

> In addition, I assume I don't need to add any validation of alignment
> to PvScsiWriteCmdDesc().

No, I don't think that's necessary. I think the generic edk2 machinery
rejects a misaligned memory buffer explicitly, as follows:

(a) The PciIo->Mem.Read/Write members are implemented in PciIoMemRead()
    / PciIoMemWrite() [MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c].

    Two comments about them:

    - These functions break up unaligned requests into byte-size
      requests if "PcdUnalignedPciIoEnable" is TRUE. (Note: it is FALSE
      for OvmfPkg, and we should not change that.)

    - These functions do not actually check the alignment of either
      "Buffer" or the MMIO "Offset" within the BAR. They just delegate
      to PciRootBridgeIo->Mem.Read() and PciRootBridgeIo->Mem.Write().

(b) For those, we need to look at RootBridgeIoMemRead() and
    RootBridgeIoMemWrite(), in
    "MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c".

    Both of these functions call RootBridgeIoCheckParameter(),
    RootBridgeIoCheckParameter() -- which checks the alignment on the
    MMIO "Address" within the BAR (--> EFI_UNSUPPORTED), but still
    doesn't check the alignment of "Buffer".

    So, let's continue analyzing RootBridgeIoMemRead() and
    RootBridgeIoMemWrite()... Once RootBridgeIoCheckParameter() is
    happy, the work is delegated to CpuIo->Mem.Read/Write.

(c) For those, we need to look at CpuMemoryServiceRead() and
    CpuMemoryServiceWrite(), in "UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c".

    These functions call CpuIoCheckParameter(). And that function
    finally does seem to check the alignment of "Buffer":

  //
  // Check to see if Buffer is aligned
  // (IA-32 allows UINT64 and INT64 data types to be 32-bit aligned.)
  //
  if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width])  - 1))) != 0) {
    return EFI_UNSUPPORTED;
  }

    (See related commit 36de860619c2, "Update the check condition to
    allows UINT64 and INT64 data types to be 32-bit aligned on IA32
    system.", 2011-12-01.)

Thus I believe any mis-alignment in "Desc" would be caught for you.

Thanks,
Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init
  2020-03-25 16:31       ` Laszlo Ersek
@ 2020-03-25 16:40         ` Liran Alon
  2020-03-25 17:13           ` Liran Alon
  0 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-25 16:40 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel


On 25/03/2020 18:31, Laszlo Ersek wrote:
> On 03/25/20 02:11, Liran Alon wrote:
>> On 24/03/2020 18:00, Laszlo Ersek wrote:
>>> On 03/16/20 16:01, Liran Alon wrote:
>>>> +STATIC
>>>> +EFI_STATUS
>>>> +PvScsiWriteCmdDesc (
>>>> +  IN CONST PVSCSI_DEV   *Dev,
>>>> +  IN UINT32             Cmd,
>>>> +  IN VOID               *Desc,
>>>> +  IN UINTN              Length
>>>> +  )
>>>> +{
>>>> +  EFI_STATUS Status;
>>>> +  UINTN      LengthInWords;
>>>> +  UINT8      *WordPtr;
>>>> +  UINT8      *DescEndPtr;
>>>> +  UINT32     Word;
>>>> +
>>>> +  LengthInWords = Length / sizeof (UINT32);
>>> (4) What guarantees that "Length" is a whole multiple of sizeof
>>> (UINT32)?
>> Nothing.
>> Besides the fact that all commands passed to this function are indeed
>> multiple of sizeof (UINT32).
>>
>>> In this review I have not insisted on including full-blown interface
>>> contracts in the top-level function comment blocks (with @param[in]
>>> and @retval etc).
>> Thanks for that. I think too it would be an overkill with little
>> value.
>>> But, for this function, it really is unclear.
>> Will it be sufficient for you if I just replace the prototype with
>> something like the following?
>>
>> /**
>>    Send PVSCSI command to device
>> **/
>> STATIC
>> EFI_STATUS
>> PvScsiWriteCmdDesc (
>>     IN CONST PVSCSI_DEV   *Dev,
>>     IN UINT32                     Cmd,
>>     IN VOID                         *Desc,
>>     IN UINTN                       LengthInWords     // Note: Word is UINT32
>>     )
> The comment "// Note: ..." on a particular parameter is really
> non-idiomatic. So please either (a) rename "LengthInWords" so that
> "UINT32" is obvious from it, or (for this one particular function) (b)
> please do add a full-blown function-level comment, with @param[in] and
> @return / @retval markers.
I took a different approach eventually in v2 which I think you will like.
See v2 patch-series for more information.
>
>>>> +
>>>> +  if (LengthInWords > PVSCSI_MAX_CMD_DATA_WORDS) {
>>>> +    return EFI_INVALID_PARAMETER;
>>>> +  }
>>>> +
>>>> +  Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_COMMAND, Cmd);
>>>> +  if (EFI_ERROR (Status)) {
>>>> +    return Status;
>>>> +  }
>>>> +
>>>> +  WordPtr = Desc;
>>>> +  DescEndPtr = WordPtr + Length;
>>>> +
>>>> +  while (WordPtr != DescEndPtr) {
>>>> +    //
>>>> +    // CopyMem() is used to avoid strict-aliasing issues
>>>> +    //
>>> (5) In edk2, we -- completely intentionally -- disable the
>>> enforcement of the effective type rules / strict aliasing rules. See
>>> "-fno-strict-aliasing" in "BaseTools/Conf/tools_def.template".
>>>> +    CopyMem (&Word, WordPtr, sizeof (UINT32));
>>>> +
>>>> +    Status = PvScsiMmioWrite32 (Dev, PVSCSI_REG_OFFSET_COMMAND_DATA,
>>>> Word);
>>>> +    if (EFI_ERROR (Status)) {
>>>> +      return Status;
>>>> +    }
>>>> +
>>>> +    WordPtr += sizeof (UINT32);
>>>> +  }
>>>> +
>>>> +  return EFI_SUCCESS;
>>>> +}
>>> (6) I think the open-coded loop is suboptimal -- the PciIo protocol
>>> seems to offer EfiPciIoWidthFifoUint32 for exactly this purpose (=
>>> advance in the memory buffer, while accessing the same offset in the
>>> BAR).
>>>
>>> Have you perhaps tried that?
>> I actually haven't noticed EfiPciIoWidthFifoUint32 until you mentioned
>> it.
>> As it seems there isn't even a single line of code in EDK2 that use
>> it. :)
> "MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c" seems to use it,
> doesn't it? From commit 9bfaa3da1ee5 ("MdeModulePkg/SdMmcPciHcDxe: Fix
> PIO transfer mode", 2020-03-05).
>
>> In fact, the only code that use one of the EfiPciIoWidthFifo* is
>> MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c.
>>> (I can imagine that you ruled it out, due to "Desc" being unaligned.
>>> The UEFI spec does say, "The caller is responsible for any alignment
>>> and I/O width issues which the bus, device, platform, or type of I/O
>>> might require.)
>> Why is this an issue?
> If it's not an issue for you, it's definitely not an issue for me. :) I
> didn't know how difficult it would be for you to satisfy such an
> alignment requirement, at all the call sites.
>
>> It's easy to document with one-line comment at end of Desc parameter
>> deceleration that it must be aligned.
> Documenting the requirement is good, but *if* you do that, you can
> *only* do it with a @param[in] marker.
>
>> It's also not difficult to modify callers as only a single caller
>> actually pass a descriptor (The caller PvScsiInitRings()).
> OK.
>
>> To avoid further style comments, what is the coding convention in EDK2
>> to align the "PVSCSI_CMD_DESC_SETUP_RINGS Cmd;" var properly?
> The best I can recommend off-hand is:
>
> union {
>    PVSCSI_CMD_DESC_SETUP_RINGS Cmd;
>    UINT32                      Uint32;
> } AlignAtUint32;
>
> Perhaps someone else can recommend something less awkward.
>
> Note: PVSCSI_CMD_DESC_SETUP_RINGS is a packed structure (and I do agree
> that's good, if at least for documentation purposes). If it weren't
> packed, then the following passage from the UEFI spec would apply:
>
>      2.3.1 Data Types
>
>      Table 5 lists the common data types that are used in the interface
>      definitions, and Table 6 lists their modifiers. Unless otherwise
>      specified all data types are naturally aligned. Structures are
>      aligned on boundaries equal to the largest internal datum of the
>      structure and internal data are implicitly padded to achieve natural
>      alignment.
>
> Because PVSCSI_CMD_DESC_SETUP_RINGS only contains members with types
> listed in Table 5 (namely, UINT32 and UINT64), the above language would
> normally guarantee the proper alignment. *But*, because the structure is
> packed, I don't think we can rely on the spec's description (cf. "unless
> otherwise specified").
>
> So, in theory, there are two options:
>
> - drop the packing (and rely on the natural alignment providing what you
>    need anyway),
>
> - keep the packing, and use other methods to guarantee struct-level
>    alignment (such as the above union).
>
> I prefer keeping the packing, if for nothing else then for documentation
> purposes (it says "wire format" loud and clear). If you use the union
> above, I'll be OK with it.
Ok. I will use this union approach.
Unfortunately, I have seen this comment only after submitting v2.
So I will wait for the rest of your v2 review comments and make sure to 
do this change for v3 as-well.

Thanks.

>
>> In addition, I assume I don't need to add any validation of alignment
>> to PvScsiWriteCmdDesc().
> No, I don't think that's necessary. I think the generic edk2 machinery
> rejects a misaligned memory buffer explicitly, as follows:
>
> (a) The PciIo->Mem.Read/Write members are implemented in PciIoMemRead()
>      / PciIoMemWrite() [MdeModulePkg/Bus/Pci/PciBusDxe/PciIo.c].
>
>      Two comments about them:
>
>      - These functions break up unaligned requests into byte-size
>        requests if "PcdUnalignedPciIoEnable" is TRUE. (Note: it is FALSE
>        for OvmfPkg, and we should not change that.)
>
>      - These functions do not actually check the alignment of either
>        "Buffer" or the MMIO "Offset" within the BAR. They just delegate
>        to PciRootBridgeIo->Mem.Read() and PciRootBridgeIo->Mem.Write().
>
> (b) For those, we need to look at RootBridgeIoMemRead() and
>      RootBridgeIoMemWrite(), in
>      "MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c".
>
>      Both of these functions call RootBridgeIoCheckParameter(),
>      RootBridgeIoCheckParameter() -- which checks the alignment on the
>      MMIO "Address" within the BAR (--> EFI_UNSUPPORTED), but still
>      doesn't check the alignment of "Buffer".
>
>      So, let's continue analyzing RootBridgeIoMemRead() and
>      RootBridgeIoMemWrite()... Once RootBridgeIoCheckParameter() is
>      happy, the work is delegated to CpuIo->Mem.Read/Write.
>
> (c) For those, we need to look at CpuMemoryServiceRead() and
>      CpuMemoryServiceWrite(), in "UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.c".
>
>      These functions call CpuIoCheckParameter(). And that function
>      finally does seem to check the alignment of "Buffer":
>
>    //
>    // Check to see if Buffer is aligned
>    // (IA-32 allows UINT64 and INT64 data types to be 32-bit aligned.)
>    //
>    if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width])  - 1))) != 0) {
>      return EFI_UNSUPPORTED;
>    }
>
>      (See related commit 36de860619c2, "Update the check condition to
>      allows UINT64 and INT64 data types to be 32-bit aligned on IA32
>      system.", 2011-12-01.)
>
> Thus I believe any mis-alignment in "Desc" would be caught for you.

That's what I thought as-well. Thanks for all the details. :)

-Liran



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init
  2020-03-25 16:40         ` Liran Alon
@ 2020-03-25 17:13           ` Liran Alon
  2020-03-27 12:55             ` Laszlo Ersek
  0 siblings, 1 reply; 47+ messages in thread
From: Liran Alon @ 2020-03-25 17:13 UTC (permalink / raw)
  To: Laszlo Ersek, devel
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel


On 25/03/2020 18:40, Liran Alon wrote:
>
> On 25/03/2020 18:31, Laszlo Ersek wrote:
>> On 03/25/20 02:11, Liran Alon wrote:
>>> To avoid further style comments, what is the coding convention in EDK2
>>> to align the "PVSCSI_CMD_DESC_SETUP_RINGS Cmd;" var properly?
>> The best I can recommend off-hand is:
>>
>> union {
>>    PVSCSI_CMD_DESC_SETUP_RINGS Cmd;
>>    UINT32                      Uint32;
>> } AlignAtUint32;
>>
>> Perhaps someone else can recommend something less awkward.
>>
>> Note: PVSCSI_CMD_DESC_SETUP_RINGS is a packed structure (and I do agree
>> that's good, if at least for documentation purposes). If it weren't
>> packed, then the following passage from the UEFI spec would apply:
>>
>>      2.3.1 Data Types
>>
>>      Table 5 lists the common data types that are used in the interface
>>      definitions, and Table 6 lists their modifiers. Unless otherwise
>>      specified all data types are naturally aligned. Structures are
>>      aligned on boundaries equal to the largest internal datum of the
>>      structure and internal data are implicitly padded to achieve 
>> natural
>>      alignment.
>>
>> Because PVSCSI_CMD_DESC_SETUP_RINGS only contains members with types
>> listed in Table 5 (namely, UINT32 and UINT64), the above language would
>> normally guarantee the proper alignment. *But*, because the structure is
>> packed, I don't think we can rely on the spec's description (cf. "unless
>> otherwise specified").
>>
>> So, in theory, there are two options:
>>
>> - drop the packing (and rely on the natural alignment providing what you
>>    need anyway),
>>
>> - keep the packing, and use other methods to guarantee struct-level
>>    alignment (such as the above union).
>>
>> I prefer keeping the packing, if for nothing else then for documentation
>> purposes (it says "wire format" loud and clear). If you use the union
>> above, I'll be OK with it.
> Ok. I will use this union approach.
> Unfortunately, I have seen this comment only after submitting v2.
> So I will wait for the rest of your v2 review comments and make sure 
> to do this change for v3 as-well.
>
> Thanks.
>
Actually, I'm not sure I understand how this union approach helps with 
anything.
Isn't the PVSCSI_CMD_DESC_SETUP_RINGS structure already aligned because 
it have only UINT32 and UINT64 fields?
And if alignment is not guaranteed, how does putting it in a union 
together with another UINT32 provides the required alignment it didn't 
had before?
Because the union itself is not marked with packed(), in contrast to 
PVSCSI_CMD_DESC_SETUP_RINGS?

-Liran



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [edk2-devel] [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init
  2020-03-25 17:13           ` Liran Alon
@ 2020-03-27 12:55             ` Laszlo Ersek
  0 siblings, 0 replies; 47+ messages in thread
From: Laszlo Ersek @ 2020-03-27 12:55 UTC (permalink / raw)
  To: Liran Alon, devel
  Cc: nikita.leshchenko, aaron.young, jordan.l.justen, ard.biesheuvel

On 03/25/20 18:13, Liran Alon wrote:
> 
> On 25/03/2020 18:40, Liran Alon wrote:
>>
>> On 25/03/2020 18:31, Laszlo Ersek wrote:
>>> On 03/25/20 02:11, Liran Alon wrote:
>>>> To avoid further style comments, what is the coding convention in EDK2
>>>> to align the "PVSCSI_CMD_DESC_SETUP_RINGS Cmd;" var properly?
>>> The best I can recommend off-hand is:
>>>
>>> union {
>>>    PVSCSI_CMD_DESC_SETUP_RINGS Cmd;
>>>    UINT32                      Uint32;
>>> } AlignAtUint32;
>>>
>>> Perhaps someone else can recommend something less awkward.
>>>
>>> Note: PVSCSI_CMD_DESC_SETUP_RINGS is a packed structure (and I do agree
>>> that's good, if at least for documentation purposes). If it weren't
>>> packed, then the following passage from the UEFI spec would apply:
>>>
>>>      2.3.1 Data Types
>>>
>>>      Table 5 lists the common data types that are used in the interface
>>>      definitions, and Table 6 lists their modifiers. Unless otherwise
>>>      specified all data types are naturally aligned. Structures are
>>>      aligned on boundaries equal to the largest internal datum of the
>>>      structure and internal data are implicitly padded to achieve
>>> natural
>>>      alignment.
>>>
>>> Because PVSCSI_CMD_DESC_SETUP_RINGS only contains members with types
>>> listed in Table 5 (namely, UINT32 and UINT64), the above language would
>>> normally guarantee the proper alignment. *But*, because the structure is
>>> packed, I don't think we can rely on the spec's description (cf. "unless
>>> otherwise specified").
>>>
>>> So, in theory, there are two options:
>>>
>>> - drop the packing (and rely on the natural alignment providing what you
>>>    need anyway),
>>>
>>> - keep the packing, and use other methods to guarantee struct-level
>>>    alignment (such as the above union).
>>>
>>> I prefer keeping the packing, if for nothing else then for documentation
>>> purposes (it says "wire format" loud and clear). If you use the union
>>> above, I'll be OK with it.
>> Ok. I will use this union approach.
>> Unfortunately, I have seen this comment only after submitting v2.
>> So I will wait for the rest of your v2 review comments and make sure
>> to do this change for v3 as-well.
>>
>> Thanks.
>>
> Actually, I'm not sure I understand how this union approach helps with
> anything.
> Isn't the PVSCSI_CMD_DESC_SETUP_RINGS structure already aligned because
> it have only UINT32 and UINT64 fields?

Yes, that would be sufficient, due to the UEFI spec, and due to edk2
conforming to the UEFI spec the best it can. Except, the structure is
packed.

> And if alignment is not guaranteed, how does putting it in a union
> together with another UINT32 provides the required alignment it didn't
> had before?
> Because the union itself is not marked with packed(), in contrast to
> PVSCSI_CMD_DESC_SETUP_RINGS?

Exactly.

Laszlo


^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2020-03-27 12:55 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-16 15:00 [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller liran.alon
2020-03-16 15:00 ` [PATCH 01/17] OvmfPkg/PvScsiDxe: Create empty driver Liran Alon
2020-03-24 11:15   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:00 ` [PATCH 02/17] OvmfPkg/PvScsiDxe: Install DriverBinding protocol Liran Alon
2020-03-24 11:23   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:00 ` [PATCH 03/17] OvmfPkg/PvScsiDxe: Report name of driver Liran Alon
2020-03-24 11:29   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:01 ` [PATCH 04/17] OvmfPkg/PvScsiDxe: Probe PCI devices and look for PvScsi Liran Alon
2020-03-24 11:41   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:01 ` [PATCH 05/17] OvmfPkg/PvScsiDxe: Install stubbed EXT_SCSI_PASS_THRU Liran Alon
2020-03-24 12:27   ` [edk2-devel] " Laszlo Ersek
2020-03-24 12:47     ` Laszlo Ersek
2020-03-16 15:01 ` [PATCH 06/17] OvmfPkg/PvScsiDxe: Report the number of targets and LUNs Liran Alon
2020-03-24 13:12   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:01 ` [PATCH 07/17] OvmfPkg/PvScsiDxe: Translate Target & LUN to/from DevicePath Liran Alon
2020-03-24 13:36   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:01 ` [PATCH 08/17] OvmfPkg/PvScsiDxe: Open PciIo protocol for later use Liran Alon
2020-03-24 13:47   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:01 ` [PATCH 09/17] OvmfPkg/PvScsiDxe: Backup/Restore PCI attributes on Init/UnInit Liran Alon
2020-03-24 15:14   ` [edk2-devel] " Laszlo Ersek
2020-03-24 15:35     ` Liran Alon
2020-03-25  1:48       ` Laszlo Ersek
2020-03-25 10:32         ` Liran Alon
2020-03-16 15:01 ` [PATCH 10/17] OvmfPkg/PvScsiDxe: Enable IOSpace & Bus-Mastering in PCI attributes Liran Alon
2020-03-24 15:22   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:01 ` [PATCH 11/17] OvmfPkg/PvScsiDxe: Define device interface structures and constants Liran Alon
2020-03-24 15:35   ` [edk2-devel] " Laszlo Ersek
2020-03-24 16:34     ` Laszlo Ersek
2020-03-16 15:01 ` [PATCH 12/17] OvmfPkg/PvScsiDxe: Reset adapter on init Liran Alon
2020-03-24 16:00   ` [edk2-devel] " Laszlo Ersek
2020-03-25  1:11     ` Liran Alon
2020-03-25 16:31       ` Laszlo Ersek
2020-03-25 16:40         ` Liran Alon
2020-03-25 17:13           ` Liran Alon
2020-03-27 12:55             ` Laszlo Ersek
2020-03-16 15:01 ` [PATCH 13/17] OvmfPkg/PvScsiDxe: Setup requests and completions rings Liran Alon
2020-03-24 16:11   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:01 ` [PATCH 14/17] OvmfPkg/PvScsiDxe: Introduce DMA communication buffer Liran Alon
2020-03-24 16:13   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:01 ` [PATCH 15/17] OvmfPkg/PvScsiDxe: Support sending SCSI request and receive response Liran Alon
2020-03-24 16:43   ` [edk2-devel] " Laszlo Ersek
2020-03-25  1:17     ` Liran Alon
2020-03-16 15:01 ` [PATCH 16/17] OvmfPkg/PvScsiDxe: Reset device on ExitBootServices() Liran Alon
2020-03-24 17:04   ` [edk2-devel] " Laszlo Ersek
2020-03-16 15:01 ` [PATCH 17/17] OvmfPkg/PvScsiDxe: Enable device 64-bit DMA addresses Liran Alon
2020-03-24 15:26   ` [edk2-devel] " Laszlo Ersek
2020-03-23 16:33 ` [edk2-devel] [PATCH 00/17]: OvmfPkg: Support booting from VMware PVSCSI controller Laszlo Ersek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox