public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg
@ 2020-07-16  7:45 Gary Lin
  2020-07-16  7:45 ` [PATCH v2 01/12] OvmfPkg/LsiScsiDxe: Create the empty driver Gary Lin
                   ` (11 more replies)
  0 siblings, 12 replies; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:45 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

This patch series implement the driver for LSI 53C895A SCSI controller
for OVMF so that the user can access the storage devices connected to
QEMU "lsi" controller. The driver is disabled by default since LSI
53C895A is considered as a legacy device. To enable the driver, please
add "-D LSI_SCSI_ENABLE" when building OvmfPkg.

The patch series is also available in my git branch:
https://github.com/lcp/edk2/tree/ovmf-lsi-v2

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>

v2:
  - Fix the mixed-case GUID string
  - Remove "STATIC" from LsiScsiControllerSupported()
  - Move the closing of PciIo protocol to the right patch
  - Add asserts for PcdLsiScsiMaxTargetLimit and PcdLsiScsiMaxLunLimit
  - Handle the "Target" array correctly
  - Use BITx macros for the bit constants
  - Replace 0x10000 with SIZE_64KB macro for the DMA buffer data array
  - Remove DUAL_ADDRESS_CYCLE from PciIo since we don't really need
    64-bit DMA address
  - Fix a typo
  - Fix the coding style of the instructions for the script.
  - Improve the error handling in LsiScsiProcessRequest()
  - Calculate the transferred bytes after the execution of the script

Gary Lin (12):
  OvmfPkg/LsiScsiDxe: Create the empty driver
  OvmfPkg/LsiScsiDxe: Install the skeleton of driver binding
  OvmfPkg/LsiScsiDxe: Report the name of the driver
  OvmfPkg/LsiScsiDxe: Probe PCI devices and look for LsiScsi
  OvmfPkg/LsiScsiDxe: Install stubbed EXT_SCSI_PASS_THRU
  OvmfPkg/LsiScsiDxe: Report Targets and LUNs
  OvmfPkg/LsiScsiDxe: Open PciIo protocol and initialize the device
  OvmfPkg/LsiScsiDxe: Map DMA buffer
  OvmfPkg/LsiScsiDxe: Examine the incoming SCSI Request Packet
  OvmfPkg/LsiScsiDxe: Process the SCSI Request Packet
  OvmfPkg/LsiScsiDxe: Calculate the transferred bytes
  Maintainers.txt: Add Gary Lin as the reviewer for LsiScsi driver

 Maintainers.txt                            |    4 +
 OvmfPkg/Include/IndustryStandard/LsiScsi.h |  105 ++
 OvmfPkg/LsiScsiDxe/LsiScsi.c               | 1188 ++++++++++++++++++++
 OvmfPkg/LsiScsiDxe/LsiScsi.h               |  202 ++++
 OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf          |   46 +
 OvmfPkg/OvmfPkg.dec                        |    8 +
 OvmfPkg/OvmfPkgIa32.dsc                    |    4 +
 OvmfPkg/OvmfPkgIa32.fdf                    |    3 +
 OvmfPkg/OvmfPkgIa32X64.dsc                 |    4 +
 OvmfPkg/OvmfPkgIa32X64.fdf                 |    3 +
 OvmfPkg/OvmfPkgX64.dsc                     |    4 +
 OvmfPkg/OvmfPkgX64.fdf                     |    3 +
 12 files changed, 1574 insertions(+)
 create mode 100644 OvmfPkg/Include/IndustryStandard/LsiScsi.h
 create mode 100644 OvmfPkg/LsiScsiDxe/LsiScsi.c
 create mode 100644 OvmfPkg/LsiScsiDxe/LsiScsi.h
 create mode 100644 OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf

-- 
2.25.1


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

* [PATCH v2 01/12] OvmfPkg/LsiScsiDxe: Create the empty driver
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
@ 2020-07-16  7:45 ` Gary Lin
  2020-07-16  7:45 ` [PATCH v2 02/12] OvmfPkg/LsiScsiDxe: Install the skeleton of driver binding Gary Lin
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:45 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

Create the driver with only a dummy LsiScsiEntryPoint() for the further
implementation of the driver for LSI 53C895A SCSI controller.

v2: Fix the mixed-case GUID string

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/LsiScsiDxe/LsiScsi.c      | 25 +++++++++++++++++++++++++
 OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf | 26 ++++++++++++++++++++++++++
 OvmfPkg/OvmfPkgIa32.dsc           |  4 ++++
 OvmfPkg/OvmfPkgIa32.fdf           |  3 +++
 OvmfPkg/OvmfPkgIa32X64.dsc        |  4 ++++
 OvmfPkg/OvmfPkgIa32X64.fdf        |  3 +++
 OvmfPkg/OvmfPkgX64.dsc            |  4 ++++
 OvmfPkg/OvmfPkgX64.fdf            |  3 +++
 8 files changed, 72 insertions(+)
 create mode 100644 OvmfPkg/LsiScsiDxe/LsiScsi.c
 create mode 100644 OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf

diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
new file mode 100644
index 000000000000..9c90941688ed
--- /dev/null
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -0,0 +1,25 @@
+/** @file
+
+  This driver produces Extended SCSI Pass Thru Protocol instances for
+  LSI 53C895A SCSI devices.
+
+  Copyright (C) 2020, SUSE LLC.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiSpec.h>
+
+//
+// Entry point of this driver
+//
+EFI_STATUS
+EFIAPI
+LsiScsiEntryPoint (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
new file mode 100644
index 000000000000..8b6dccaff3eb
--- /dev/null
+++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
@@ -0,0 +1,26 @@
+## @file
+# This driver produces Extended SCSI Pass Thru Protocol instances for
+# LSI 53C895A SCSI devices.
+#
+# Copyright (C) 2020, SUSE LLC.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 1.29
+  BASE_NAME                      = LsiScsiDxe
+  FILE_GUID                      = EB4EB21F-5A3D-40BE-8BD2-F1B0E38E5744
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = LsiScsiEntryPoint
+
+[Sources]
+  LsiScsi.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index b4ee7376791b..9178ffeb71cb 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -50,6 +50,7 @@ [Defines]
   #
   DEFINE PVSCSI_ENABLE           = TRUE
   DEFINE MPT_SCSI_ENABLE         = TRUE
+  DEFINE LSI_SCSI_ENABLE         = FALSE
 
   #
   # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to
@@ -771,6 +772,9 @@ [Components]
 !endif
 !if $(MPT_SCSI_ENABLE) == TRUE
   OvmfPkg/MptScsiDxe/MptScsiDxe.inf
+!endif
+!if $(LSI_SCSI_ENABLE) == TRUE
+  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
 !endif
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
index e2b759aa8d05..2b9a6b58015f 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.fdf
@@ -236,6 +236,9 @@ [FV.DXEFV]
 !if $(MPT_SCSI_ENABLE) == TRUE
 INF  OvmfPkg/MptScsiDxe/MptScsiDxe.inf
 !endif
+!if $(LSI_SCSI_ENABLE) == TRUE
+INF  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
+!endif
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index ed68b080f2a2..a665f78f0dc7 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -49,6 +49,7 @@ [Defines]
   #
   DEFINE PVSCSI_ENABLE           = TRUE
   DEFINE MPT_SCSI_ENABLE         = TRUE
+  DEFINE LSI_SCSI_ENABLE         = FALSE
 
   #
   # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to
@@ -785,6 +786,9 @@ [Components.X64]
 !endif
 !if $(MPT_SCSI_ENABLE) == TRUE
   OvmfPkg/MptScsiDxe/MptScsiDxe.inf
+!endif
+!if $(LSI_SCSI_ENABLE) == TRUE
+  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
 !endif
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
index bfca1eff9e83..83ff6aef2e8c 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -237,6 +237,9 @@ [FV.DXEFV]
 !if $(MPT_SCSI_ENABLE) == TRUE
 INF  OvmfPkg/MptScsiDxe/MptScsiDxe.inf
 !endif
+!if $(LSI_SCSI_ENABLE) == TRUE
+INF  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
+!endif
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index cb7e8068a3d8..17f345acf4ee 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -49,6 +49,7 @@ [Defines]
   #
   DEFINE PVSCSI_ENABLE           = TRUE
   DEFINE MPT_SCSI_ENABLE         = TRUE
+  DEFINE LSI_SCSI_ENABLE         = FALSE
 
   #
   # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to
@@ -781,6 +782,9 @@ [Components]
 !endif
 !if $(MPT_SCSI_ENABLE) == TRUE
   OvmfPkg/MptScsiDxe/MptScsiDxe.inf
+!endif
+!if $(LSI_SCSI_ENABLE) == TRUE
+  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
 !endif
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index bfca1eff9e83..83ff6aef2e8c 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -237,6 +237,9 @@ [FV.DXEFV]
 !if $(MPT_SCSI_ENABLE) == TRUE
 INF  OvmfPkg/MptScsiDxe/MptScsiDxe.inf
 !endif
+!if $(LSI_SCSI_ENABLE) == TRUE
+INF  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
+!endif
 
 !if $(SECURE_BOOT_ENABLE) == TRUE
   INF  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
-- 
2.25.1


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

* [PATCH v2 02/12] OvmfPkg/LsiScsiDxe: Install the skeleton of driver binding
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
  2020-07-16  7:45 ` [PATCH v2 01/12] OvmfPkg/LsiScsiDxe: Create the empty driver Gary Lin
@ 2020-07-16  7:45 ` Gary Lin
  2020-07-16  7:45 ` [PATCH v2 03/12] OvmfPkg/LsiScsiDxe: Report the name of the driver Gary Lin
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:45 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

Implement the dummy functions for EFI Driver Binding protocol.

v2: Remove "STATIC" from LsiScsiControllerSupported()

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/LsiScsiDxe/LsiScsi.c      | 72 ++++++++++++++++++++++++++++++-
 OvmfPkg/LsiScsiDxe/LsiScsi.h      | 49 +++++++++++++++++++++
 OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf |  2 +
 3 files changed, 122 insertions(+), 1 deletion(-)
 create mode 100644 OvmfPkg/LsiScsiDxe/LsiScsi.h

diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
index 9c90941688ed..79a2af4fee73 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -9,8 +9,71 @@
 
 **/
 
+#include <Library/UefiLib.h>
 #include <Uefi/UefiSpec.h>
 
+#include "LsiScsi.h"
+
+//
+// Probe, start and stop functions of this driver, called by the DXE core for
+// specific devices.
+//
+// The following specifications document these interfaces:
+// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
+// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
+//
+
+EFI_STATUS
+EFIAPI
+LsiScsiControllerSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+LsiScsiControllerStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
+  )
+{
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+LsiScsiControllerStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN UINTN                       NumberOfChildren,
+  IN EFI_HANDLE                  *ChildHandleBuffer
+  )
+{
+  return EFI_SUCCESS;
+}
+
+//
+// The static object that groups the Supported() (ie. probe), Start() and
+// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
+// C, 10.1 EFI Driver Binding Protocol.
+//
+STATIC
+EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
+  &LsiScsiControllerSupported,
+  &LsiScsiControllerStart,
+  &LsiScsiControllerStop,
+  0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
+  NULL, // ImageHandle, to be overwritten by
+        // EfiLibInstallDriverBindingComponentName2() in LsiScsiEntryPoint()
+  NULL  // DriverBindingHandle, ditto
+};
+
+
 //
 // Entry point of this driver
 //
@@ -21,5 +84,12 @@ LsiScsiEntryPoint (
   IN EFI_SYSTEM_TABLE *SystemTable
   )
 {
-  return EFI_UNSUPPORTED;
+  return EfiLibInstallDriverBindingComponentName2 (
+           ImageHandle,
+           SystemTable,
+           &gDriverBinding,
+           ImageHandle, // The handle to install onto
+           NULL, // TODO Component name
+           NULL  // TODO Component name
+           );
 }
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
new file mode 100644
index 000000000000..328bd289b8e8
--- /dev/null
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
@@ -0,0 +1,49 @@
+/** @file
+
+  Internal definitions for the LSI 53C895A SCSI driver, which produces
+  Extended SCSI Pass Thru Protocol instances for LSI 53C895A SCSI devices.
+
+  Copyright (C) 2020, SUSE LLC.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _LSI_SCSI_DXE_H_
+#define _LSI_SCSI_DXE_H_
+
+//
+// Probe, start and stop functions of this driver, called by the DXE core for
+// specific devices.
+//
+// The following specifications document these interfaces:
+// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
+// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
+//
+
+EFI_STATUS
+EFIAPI
+LsiScsiControllerSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+LsiScsiControllerStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
+  );
+
+EFI_STATUS
+EFIAPI
+LsiScsiControllerStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  ControllerHandle,
+  IN UINTN                       NumberOfChildren,
+  IN EFI_HANDLE                  *ChildHandleBuffer
+  );
+
+#endif // _LSI_SCSI_DXE_H_
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
index 8b6dccaff3eb..5cb15c456549 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
+++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
@@ -18,9 +18,11 @@ [Defines]
 
 [Sources]
   LsiScsi.c
+  LsiScsi.h
 
 [Packages]
   MdePkg/MdePkg.dec
 
 [LibraryClasses]
   UefiDriverEntryPoint
+  UefiLib
-- 
2.25.1


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

* [PATCH v2 03/12] OvmfPkg/LsiScsiDxe: Report the name of the driver
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
  2020-07-16  7:45 ` [PATCH v2 01/12] OvmfPkg/LsiScsiDxe: Create the empty driver Gary Lin
  2020-07-16  7:45 ` [PATCH v2 02/12] OvmfPkg/LsiScsiDxe: Install the skeleton of driver binding Gary Lin
@ 2020-07-16  7:45 ` Gary Lin
  2020-07-16  7:45 ` [PATCH v2 04/12] OvmfPkg/LsiScsiDxe: Probe PCI devices and look for LsiScsi Gary Lin
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:45 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

Implement LsiScsiGetDriverName() and LsiScsiGetDeviceName()
to report the name of the driver.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/LsiScsiDxe/LsiScsi.c | 69 ++++++++++++++++++++++++++++++++++--
 OvmfPkg/LsiScsiDxe/LsiScsi.h | 31 ++++++++++++++++
 2 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
index 79a2af4fee73..62daa3ab99bf 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -74,6 +74,71 @@ EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
 };
 
 
+//
+// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
+// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
+// in English, for display on standard console devices. This is recommended for
+// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
+// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
+//
+// Device type names ("LSI 53C895A SCSI Controller") are not formatted because
+// the driver supports only that device type. Therefore the driver name
+// suffices for unambiguous identification.
+//
+
+STATIC
+EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
+  { "eng;en", L"LSI 53C895A SCSI Controller Driver" },
+  { NULL,     NULL                                  }
+};
+
+STATIC
+EFI_COMPONENT_NAME_PROTOCOL gComponentName;
+
+EFI_STATUS
+EFIAPI
+LsiScsiGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gComponentName) // Iso639Language
+           );
+}
+
+EFI_STATUS
+EFIAPI
+LsiScsiGetDeviceName (
+  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 gComponentName = {
+  &LsiScsiGetDriverName,
+  &LsiScsiGetDeviceName,
+  "eng" // SupportedLanguages, ISO 639-2 language codes
+};
+
+STATIC
+EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &LsiScsiGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &LsiScsiGetDeviceName,
+  "en" // SupportedLanguages, RFC 4646 language codes
+};
+
 //
 // Entry point of this driver
 //
@@ -89,7 +154,7 @@ LsiScsiEntryPoint (
            SystemTable,
            &gDriverBinding,
            ImageHandle, // The handle to install onto
-           NULL, // TODO Component name
-           NULL  // TODO Component name
+           &gComponentName,
+           &gComponentName2
            );
 }
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
index 328bd289b8e8..6c8dcbd70a0a 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
@@ -46,4 +46,35 @@ LsiScsiControllerStop (
   IN EFI_HANDLE                  *ChildHandleBuffer
   );
 
+
+//
+// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
+// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
+// in English, for display on standard console devices. This is recommended for
+// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
+// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
+//
+// Device type names ("LSI 53C895A SCSI Controller") are not formatted because
+// the driver supports only that device type. Therefore the driver name
+// suffices for unambiguous identification.
+//
+
+EFI_STATUS
+EFIAPI
+LsiScsiGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **DriverName
+  );
+
+EFI_STATUS
+EFIAPI
+LsiScsiGetDeviceName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  EFI_HANDLE                  DeviceHandle,
+  IN  EFI_HANDLE                  ChildHandle,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **ControllerName
+  );
+
 #endif // _LSI_SCSI_DXE_H_
-- 
2.25.1


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

* [PATCH v2 04/12] OvmfPkg/LsiScsiDxe: Probe PCI devices and look for LsiScsi
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
                   ` (2 preceding siblings ...)
  2020-07-16  7:45 ` [PATCH v2 03/12] OvmfPkg/LsiScsiDxe: Report the name of the driver Gary Lin
@ 2020-07-16  7:45 ` Gary Lin
  2020-07-16  7:46 ` [PATCH v2 05/12] OvmfPkg/LsiScsiDxe: Install stubbed EXT_SCSI_PASS_THRU Gary Lin
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:45 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

Implement LsiScsiControllerSupported() to probe the PCI ID and look for
LSI 53C895A.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/Include/IndustryStandard/LsiScsi.h | 20 +++++++++
 OvmfPkg/LsiScsiDxe/LsiScsi.c               | 48 +++++++++++++++++++++-
 OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf          |  6 +++
 3 files changed, 73 insertions(+), 1 deletion(-)
 create mode 100644 OvmfPkg/Include/IndustryStandard/LsiScsi.h

diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
new file mode 100644
index 000000000000..c09e864a1f39
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
@@ -0,0 +1,20 @@
+/** @file
+
+  Macros and type definitions for LSI 53C895A SCSI devices.
+
+  Copyright (C) 2020, SUSE LLC.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _LSI_SCSI_H_
+#define _LSI_SCSI_H_
+
+//
+// Device ID
+//
+#define LSI_LOGIC_PCI_VENDOR_ID   0x1000
+#define LSI_53C895A_PCI_DEVICE_ID 0x0012
+
+#endif // _LSI_SCSI_H_
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
index 62daa3ab99bf..5bca85bd75eb 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -9,7 +9,12 @@
 
 **/
 
+#include <IndustryStandard/LsiScsi.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/PciRootBridgeIo.h>
 #include <Uefi/UefiSpec.h>
 
 #include "LsiScsi.h"
@@ -31,7 +36,48 @@ LsiScsiControllerSupported (
   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 == LSI_LOGIC_PCI_VENDOR_ID &&
+      Pci.Hdr.DeviceId == LSI_53C895A_PCI_DEVICE_ID) {
+    Status = EFI_SUCCESS;
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+Done:
+  gBS->CloseProtocol (
+         ControllerHandle,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         ControllerHandle
+         );
+  return Status;
 }
 
 EFI_STATUS
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
index 5cb15c456549..7ce11fcc6a03 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
+++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
@@ -22,7 +22,13 @@ [Sources]
 
 [Packages]
   MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
 
 [LibraryClasses]
+  BaseLib
+  UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiLib
+
+[Protocols]
+  gEfiPciIoProtocolGuid                  ## TO_START
-- 
2.25.1


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

* [PATCH v2 05/12] OvmfPkg/LsiScsiDxe: Install stubbed EXT_SCSI_PASS_THRU
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
                   ` (3 preceding siblings ...)
  2020-07-16  7:45 ` [PATCH v2 04/12] OvmfPkg/LsiScsiDxe: Probe PCI devices and look for LsiScsi Gary Lin
@ 2020-07-16  7:46 ` Gary Lin
  2020-07-16  7:46 ` [PATCH v2 06/12] OvmfPkg/LsiScsiDxe: Report Targets and LUNs Gary Lin
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:46 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

Partially implement LsiScsiControllerStart() and LsiScsiControllerStop()
to insert the scaffolding of EXT_SCSI_PASS_THRU functions.

v2: Remove the closing of PciIo protocol from LsiScsiControllerStop().

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/LsiScsiDxe/LsiScsi.c      | 164 +++++++++++++++++++++++++++++-
 OvmfPkg/LsiScsiDxe/LsiScsi.h      |  77 ++++++++++++++
 OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf |   3 +
 3 files changed, 243 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
index 5bca85bd75eb..67fadb411e85 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -11,14 +11,105 @@
 
 #include <IndustryStandard/LsiScsi.h>
 #include <IndustryStandard/Pci.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
 #include <Protocol/PciIo.h>
 #include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/ScsiPassThruExt.h>
 #include <Uefi/UefiSpec.h>
 
 #include "LsiScsi.h"
 
+//
+// The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
+// for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
+// sections
+// - 14.1 SCSI Driver Model Overview,
+// - 14.7 Extended SCSI Pass Thru Protocol.
+//
+
+EFI_STATUS
+EFIAPI
+LsiScsiPassThru (
+  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;
+}
+
+EFI_STATUS
+EFIAPI
+LsiScsiGetNextTargetLun (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+  IN OUT UINT8                       **TargetPointer,
+  IN OUT UINT64                      *Lun
+  )
+{
+  return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+EFIAPI
+LsiScsiBuildDevicePath (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+  IN UINT8                           *Target,
+  IN UINT64                          Lun,
+  IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath
+  )
+{
+  return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+EFIAPI
+LsiScsiGetTargetLun (
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,
+  OUT UINT8                           **TargetPointer,
+  OUT UINT64                          *Lun
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+LsiScsiResetChannel (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+LsiScsiResetTargetLun (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+  IN UINT8                           *Target,
+  IN UINT64                          Lun
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+LsiScsiGetNextTarget (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+  IN OUT UINT8                       **TargetPointer
+  )
+{
+  return EFI_NOT_FOUND;
+}
+
 //
 // Probe, start and stop functions of this driver, called by the DXE core for
 // specific devices.
@@ -88,7 +179,49 @@ LsiScsiControllerStart (
   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL
   )
 {
+  EFI_STATUS           Status;
+  LSI_SCSI_DEV         *Dev;
+
+  Dev = AllocateZeroPool (sizeof (*Dev));
+  if (Dev == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Dev->Signature = LSI_SCSI_DEV_SIGNATURE;
+
+  //
+  // Host adapter channel, doesn't exist
+  //
+  Dev->PassThruMode.AdapterId = MAX_UINT32;
+  Dev->PassThruMode.Attributes =
+    EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
+    EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
+
+  Dev->PassThru.Mode = &Dev->PassThruMode;
+  Dev->PassThru.PassThru = &LsiScsiPassThru;
+  Dev->PassThru.GetNextTargetLun = &LsiScsiGetNextTargetLun;
+  Dev->PassThru.BuildDevicePath = &LsiScsiBuildDevicePath;
+  Dev->PassThru.GetTargetLun = &LsiScsiGetTargetLun;
+  Dev->PassThru.ResetChannel = &LsiScsiResetChannel;
+  Dev->PassThru.ResetTargetLun = &LsiScsiResetTargetLun;
+  Dev->PassThru.GetNextTarget = &LsiScsiGetNextTarget;
+
+  Status = gBS->InstallProtocolInterface (
+                  &ControllerHandle,
+                  &gEfiExtScsiPassThruProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &Dev->PassThru
+                  );
+  if (EFI_ERROR (Status)) {
+    goto FreePool;
+  }
+
   return EFI_SUCCESS;
+
+FreePool:
+  FreePool (Dev);
+
+  return Status;
 }
 
 EFI_STATUS
@@ -100,7 +233,36 @@ LsiScsiControllerStop (
   IN EFI_HANDLE                  *ChildHandleBuffer
   )
 {
-  return EFI_SUCCESS;
+  EFI_STATUS                      Status;
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
+  LSI_SCSI_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 = LSI_SCSI_FROM_PASS_THRU (PassThru);
+
+  Status = gBS->UninstallProtocolInterface (
+                  ControllerHandle,
+                  &gEfiExtScsiPassThruProtocolGuid,
+                  &Dev->PassThru
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  FreePool (Dev);
+
+  return Status;
 }
 
 //
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
index 6c8dcbd70a0a..c194dfbf3347 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
@@ -12,6 +12,17 @@
 #ifndef _LSI_SCSI_DXE_H_
 #define _LSI_SCSI_DXE_H_
 
+typedef struct {
+  UINT32                          Signature;
+  EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
+} LSI_SCSI_DEV;
+
+#define LSI_SCSI_DEV_SIGNATURE SIGNATURE_32 ('L','S','I','S')
+
+#define LSI_SCSI_FROM_PASS_THRU(PassThruPtr) \
+  CR (PassThruPtr, LSI_SCSI_DEV, PassThru, LSI_SCSI_DEV_SIGNATURE)
+
 //
 // Probe, start and stop functions of this driver, called by the DXE core for
 // specific devices.
@@ -47,6 +58,72 @@ LsiScsiControllerStop (
   );
 
 
+//
+// The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
+// for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
+// sections
+// - 14.1 SCSI Driver Model Overview,
+// - 14.7 Extended SCSI Pass Thru Protocol.
+//
+
+EFI_STATUS
+EFIAPI
+LsiScsiPassThru (
+  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
+  );
+
+EFI_STATUS
+EFIAPI
+LsiScsiGetNextTargetLun (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+  IN OUT UINT8                       **TargetPointer,
+  IN OUT UINT64                      *Lun
+  );
+
+EFI_STATUS
+EFIAPI
+LsiScsiBuildDevicePath (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+  IN UINT8                           *Target,
+  IN UINT64                          Lun,
+  IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath
+  );
+
+EFI_STATUS
+EFIAPI
+LsiScsiGetTargetLun (
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,
+  OUT UINT8                           **TargetPointer,
+  OUT UINT64                          *Lun
+  );
+
+EFI_STATUS
+EFIAPI
+LsiScsiResetChannel (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
+  );
+
+EFI_STATUS
+EFIAPI
+LsiScsiResetTargetLun (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+  IN UINT8                           *Target,
+  IN UINT64                          Lun
+  );
+
+EFI_STATUS
+EFIAPI
+LsiScsiGetNextTarget (
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
+  IN OUT UINT8                       **TargetPointer
+  );
+
+
 //
 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
index 7ce11fcc6a03..14f9c68308cc 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
+++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
@@ -26,9 +26,12 @@ [Packages]
 
 [LibraryClasses]
   BaseLib
+  BaseMemoryLib
+  MemoryAllocationLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiLib
 
 [Protocols]
+  gEfiExtScsiPassThruProtocolGuid        ## BY_START
   gEfiPciIoProtocolGuid                  ## TO_START
-- 
2.25.1


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

* [PATCH v2 06/12] OvmfPkg/LsiScsiDxe: Report Targets and LUNs
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
                   ` (4 preceding siblings ...)
  2020-07-16  7:46 ` [PATCH v2 05/12] OvmfPkg/LsiScsiDxe: Install stubbed EXT_SCSI_PASS_THRU Gary Lin
@ 2020-07-16  7:46 ` Gary Lin
  2020-07-16 15:04   ` Laszlo Ersek
  2020-07-16  7:46 ` [PATCH v2 07/12] OvmfPkg/LsiScsiDxe: Open PciIo protocol and initialize the device Gary Lin
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:46 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

Implement LsiScsiGetNextTargetLun(), LsiScsiBuildDevicePath(),
LsiScsiGetTargetLun(), and LsiScsiGetNextTarget() to report Targets and
LUNs and build the device path.

This commit also introduces two PCD value: PcdLsiScsiMaxTargetLimit and
PcdLsiScsiMaxLunLimit as the limits for Targets and LUNs.

v2:
  - Zero out (*Target) in LsiScsiGetTargetLun()
  - Use CopyMem() instead of the one-byte shortcut to copy target from
    ScsiDevicePath->Pun
  - Add asserts for PcdLsiScsiMaxTargetLimit and PcdLsiScsiMaxLunLimit

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
---
 OvmfPkg/LsiScsiDxe/LsiScsi.c      | 148 +++++++++++++++++++++++++++++-
 OvmfPkg/LsiScsiDxe/LsiScsi.h      |   3 +
 OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf |   6 ++
 OvmfPkg/OvmfPkg.dec               |   5 +
 4 files changed, 160 insertions(+), 2 deletions(-)

diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
index 67fadb411e85..989bda88d209 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -15,6 +15,7 @@
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
 #include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
 #include <Protocol/PciIo.h>
@@ -53,6 +54,49 @@ LsiScsiGetNextTargetLun (
   IN OUT UINT64                      *Lun
   )
 {
+  LSI_SCSI_DEV *Dev;
+  UINTN        Idx;
+  UINT8        *Target;
+  UINT16       LastTarget;
+
+  //
+  // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
+  //
+  Target = *TargetPointer;
+
+  //
+  // Search for first non-0xFF byte. If not found, return first target & LUN.
+  //
+  for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)
+    ;
+  if (Idx == TARGET_MAX_BYTES) {
+    SetMem (Target, TARGET_MAX_BYTES, 0x00);
+    *Lun = 0;
+    return EFI_SUCCESS;
+  }
+
+  CopyMem (&LastTarget, Target, sizeof LastTarget);
+
+  //
+  // increment (target, LUN) pair if valid on input
+  //
+  Dev = LSI_SCSI_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;
+    CopyMem (Target, &LastTarget, sizeof LastTarget);
+    return EFI_SUCCESS;
+  }
+
   return EFI_NOT_FOUND;
 }
 
@@ -65,7 +109,34 @@ LsiScsiBuildDevicePath (
   IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath
   )
 {
-  return EFI_NOT_FOUND;
+  UINT16           TargetValue;
+  LSI_SCSI_DEV     *Dev;
+  SCSI_DEVICE_PATH *ScsiDevicePath;
+
+  if (DevicePath == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CopyMem (&TargetValue, Target, sizeof TargetValue);
+  Dev = LSI_SCSI_FROM_PASS_THRU (This);
+  if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun || Lun > 0xFFFF) {
+    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;
 }
 
 EFI_STATUS
@@ -77,7 +148,33 @@ LsiScsiGetTargetLun (
   OUT UINT64                          *Lun
   )
 {
-  return EFI_UNSUPPORTED;
+  SCSI_DEVICE_PATH *ScsiDevicePath;
+  LSI_SCSI_DEV     *Dev;
+  UINT8            *Target;
+
+  if (DevicePath == NULL || TargetPointer == NULL || *TargetPointer == 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 = LSI_SCSI_FROM_PASS_THRU (This);
+  if (ScsiDevicePath->Pun > Dev->MaxTarget ||
+      ScsiDevicePath->Lun > Dev->MaxLun) {
+    return EFI_NOT_FOUND;
+  }
+
+  Target = *TargetPointer;
+  ZeroMem (Target, TARGET_MAX_BYTES);
+  CopyMem (Target, &ScsiDevicePath->Pun, sizeof ScsiDevicePath->Pun);
+  *Lun = ScsiDevicePath->Lun;
+
+  return EFI_SUCCESS;
 }
 
 EFI_STATUS
@@ -107,6 +204,42 @@ LsiScsiGetNextTarget (
   IN OUT UINT8                       **TargetPointer
   )
 {
+  LSI_SCSI_DEV *Dev;
+  UINTN        Idx;
+  UINT8        *Target;
+  UINT16       LastTarget;
+
+  //
+  // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
+  //
+  Target = *TargetPointer;
+
+  //
+  // Search for first non-0xFF byte. If not found, return first target.
+  //
+  for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)
+    ;
+  if (Idx == TARGET_MAX_BYTES) {
+    SetMem (Target, TARGET_MAX_BYTES, 0x00);
+    return EFI_SUCCESS;
+  }
+
+  CopyMem (&LastTarget, Target, sizeof LastTarget);
+
+  //
+  // increment target if valid on input
+  //
+  Dev = LSI_SCSI_FROM_PASS_THRU (This);
+  if (LastTarget > Dev->MaxTarget) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (LastTarget < Dev->MaxTarget) {
+    ++LastTarget;
+    CopyMem (Target, &LastTarget, sizeof LastTarget);
+    return EFI_SUCCESS;
+  }
+
   return EFI_NOT_FOUND;
 }
 
@@ -189,6 +322,17 @@ LsiScsiControllerStart (
 
   Dev->Signature = LSI_SCSI_DEV_SIGNATURE;
 
+  STATIC_ASSERT (
+    FixedPcdGet8 (PcdLsiScsiMaxTargetLimit) < 8,
+    "LSI 53C895A supports targets [0..7]"
+    );
+  STATIC_ASSERT (
+    FixedPcdGet8 (PcdLsiScsiMaxLunLimit) < 128,
+    "LSI 53C895A supports LUNs [0..128]"
+    );
+  Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);
+  Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);
+
   //
   // Host adapter channel, doesn't exist
   //
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
index c194dfbf3347..6c6ed25f1c33 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
@@ -14,6 +14,8 @@
 
 typedef struct {
   UINT32                          Signature;
+  UINT8                           MaxTarget;
+  UINT8                           MaxLun;
   EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
   EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
 } LSI_SCSI_DEV;
@@ -23,6 +25,7 @@ typedef struct {
 #define LSI_SCSI_FROM_PASS_THRU(PassThruPtr) \
   CR (PassThruPtr, LSI_SCSI_DEV, PassThru, LSI_SCSI_DEV_SIGNATURE)
 
+
 //
 // Probe, start and stop functions of this driver, called by the DXE core for
 // specific devices.
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
index 14f9c68308cc..6111449577a8 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
+++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
@@ -27,7 +27,9 @@ [Packages]
 [LibraryClasses]
   BaseLib
   BaseMemoryLib
+  DebugLib
   MemoryAllocationLib
+  PcdLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
   UefiLib
@@ -35,3 +37,7 @@ [LibraryClasses]
 [Protocols]
   gEfiExtScsiPassThruProtocolGuid        ## BY_START
   gEfiPciIoProtocolGuid                  ## TO_START
+
+[FixedPcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit   ## CONSUMES
+  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit      ## CONSUMES
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 2b0f137cbcce..ca13a3cb11d3 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -174,6 +174,11 @@ [PcdsFixedAtBuild]
   ## Microseconds to stall between polling for MptScsi request result
   gUefiOvmfPkgTokenSpaceGuid.PcdMptScsiStallPerPollUsec|5|UINT32|0x3a
 
+  ## Set the *inclusive* number of targets and LUNs that LsiScsi exposes for
+  #  scan by ScsiBusDxe.
+  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit|7|UINT8|0x3b
+  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit|0|UINT8|0x3c
+
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogBase|0x0|UINT32|0x8
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogSize|0x0|UINT32|0x9
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize|0x0|UINT32|0xa
-- 
2.25.1


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

* [PATCH v2 07/12] OvmfPkg/LsiScsiDxe: Open PciIo protocol and initialize the device
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
                   ` (5 preceding siblings ...)
  2020-07-16  7:46 ` [PATCH v2 06/12] OvmfPkg/LsiScsiDxe: Report Targets and LUNs Gary Lin
@ 2020-07-16  7:46 ` Gary Lin
  2020-07-16 16:07   ` Laszlo Ersek
  2020-07-16  7:46 ` [PATCH v2 08/12] OvmfPkg/LsiScsiDxe: Map DMA buffer Gary Lin
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:46 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

Open PciIo protocol and use it to initialize the device. The
initialization of LSI 53C895A is simple: just set the SRST bit in
Interrupt Status Zero register to reset the device.

v2:
  - Use the BITx macros for the bit constants
  - Add the closing of PciIo protocol in LsiScsiControllerStop()

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
---
 OvmfPkg/Include/IndustryStandard/LsiScsi.h |  21 ++++
 OvmfPkg/LsiScsiDxe/LsiScsi.c               | 136 ++++++++++++++++++++-
 OvmfPkg/LsiScsiDxe/LsiScsi.h               |   3 +
 3 files changed, 159 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
index c09e864a1f39..185e553c8eb4 100644
--- a/OvmfPkg/Include/IndustryStandard/LsiScsi.h
+++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
@@ -17,4 +17,25 @@
 #define LSI_LOGIC_PCI_VENDOR_ID   0x1000
 #define LSI_53C895A_PCI_DEVICE_ID 0x0012
 
+//
+// LSI 53C895A Registers
+//
+#define LSI_REG_DSTAT             0x0C
+#define LSI_REG_ISTAT0            0x14
+#define LSI_REG_DSP               0x2C
+#define LSI_REG_SIST0             0x42
+#define LSI_REG_SIST1             0x43
+
+//
+// The status bits for Interrupt Status Zero (ISTAT0)
+//
+#define LSI_ISTAT0_DIP            BIT0
+#define LSI_ISTAT0_SIP            BIT1
+#define LSI_ISTAT0_INTF           BIT2
+#define LSI_ISTAT0_CON            BIT3
+#define LSI_ISTAT0_SEM            BIT4
+#define LSI_ISTAT0_SIGP           BIT5
+#define LSI_ISTAT0_SRST           BIT6
+#define LSI_ISTAT0_ABRT           BIT7
+
 #endif // _LSI_SCSI_H_
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
index 989bda88d209..b21387db6e5a 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -25,6 +25,33 @@
 
 #include "LsiScsi.h"
 
+STATIC
+EFI_STATUS
+Out8 (
+  IN LSI_SCSI_DEV *Dev,
+  IN UINT32       Addr,
+  IN UINT8        Data
+  )
+{
+  return Dev->PciIo->Io.Write (
+                          Dev->PciIo,
+                          EfiPciIoWidthUint8,
+                          PCI_BAR_IDX0,
+                          Addr,
+                          1,
+                          &Data
+                          );
+}
+
+STATIC
+EFI_STATUS
+LsiScsiReset (
+  IN LSI_SCSI_DEV *Dev
+  )
+{
+  return Out8 (Dev, LSI_REG_ISTAT0, LSI_ISTAT0_SRST);
+}
+
 //
 // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
 // for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
@@ -243,6 +270,21 @@ LsiScsiGetNextTarget (
   return EFI_NOT_FOUND;
 }
 
+STATIC
+VOID
+EFIAPI
+LsiScsiExitBoot (
+  IN  EFI_EVENT Event,
+  IN  VOID      *Context
+  )
+{
+  LSI_SCSI_DEV *Dev;
+
+  Dev = Context;
+  DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
+  LsiScsiReset (Dev);
+}
+
 //
 // Probe, start and stop functions of this driver, called by the DXE core for
 // specific devices.
@@ -333,6 +375,58 @@ LsiScsiControllerStart (
   Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);
   Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);
 
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **)&Dev->PciIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    goto FreePool;
+  }
+
+  Status = Dev->PciIo->Attributes (
+                         Dev->PciIo,
+                         EfiPciIoAttributeOperationGet,
+                         0,
+                         &Dev->OrigPciAttrs
+                         );
+  if (EFI_ERROR (Status)) {
+    goto CloseProtocol;
+  }
+
+  //
+  // Enable I/O Space & Bus-Mastering
+  //
+  Status = Dev->PciIo->Attributes (
+                         Dev->PciIo,
+                         EfiPciIoAttributeOperationEnable,
+                         (EFI_PCI_IO_ATTRIBUTE_IO |
+                          EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
+                         NULL
+                         );
+  if (EFI_ERROR (Status)) {
+    goto CloseProtocol;
+  }
+
+  Status = LsiScsiReset (Dev);
+  if (EFI_ERROR (Status)) {
+    goto RestoreAttributes;
+  }
+
+  Status = gBS->CreateEvent (
+                  EVT_SIGNAL_EXIT_BOOT_SERVICES,
+                  TPL_CALLBACK,
+                  &LsiScsiExitBoot,
+                  Dev,
+                  &Dev->ExitBoot
+                  );
+  if (EFI_ERROR (Status)) {
+    goto UninitDev;
+  }
+
   //
   // Host adapter channel, doesn't exist
   //
@@ -357,11 +451,33 @@ LsiScsiControllerStart (
                   &Dev->PassThru
                   );
   if (EFI_ERROR (Status)) {
-    goto FreePool;
+    goto CloseExitBoot;
   }
 
   return EFI_SUCCESS;
 
+CloseExitBoot:
+  gBS->CloseEvent (Dev->ExitBoot);
+
+UninitDev:
+  LsiScsiReset (Dev);
+
+RestoreAttributes:
+  Dev->PciIo->Attributes (
+                Dev->PciIo,
+                EfiPciIoAttributeOperationSet,
+                Dev->OrigPciAttrs,
+                NULL
+                );
+
+CloseProtocol:
+  gBS->CloseProtocol (
+         ControllerHandle,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         ControllerHandle
+         );
+
 FreePool:
   FreePool (Dev);
 
@@ -404,6 +520,24 @@ LsiScsiControllerStop (
     return Status;
   }
 
+  gBS->CloseEvent (Dev->ExitBoot);
+
+  LsiScsiReset (Dev);
+
+  Dev->PciIo->Attributes (
+                Dev->PciIo,
+                EfiPciIoAttributeOperationSet,
+                Dev->OrigPciAttrs,
+                NULL
+                );
+
+  gBS->CloseProtocol (
+         ControllerHandle,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         ControllerHandle
+         );
+
   FreePool (Dev);
 
   return Status;
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
index 6c6ed25f1c33..8c2acff6e86f 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
@@ -14,6 +14,9 @@
 
 typedef struct {
   UINT32                          Signature;
+  UINT64                          OrigPciAttrs;
+  EFI_EVENT                       ExitBoot;
+  EFI_PCI_IO_PROTOCOL             *PciIo;
   UINT8                           MaxTarget;
   UINT8                           MaxLun;
   EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
-- 
2.25.1


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

* [PATCH v2 08/12] OvmfPkg/LsiScsiDxe: Map DMA buffer
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
                   ` (6 preceding siblings ...)
  2020-07-16  7:46 ` [PATCH v2 07/12] OvmfPkg/LsiScsiDxe: Open PciIo protocol and initialize the device Gary Lin
@ 2020-07-16  7:46 ` Gary Lin
  2020-07-16 16:11   ` Laszlo Ersek
  2020-07-16  7:46 ` [PATCH v2 09/12] OvmfPkg/LsiScsiDxe: Examine the incoming SCSI Request Packet Gary Lin
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:46 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

Map DMA buffer and perpare for the implementation of LsiScsiPassThru().

v2:
  - Replace 0x10000 with SIZE_64KB macro for the DMA buffer data array
  - Remove DUAL_ADDRESS_CYCLE from PciIo since we don't really need
    64-bit DMA address

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/LsiScsiDxe/LsiScsi.c | 62 +++++++++++++++++++++++++++++++++++-
 OvmfPkg/LsiScsiDxe/LsiScsi.h | 14 ++++++++
 2 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
index b21387db6e5a..4e84afa40085 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -356,6 +356,8 @@ LsiScsiControllerStart (
 {
   EFI_STATUS           Status;
   LSI_SCSI_DEV         *Dev;
+  UINTN                Pages;
+  UINTN                BytesMapped;
 
   Dev = AllocateZeroPool (sizeof (*Dev));
   if (Dev == NULL) {
@@ -411,11 +413,45 @@ LsiScsiControllerStart (
     goto CloseProtocol;
   }
 
-  Status = LsiScsiReset (Dev);
+  //
+  // Create buffers for data transfer
+  //
+  Pages = EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma));
+  Status = Dev->PciIo->AllocateBuffer (
+                         Dev->PciIo,
+                         AllocateAnyPages,
+                         EfiBootServicesData,
+                         Pages,
+                         (VOID **)&Dev->Dma,
+                         EFI_PCI_ATTRIBUTE_MEMORY_CACHED
+                         );
   if (EFI_ERROR (Status)) {
     goto RestoreAttributes;
   }
 
+  BytesMapped = EFI_PAGES_TO_SIZE (Pages);
+  Status = Dev->PciIo->Map (
+                         Dev->PciIo,
+                         EfiPciIoOperationBusMasterCommonBuffer,
+                         Dev->Dma,
+                         &BytesMapped,
+                         &Dev->DmaPhysical,
+                         &Dev->DmaMapping
+                         );
+  if (EFI_ERROR (Status)) {
+    goto FreeBuffer;
+  }
+
+  if (BytesMapped != EFI_PAGES_TO_SIZE (Pages)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Unmap;
+  }
+
+  Status = LsiScsiReset (Dev);
+  if (EFI_ERROR (Status)) {
+    goto Unmap;
+  }
+
   Status = gBS->CreateEvent (
                   EVT_SIGNAL_EXIT_BOOT_SERVICES,
                   TPL_CALLBACK,
@@ -462,6 +498,19 @@ CloseExitBoot:
 UninitDev:
   LsiScsiReset (Dev);
 
+Unmap:
+  Dev->PciIo->Unmap (
+                Dev->PciIo,
+                Dev->DmaMapping
+                );
+
+FreeBuffer:
+  Dev->PciIo->FreeBuffer (
+                Dev->PciIo,
+                Pages,
+                Dev->Dma
+                );
+
 RestoreAttributes:
   Dev->PciIo->Attributes (
                 Dev->PciIo,
@@ -524,6 +573,17 @@ LsiScsiControllerStop (
 
   LsiScsiReset (Dev);
 
+  Dev->PciIo->Unmap (
+                Dev->PciIo,
+                Dev->DmaMapping
+                );
+
+  Dev->PciIo->FreeBuffer (
+                Dev->PciIo,
+                EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma)),
+                Dev->Dma
+                );
+
   Dev->PciIo->Attributes (
                 Dev->PciIo,
                 EfiPciIoAttributeOperationSet,
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
index 8c2acff6e86f..9f9e5c7fed00 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
@@ -12,6 +12,17 @@
 #ifndef _LSI_SCSI_DXE_H_
 #define _LSI_SCSI_DXE_H_
 
+typedef struct {
+  //
+  // Allocate 64KB for read/write buffer. It seems sufficient for the common
+  // boot scenarios.
+  //
+  // NOTE: The number of bytes for data transmission is bounded by DMA Byte
+  //       Count (DBC), a 24-bit register, so the maximum is 0xFFFFFF (16MB-1).
+  //
+  UINT8                           Data[SIZE_64KB];
+} LSI_SCSI_DMA_BUFFER;
+
 typedef struct {
   UINT32                          Signature;
   UINT64                          OrigPciAttrs;
@@ -19,6 +30,9 @@ typedef struct {
   EFI_PCI_IO_PROTOCOL             *PciIo;
   UINT8                           MaxTarget;
   UINT8                           MaxLun;
+  LSI_SCSI_DMA_BUFFER             *Dma;
+  EFI_PHYSICAL_ADDRESS            DmaPhysical;
+  VOID                            *DmaMapping;
   EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
   EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
 } LSI_SCSI_DEV;
-- 
2.25.1


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

* [PATCH v2 09/12] OvmfPkg/LsiScsiDxe: Examine the incoming SCSI Request Packet
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
                   ` (7 preceding siblings ...)
  2020-07-16  7:46 ` [PATCH v2 08/12] OvmfPkg/LsiScsiDxe: Map DMA buffer Gary Lin
@ 2020-07-16  7:46 ` Gary Lin
  2020-07-16  7:46 ` [PATCH v2 10/12] OvmfPkg/LsiScsiDxe: Process the " Gary Lin
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:46 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

This is the first part of LsiScsiPassThru(). Before processing the SCSI
Request packet, we have to make sure whether the packet is valid or not.

v2: Make LsiScsiPassThru() return EFI_UNSUPPORTED since this function is
    half-implemented

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/LsiScsiDxe/LsiScsi.c | 98 ++++++++++++++++++++++++++++++++++++
 OvmfPkg/LsiScsiDxe/LsiScsi.h |  4 ++
 2 files changed, 102 insertions(+)

diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
index 4e84afa40085..b3a88cc7119b 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -52,6 +52,95 @@ LsiScsiReset (
   return Out8 (Dev, LSI_REG_ISTAT0, LSI_ISTAT0_SRST);
 }
 
+STATIC
+EFI_STATUS
+ReportHostAdapterOverrunError (
+  OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+  )
+{
+  Packet->SenseDataLength = 0;
+  Packet->HostAdapterStatus =
+            EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
+  Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
+  return EFI_BAD_BUFFER_SIZE;
+}
+
+/**
+
+  Check the request packet from the Extended SCSI Pass Thru Protocol. The
+  request packet is modified, to be forwarded outwards by LsiScsiPassThru(),
+  if invalid or unsupported parameters are detected.
+
+  @param[in] Dev          The LSI 53C895A SCSI device the packet targets.
+
+  @param[in] Target       The SCSI target controlled by the LSI 53C895A SCSI
+                          device.
+
+  @param[in] Lun          The Logical Unit Number under the SCSI target.
+
+  @param[in out] Packet   The Extended SCSI Pass Thru Protocol packet.
+
+
+  @retval EFI_SUCCESS  The Extended SCSI Pass Thru Protocol packet was valid.
+
+  @return              Otherwise, invalid or unsupported parameters were
+                       detected. Status codes are meant for direct forwarding
+                       by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()
+                       implementation.
+
+ **/
+STATIC
+EFI_STATUS
+LsiScsiCheckRequest (
+  IN LSI_SCSI_DEV                                   *Dev,
+  IN UINT8                                          Target,
+  IN UINT64                                         Lun,
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+  )
+{
+  if (Target > Dev->MaxTarget || Lun > Dev->MaxLun ||
+      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
+         )
+        )
+    ) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL ||
+      (Packet->InTransferLength > 0 && Packet->OutTransferLength > 0) ||
+      Packet->CdbLength > sizeof Dev->Dma->Cdb) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (Packet->InTransferLength > sizeof Dev->Dma->Data) {
+    Packet->InTransferLength = sizeof Dev->Dma->Data;
+    return ReportHostAdapterOverrunError (Packet);
+  }
+  if (Packet->OutTransferLength > sizeof Dev->Dma->Data) {
+    Packet->OutTransferLength = sizeof Dev->Dma->Data;
+    return ReportHostAdapterOverrunError (Packet);
+  }
+
+  return EFI_SUCCESS;
+}
+
 //
 // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
 // for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
@@ -70,6 +159,15 @@ LsiScsiPassThru (
   IN EFI_EVENT                                      Event     OPTIONAL
   )
 {
+  EFI_STATUS   Status;
+  LSI_SCSI_DEV *Dev;
+
+  Dev = LSI_SCSI_FROM_PASS_THRU (This);
+  Status = LsiScsiCheckRequest (Dev, *Target, Lun, Packet);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
   return EFI_UNSUPPORTED;
 }
 
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
index 9f9e5c7fed00..05deeed379fe 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
@@ -13,6 +13,10 @@
 #define _LSI_SCSI_DXE_H_
 
 typedef struct {
+  //
+  // The max size of CDB is 32.
+  //
+  UINT8                           Cdb[32];
   //
   // Allocate 64KB for read/write buffer. It seems sufficient for the common
   // boot scenarios.
-- 
2.25.1


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

* [PATCH v2 10/12] OvmfPkg/LsiScsiDxe: Process the SCSI Request Packet
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
                   ` (8 preceding siblings ...)
  2020-07-16  7:46 ` [PATCH v2 09/12] OvmfPkg/LsiScsiDxe: Examine the incoming SCSI Request Packet Gary Lin
@ 2020-07-16  7:46 ` Gary Lin
  2020-07-16 17:37   ` Laszlo Ersek
  2020-07-16  7:46 ` [PATCH v2 11/12] OvmfPkg/LsiScsiDxe: Calculate the transferred bytes Gary Lin
  2020-07-16  7:46 ` [PATCH v2 12/12] Maintainers.txt: Add Gary Lin as the reviewer for LsiScsi driver Gary Lin
  11 siblings, 1 reply; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:46 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

This is the second part of LsiScsiPassThru(). LsiScsiProcessRequest() is
added to translate the SCSI Request Packet into the LSI 53C895A
commands. This function utilizes the so-called Script buffer to transmit
a series of commands to the chip and then polls the DMA Status (DSTAT)
register until the Scripts Interrupt Instruction Received (SIR) bit
sets. Once the script is done, the SCSI Request Packet will be modified
to reflect the result of the script.

v2:
  - Use the BITx macros for the most of LSI_* constants
  - Fix a typo: contorller => controller
  - Add SeaBIOS lsi-scsi driver as one of the references of the script
  - Cast the result of sizeof to UINT32 for the instructions of the
    script
  - Drop the backslashes
  - Replace LSI_SCSI_DMA_ADDR_LOW with LSI_SCSI_DMA_ADDR since we
    already removed DUAL_ADDRESS_CYCLE
  - Add more comments for the script
  - Fix the check of the script size at the end of the script
  - Always set SenseDataLength to 0 to avoid the caller to access
    SenseData
  - Improve the error handling in LsiScsiProcessRequest()

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
---
 OvmfPkg/Include/IndustryStandard/LsiScsi.h |  63 ++++
 OvmfPkg/LsiScsiDxe/LsiScsi.c               | 336 ++++++++++++++++++++-
 OvmfPkg/LsiScsiDxe/LsiScsi.h               |  21 ++
 OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf          |   3 +
 OvmfPkg/OvmfPkg.dec                        |   3 +
 5 files changed, 425 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
index 185e553c8eb4..9964bd40385c 100644
--- a/OvmfPkg/Include/IndustryStandard/LsiScsi.h
+++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
@@ -26,6 +26,18 @@
 #define LSI_REG_SIST0             0x42
 #define LSI_REG_SIST1             0x43
 
+//
+// The status bits for DMA Status (DSTAT)
+//
+#define LSI_DSTAT_IID             BIT0
+#define LSI_DSTAT_R               BIT1
+#define LSI_DSTAT_SIR             BIT2
+#define LSI_DSTAT_SSI             BIT3
+#define LSI_DSTAT_ABRT            BIT4
+#define LSI_DSTAT_BF              BIT5
+#define LSI_DSTAT_MDPE            BIT6
+#define LSI_DSTAT_DFE             BIT7
+
 //
 // The status bits for Interrupt Status Zero (ISTAT0)
 //
@@ -38,4 +50,55 @@
 #define LSI_ISTAT0_SRST           BIT6
 #define LSI_ISTAT0_ABRT           BIT7
 
+//
+// The status bits for SCSI Interrupt Status Zero (SIST0)
+//
+#define LSI_SIST0_PAR             BIT0
+#define LSI_SIST0_RST             BIT1
+#define LSI_SIST0_UDC             BIT2
+#define LSI_SIST0_SGE             BIT3
+#define LSI_SIST0_RSL             BIT4
+#define LSI_SIST0_SEL             BIT5
+#define LSI_SIST0_CMP             BIT6
+#define LSI_SIST0_MA              BIT7
+
+//
+// The status bits for SCSI Interrupt Status One (SIST1)
+//
+#define LSI_SIST1_HTH             BIT0
+#define LSI_SIST1_GEN             BIT1
+#define LSI_SIST1_STO             BIT2
+#define LSI_SIST1_R3              BIT3
+#define LSI_SIST1_SBMC            BIT4
+#define LSI_SIST1_R5              BIT5
+#define LSI_SIST1_R6              BIT6
+#define LSI_SIST1_R7              BIT7
+
+//
+// LSI 53C895A Script Instructions
+//
+#define LSI_INS_TYPE_BLK          0x00000000
+#define LSI_INS_TYPE_IO           BIT30
+#define LSI_INS_TYPE_TC           BIT31
+
+#define LSI_INS_BLK_SCSIP_DAT_OUT 0x00000000
+#define LSI_INS_BLK_SCSIP_DAT_IN  BIT24
+#define LSI_INS_BLK_SCSIP_CMD     BIT25
+#define LSI_INS_BLK_SCSIP_STAT    (BIT24 | BIT25)
+#define LSI_INS_BLK_SCSIP_MSG_OUT (BIT25 | BIT26)
+#define LSI_INS_BLK_SCSIP_MSG_IN  (BIT24 | BIT25 | BIT26)
+
+#define LSI_INS_IO_OPC_SEL        0x00000000
+#define LSI_INS_IO_OPC_WAIT_RESEL BIT28
+
+#define LSI_INS_TC_CP             BIT17
+#define LSI_INS_TC_JMP            BIT19
+#define LSI_INS_TC_RA             BIT23
+
+#define LSI_INS_TC_OPC_JMP        0x00000000
+#define LSI_INS_TC_OPC_INT        (BIT27 | BIT28)
+
+#define LSI_INS_TC_SCSIP_DAT_OUT  0x00000000
+#define LSI_INS_TC_SCSIP_MSG_IN   (BIT24 | BIT25 | BIT26)
+
 #endif // _LSI_SCSI_H_
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
index b3a88cc7119b..d5fe1d4ab3b8 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -43,6 +43,42 @@ Out8 (
                           );
 }
 
+STATIC
+EFI_STATUS
+Out32 (
+  IN LSI_SCSI_DEV       *Dev,
+  IN UINT32             Addr,
+  IN UINT32             Data
+  )
+{
+  return Dev->PciIo->Io.Write (
+                          Dev->PciIo,
+                          EfiPciIoWidthUint32,
+                          PCI_BAR_IDX0,
+                          Addr,
+                          1,
+                          &Data
+                          );
+}
+
+STATIC
+EFI_STATUS
+In8 (
+  IN  LSI_SCSI_DEV *Dev,
+  IN  UINT32       Addr,
+  OUT UINT8        *Data
+  )
+{
+  return Dev->PciIo->Io.Read (
+                          Dev->PciIo,
+                          EfiPciIoWidthUint8,
+                          PCI_BAR_IDX0,
+                          Addr,
+                          1,
+                          Data
+                          );
+}
+
 STATIC
 EFI_STATUS
 LsiScsiReset (
@@ -141,6 +177,303 @@ LsiScsiCheckRequest (
   return EFI_SUCCESS;
 }
 
+/**
+
+  Interpret the request packet from the Extended SCSI Pass Thru Protocol and
+  compose the script to submit the command and data to the controller.
+
+  @param[in] Dev          The LSI 53C895A SCSI device the packet targets.
+
+  @param[in] Target       The SCSI target controlled by the LSI 53C895A SCSI
+                          device.
+
+  @param[in] Lun          The Logical Unit Number under the SCSI target.
+
+  @param[in out] Packet   The Extended SCSI Pass Thru Protocol packet.
+
+
+  @retval EFI_SUCCESS  The Extended SCSI Pass Thru Protocol packet was valid.
+
+  @return              Otherwise, invalid or unsupported parameters were
+                       detected. Status codes are meant for direct forwarding
+                       by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()
+                       implementation.
+
+ **/
+STATIC
+EFI_STATUS
+LsiScsiProcessRequest (
+  IN LSI_SCSI_DEV                                   *Dev,
+  IN UINT8                                          Target,
+  IN UINT64                                         Lun,
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
+  )
+{
+  EFI_STATUS Status;
+  UINT32     *Script;
+  UINT8      *Cdb;
+  UINT8      *MsgOut;
+  UINT8      *MsgIn;
+  UINT8      *ScsiStatus;
+  UINT8      *Data;
+  UINT8      DStat;
+  UINT8      SIst0;
+  UINT8      SIst1;
+
+  Script      = Dev->Dma->Script;
+  Cdb         = Dev->Dma->Cdb;
+  Data        = Dev->Dma->Data;
+  MsgIn       = Dev->Dma->MsgIn;
+  MsgOut      = &Dev->Dma->MsgOut;
+  ScsiStatus  = &Dev->Dma->Status;
+
+  *ScsiStatus = 0xFF;
+
+  SetMem (Cdb, sizeof Dev->Dma->Cdb, 0x00);
+  CopyMem (Cdb, Packet->Cdb, Packet->CdbLength);
+
+  //
+  // Clean up the DMA buffer for the script.
+  //
+  SetMem (Script, sizeof Dev->Dma->Script, 0x00);
+
+  //
+  // Compose the script to transfer data between the host and the device.
+  //
+  // References:
+  //   * LSI53C895A PCI to Ultra2 SCSI Controller Version 2.2
+  //     - Chapter 5 SCSI SCRIPT Instruction Set
+  //   * SEABIOS lsi-scsi driver
+  //
+  // All instructions used here consist of 2 32bit words. The first word
+  // contains the command to execute. The second word is loaded into the
+  // DMA SCRIPTS Pointer Save (DSPS) register as either the DMA address
+  // for data transmission or the address/offset for the jump command.
+  // Some commands, such as the selection of the target, don't need to
+  // transfer data through DMA or jump to another instruction, then DSPS
+  // has to be zero.
+  //
+  // There are 3 major parts in this script. The first part (1~3) contains
+  // the instructions to select target and LUN and send the SCSI command
+  // from the request packet. The second part (4~7) is to handle the
+  // potential disconnection and prepare for the data transmission. The
+  // instructions in the third part (8~10) transmit the given data and
+  // collect the result. Instruction 11 raises the interrupt and marks the
+  // end of the script.
+  //
+
+  //
+  // 1. Select target.
+  //
+  *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_SEL | (UINT32)Target << 16;
+  *Script++ = 0x00000000;
+
+  //
+  // 2. Select LUN.
+  //
+  *MsgOut   = 0x80 | (UINT8) Lun; // 0x80: Identify bit
+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_OUT |
+              (UINT32)sizeof Dev->Dma->MsgOut;
+  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgOut);
+
+  //
+  // 3. Send the SCSI Command.
+  //
+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_CMD |
+              (UINT32)sizeof Dev->Dma->Cdb;
+  *Script++ = LSI_SCSI_DMA_ADDR (Dev, Cdb);
+
+  //
+  // 4. Check whether the current SCSI phase is "Message In" or not
+  //    and jump to 7 if it is.
+  //    Note: LSI_INS_TC_RA stands for "Relative Address Mode", so the
+  //          offset 0x18 in the second word means jumping forward
+  //          3 (0x18/8) instructions.
+  //
+  *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_JMP |
+              LSI_INS_TC_SCSIP_MSG_IN | LSI_INS_TC_RA |
+              LSI_INS_TC_CP;
+  *Script++ = 0x00000018;
+
+  //
+  // 5. Read "Message" from the initiator to trigger reselect.
+  //
+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
+              (UINT32)sizeof Dev->Dma->MsgIn;
+  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
+
+  //
+  // 6. Wait reselect.
+  //
+  *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_WAIT_RESEL;
+  *Script++ = 0x00000000;
+
+  //
+  // 7. Read "Message" from the initiator again
+  //
+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
+              (UINT32)sizeof Dev->Dma->MsgIn;
+  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
+
+  //
+  // 8. Set the DMA command for the read/write operations.
+  //    Note: Some requests, e.g. "TEST UNIT READY", do not come with
+  //          allocated InDataBuffer or OutDataBuffer. We skip the DMA
+  //          data command for those requests or this script would fail
+  //          with LSI_SIST0_SGE due to the zero data length.
+  //
+  // LsiScsiCheckRequest() prevents both integer overflows in the command
+  // opcodes, and buffer overflows.
+  //
+  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ &&
+      Packet->InTransferLength > 0) {
+    ASSERT (Packet->InTransferLength <= sizeof Dev->Dma->Data);
+    *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_IN |
+                Packet->InTransferLength;
+    *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);
+  } else if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE &&
+             Packet->OutTransferLength > 0) {
+    ASSERT (Packet->OutTransferLength <= sizeof Dev->Dma->Data);
+    CopyMem (Data, Packet->OutDataBuffer, Packet->OutTransferLength);
+    *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_OUT |
+                Packet->OutTransferLength;
+    *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);
+  }
+
+  //
+  // 9. Get the SCSI status.
+  //
+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_STAT |
+              (UINT32)sizeof Dev->Dma->Status;
+  *Script++ = LSI_SCSI_DMA_ADDR (Dev, Status);
+
+  //
+  // 10. Get the SCSI message.
+  //
+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
+              (UINT32)sizeof Dev->Dma->MsgIn;
+  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
+
+  //
+  // 11. Raise the interrupt to end the script.
+  //
+  *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_INT |
+              LSI_INS_TC_SCSIP_DAT_OUT | LSI_INS_TC_JMP;
+  *Script++ = 0x00000000;
+
+  //
+  // Make sure the size of the script doesn't exceed the buffer.
+  //
+  ASSERT (Script <= Dev->Dma->Script + ARRAY_SIZE (Dev->Dma->Script));
+
+  //
+  // The controller starts to execute the script once the DMA Script
+  // Pointer (DSP) register is set.
+  //
+  Status = Out32 (Dev, LSI_REG_DSP, LSI_SCSI_DMA_ADDR (Dev, Script));
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
+  //
+  // Poll the device registers (DSTAT, SIST0, and SIST1) until the SIR
+  // bit sets.
+  //
+  for(;;) {
+    Status = In8 (Dev, LSI_REG_DSTAT, &DStat);
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+    Status = In8 (Dev, LSI_REG_SIST0, &SIst0);
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+    Status = In8 (Dev, LSI_REG_SIST1, &SIst1);
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+
+    if (SIst0 != 0 || SIst1 != 0) {
+      goto Error;
+    }
+
+    //
+    // Check the SIR (SCRIPTS Interrupt Instruction Received) bit.
+    //
+    if (DStat & LSI_DSTAT_SIR) {
+      break;
+    }
+
+    gBS->Stall (Dev->StallPerPollUsec);
+  }
+
+  //
+  // Check if everything is good.
+  //   SCSI Message Code 0x00: COMMAND COMPLETE
+  //   SCSI Status  Code 0x00: Good
+  //
+  if (MsgIn[0] != 0 || *ScsiStatus != 0) {
+    goto Error;
+  }
+
+  //
+  // Copy Data to InDataBuffer if necessary.
+  //
+  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+    CopyMem (Packet->InDataBuffer, Data, Packet->InTransferLength);
+  }
+
+  //
+  // Always set SenseDataLength to 0.
+  // The instructions of LSI53C895A doesn't reply sense data. Instead, it
+  // relies on the SCSI command, "REQUEST SENSE", to get sense data. We set
+  // SenseDataLength to 0 to notify ScsiDiskDxe that there is no sense data
+  // written even if this request is processed successfully, so that It will
+  // issue "REQUEST SENSE" later to retrieve sense data.
+  //
+  Packet->SenseDataLength   = 0;
+  Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
+  Packet->TargetStatus      = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
+
+  return EFI_SUCCESS;
+
+Error:
+  DEBUG ((DEBUG_VERBOSE, "%a: dstat: %02X, sist0: %02X, sist1: %02X\n",
+    __FUNCTION__, DStat, SIst0, SIst1));
+  //
+  // Update the request packet to reflect the status.
+  //
+  if (*ScsiStatus != 0xFF) {
+    Packet->TargetStatus    = *ScsiStatus;
+  } else {
+    Packet->TargetStatus    = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;
+  }
+
+  if (SIst0 & LSI_SIST0_PAR) {
+    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR;
+  } else if (SIst0 & LSI_SIST0_RST) {
+    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;
+  } else if (SIst0 & LSI_SIST0_UDC) {
+    //
+    // The target device is disconnected unexpectedly. According to UEFI spec,
+    // this is TIMEOUT_COMMAND.
+    //
+    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
+  } else if (SIst0 & LSI_SIST0_SGE) {
+    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
+  } else if (SIst1 & LSI_SIST1_HTH) {
+    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
+  } else if (SIst1 & LSI_SIST1_GEN) {
+    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
+  } else if (SIst1 & LSI_SIST1_STO) {
+    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
+  } else {
+    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
+  }
+
+  return EFI_DEVICE_ERROR;
+}
+
 //
 // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
 // for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
@@ -168,7 +501,7 @@ LsiScsiPassThru (
     return Status;
   }
 
-  return EFI_UNSUPPORTED;
+  return LsiScsiProcessRequest (Dev, *Target, Lun, Packet);
 }
 
 EFI_STATUS
@@ -474,6 +807,7 @@ LsiScsiControllerStart (
     );
   Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);
   Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);
+  Dev->StallPerPollUsec = PcdGet32 (PcdLsiScsiStallPerPollUsec);
 
   Status = gBS->OpenProtocol (
                   ControllerHandle,
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
index 05deeed379fe..6ecf523f5a9e 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
@@ -13,6 +13,11 @@
 #define _LSI_SCSI_DXE_H_
 
 typedef struct {
+  //
+  // Allocate 32 UINT32 entries for the script and it's sufficient for
+  // 16 instructions.
+  //
+  UINT32                          Script[32];
   //
   // The max size of CDB is 32.
   //
@@ -25,6 +30,18 @@ typedef struct {
   //       Count (DBC), a 24-bit register, so the maximum is 0xFFFFFF (16MB-1).
   //
   UINT8                           Data[SIZE_64KB];
+  //
+  // For SCSI Message In phase
+  //
+  UINT8                           MsgIn[2];
+  //
+  // For SCSI Message Out phase
+  //
+  UINT8                           MsgOut;
+  //
+  // For SCSI Status phase
+  //
+  UINT8                           Status;
 } LSI_SCSI_DMA_BUFFER;
 
 typedef struct {
@@ -34,6 +51,7 @@ typedef struct {
   EFI_PCI_IO_PROTOCOL             *PciIo;
   UINT8                           MaxTarget;
   UINT8                           MaxLun;
+  UINT32                          StallPerPollUsec;
   LSI_SCSI_DMA_BUFFER             *Dma;
   EFI_PHYSICAL_ADDRESS            DmaPhysical;
   VOID                            *DmaMapping;
@@ -46,6 +64,9 @@ typedef struct {
 #define LSI_SCSI_FROM_PASS_THRU(PassThruPtr) \
   CR (PassThruPtr, LSI_SCSI_DEV, PassThru, LSI_SCSI_DEV_SIGNATURE)
 
+#define LSI_SCSI_DMA_ADDR(Dev, MemberName) \
+  ((UINT32)(Dev->DmaPhysical + OFFSET_OF (LSI_SCSI_DMA_BUFFER, MemberName)))
+
 
 //
 // Probe, start and stop functions of this driver, called by the DXE core for
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
index 6111449577a8..4c7abcec618f 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
+++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
@@ -41,3 +41,6 @@ [Protocols]
 [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit   ## CONSUMES
   gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit      ## CONSUMES
+
+[Pcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiStallPerPollUsec ## CONSUMES
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index ca13a3cb11d3..f16c00ad5b99 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -179,6 +179,9 @@ [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit|7|UINT8|0x3b
   gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit|0|UINT8|0x3c
 
+  ## Microseconds to stall between polling for LsiScsi request result
+  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiStallPerPollUsec|5|UINT32|0x3d
+
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogBase|0x0|UINT32|0x8
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogSize|0x0|UINT32|0x9
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize|0x0|UINT32|0xa
-- 
2.25.1


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

* [PATCH v2 11/12] OvmfPkg/LsiScsiDxe: Calculate the transferred bytes
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
                   ` (9 preceding siblings ...)
  2020-07-16  7:46 ` [PATCH v2 10/12] OvmfPkg/LsiScsiDxe: Process the " Gary Lin
@ 2020-07-16  7:46 ` Gary Lin
  2020-07-16 18:21   ` Laszlo Ersek
  2020-07-16  7:46 ` [PATCH v2 12/12] Maintainers.txt: Add Gary Lin as the reviewer for LsiScsi driver Gary Lin
  11 siblings, 1 reply; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:46 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

Calculate the transferred bytes during data phases based on the
Cumulative SCSI Byte Count (CSBC) and update
InTransferLength/OutTransferLength of the request packet.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
---
 OvmfPkg/Include/IndustryStandard/LsiScsi.h |  1 +
 OvmfPkg/LsiScsiDxe/LsiScsi.c               | 50 ++++++++++++++++++++++
 2 files changed, 51 insertions(+)

diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
index 9964bd40385c..01d75323cdbc 100644
--- a/OvmfPkg/Include/IndustryStandard/LsiScsi.h
+++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
@@ -25,6 +25,7 @@
 #define LSI_REG_DSP               0x2C
 #define LSI_REG_SIST0             0x42
 #define LSI_REG_SIST1             0x43
+#define LSI_REG_CSBC              0xDC
 
 //
 // The status bits for DMA Status (DSTAT)
diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
index d5fe1d4ab3b8..10483ed02bd7 100644
--- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -79,6 +79,24 @@ In8 (
                           );
 }
 
+STATIC
+EFI_STATUS
+In32 (
+  IN  LSI_SCSI_DEV *Dev,
+  IN  UINT32       Addr,
+  OUT UINT32       *Data
+  )
+{
+  return Dev->PciIo->Io.Read (
+                          Dev->PciIo,
+                          EfiPciIoWidthUint32,
+                          PCI_BAR_IDX0,
+                          Addr,
+                          1,
+                          Data
+                          );
+}
+
 STATIC
 EFI_STATUS
 LsiScsiReset (
@@ -219,6 +237,8 @@ LsiScsiProcessRequest (
   UINT8      DStat;
   UINT8      SIst0;
   UINT8      SIst1;
+  UINT32     Csbc;
+  UINT32     CsbcBase;
 
   Script      = Dev->Dma->Script;
   Cdb         = Dev->Dma->Cdb;
@@ -232,6 +252,18 @@ LsiScsiProcessRequest (
   SetMem (Cdb, sizeof Dev->Dma->Cdb, 0x00);
   CopyMem (Cdb, Packet->Cdb, Packet->CdbLength);
 
+  //
+  // Fetch the first Cumulative SCSI Byte Count (CSBC).
+  //
+  // CSBC is a cumulative counter of the actual number of bytes that has been
+  // transferred across the SCSI bus during data phases, i.e. it will not
+  // bytes sent in command, status, message in and out phases.
+  //
+  Status = In32 (Dev, LSI_REG_CSBC, &CsbcBase);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
   //
   // Clean up the DMA buffer for the script.
   //
@@ -407,6 +439,24 @@ LsiScsiProcessRequest (
     gBS->Stall (Dev->StallPerPollUsec);
   }
 
+  //
+  // Fetch CSBC again to calculate the transferred bytes and update
+  // InTransferLength/OutTransferLength.
+  //
+  // Note: The number of transferred bytes is bounded by
+  //       "sizeof Dev->Dma->Data", so it's safe to subtract CsbcBase
+  //       from Csbc.
+  //
+  Status = In32 (Dev, LSI_REG_CSBC, &Csbc);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (Packet->InTransferLength > 0) {
+    Packet->InTransferLength = Csbc - CsbcBase;
+  } else if (Packet->OutTransferLength > 0) {
+    Packet->OutTransferLength = Csbc - CsbcBase;
+  }
+
   //
   // Check if everything is good.
   //   SCSI Message Code 0x00: COMMAND COMPLETE
-- 
2.25.1


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

* [PATCH v2 12/12] Maintainers.txt: Add Gary Lin as the reviewer for LsiScsi driver
  2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
                   ` (10 preceding siblings ...)
  2020-07-16  7:46 ` [PATCH v2 11/12] OvmfPkg/LsiScsiDxe: Calculate the transferred bytes Gary Lin
@ 2020-07-16  7:46 ` Gary Lin
  11 siblings, 0 replies; 21+ messages in thread
From: Gary Lin @ 2020-07-16  7:46 UTC (permalink / raw)
  To: devel; +Cc: Jordan Justen, Laszlo Ersek, Ard Biesheuvel

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 Maintainers.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Maintainers.txt b/Maintainers.txt
index 32c9003a6209..075a8d0ea763 100644
--- a/Maintainers.txt
+++ b/Maintainers.txt
@@ -400,6 +400,10 @@ OvmfPkg: CSM modules
 F: OvmfPkg/Csm/
 R: David Woodhouse <dwmw2@infradead.org>
 
+OvmfPkg: LsiScsi driver
+F: OvmfPkg/LsiScsiDxe/
+R: Gary Lin <glin@suse.com>
+
 OvmfPkg: MptScsi and PVSCSI driver
 F: OvmfPkg/MptScsiDxe/
 F: OvmfPkg/PvScsiDxe/
-- 
2.25.1


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

* Re: [PATCH v2 06/12] OvmfPkg/LsiScsiDxe: Report Targets and LUNs
  2020-07-16  7:46 ` [PATCH v2 06/12] OvmfPkg/LsiScsiDxe: Report Targets and LUNs Gary Lin
@ 2020-07-16 15:04   ` Laszlo Ersek
  2020-07-16 16:19     ` Laszlo Ersek
  0 siblings, 1 reply; 21+ messages in thread
From: Laszlo Ersek @ 2020-07-16 15:04 UTC (permalink / raw)
  To: Gary Lin, devel; +Cc: Jordan Justen, Ard Biesheuvel

On 07/16/20 09:46, Gary Lin wrote:
> Implement LsiScsiGetNextTargetLun(), LsiScsiBuildDevicePath(),
> LsiScsiGetTargetLun(), and LsiScsiGetNextTarget() to report Targets and
> LUNs and build the device path.
> 
> This commit also introduces two PCD value: PcdLsiScsiMaxTargetLimit and
> PcdLsiScsiMaxLunLimit as the limits for Targets and LUNs.
> 
> v2:
>   - Zero out (*Target) in LsiScsiGetTargetLun()
>   - Use CopyMem() instead of the one-byte shortcut to copy target from
>     ScsiDevicePath->Pun
>   - Add asserts for PcdLsiScsiMaxTargetLimit and PcdLsiScsiMaxLunLimit
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>  OvmfPkg/LsiScsiDxe/LsiScsi.c      | 148 +++++++++++++++++++++++++++++-
>  OvmfPkg/LsiScsiDxe/LsiScsi.h      |   3 +
>  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf |   6 ++
>  OvmfPkg/OvmfPkg.dec               |   5 +
>  4 files changed, 160 insertions(+), 2 deletions(-)
> 
> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> index 67fadb411e85..989bda88d209 100644
> --- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
> +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> @@ -15,6 +15,7 @@
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/DebugLib.h>
>  #include <Library/MemoryAllocationLib.h>
> +#include <Library/PcdLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiLib.h>
>  #include <Protocol/PciIo.h>
> @@ -53,6 +54,49 @@ LsiScsiGetNextTargetLun (
>    IN OUT UINT64                      *Lun
>    )
>  {
> +  LSI_SCSI_DEV *Dev;
> +  UINTN        Idx;
> +  UINT8        *Target;
> +  UINT16       LastTarget;
> +
> +  //
> +  // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
> +  //
> +  Target = *TargetPointer;
> +
> +  //
> +  // Search for first non-0xFF byte. If not found, return first target & LUN.
> +  //
> +  for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)
> +    ;
> +  if (Idx == TARGET_MAX_BYTES) {
> +    SetMem (Target, TARGET_MAX_BYTES, 0x00);
> +    *Lun = 0;
> +    return EFI_SUCCESS;
> +  }
> +
> +  CopyMem (&LastTarget, Target, sizeof LastTarget);
> +
> +  //
> +  // increment (target, LUN) pair if valid on input
> +  //
> +  Dev = LSI_SCSI_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;
> +    CopyMem (Target, &LastTarget, sizeof LastTarget);
> +    return EFI_SUCCESS;
> +  }
> +
>    return EFI_NOT_FOUND;
>  }
>  
> @@ -65,7 +109,34 @@ LsiScsiBuildDevicePath (
>    IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath
>    )
>  {
> -  return EFI_NOT_FOUND;
> +  UINT16           TargetValue;
> +  LSI_SCSI_DEV     *Dev;
> +  SCSI_DEVICE_PATH *ScsiDevicePath;
> +
> +  if (DevicePath == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  CopyMem (&TargetValue, Target, sizeof TargetValue);
> +  Dev = LSI_SCSI_FROM_PASS_THRU (This);
> +  if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun || Lun > 0xFFFF) {
> +    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;
>  }
>  
>  EFI_STATUS
> @@ -77,7 +148,33 @@ LsiScsiGetTargetLun (
>    OUT UINT64                          *Lun
>    )
>  {
> -  return EFI_UNSUPPORTED;
> +  SCSI_DEVICE_PATH *ScsiDevicePath;
> +  LSI_SCSI_DEV     *Dev;
> +  UINT8            *Target;
> +
> +  if (DevicePath == NULL || TargetPointer == NULL || *TargetPointer == 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 = LSI_SCSI_FROM_PASS_THRU (This);
> +  if (ScsiDevicePath->Pun > Dev->MaxTarget ||
> +      ScsiDevicePath->Lun > Dev->MaxLun) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  Target = *TargetPointer;
> +  ZeroMem (Target, TARGET_MAX_BYTES);
> +  CopyMem (Target, &ScsiDevicePath->Pun, sizeof ScsiDevicePath->Pun);
> +  *Lun = ScsiDevicePath->Lun;
> +
> +  return EFI_SUCCESS;
>  }
>  
>  EFI_STATUS
> @@ -107,6 +204,42 @@ LsiScsiGetNextTarget (
>    IN OUT UINT8                       **TargetPointer
>    )
>  {
> +  LSI_SCSI_DEV *Dev;
> +  UINTN        Idx;
> +  UINT8        *Target;
> +  UINT16       LastTarget;
> +
> +  //
> +  // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
> +  //
> +  Target = *TargetPointer;
> +
> +  //
> +  // Search for first non-0xFF byte. If not found, return first target.
> +  //
> +  for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)
> +    ;
> +  if (Idx == TARGET_MAX_BYTES) {
> +    SetMem (Target, TARGET_MAX_BYTES, 0x00);
> +    return EFI_SUCCESS;
> +  }
> +
> +  CopyMem (&LastTarget, Target, sizeof LastTarget);
> +
> +  //
> +  // increment target if valid on input
> +  //
> +  Dev = LSI_SCSI_FROM_PASS_THRU (This);
> +  if (LastTarget > Dev->MaxTarget) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (LastTarget < Dev->MaxTarget) {
> +    ++LastTarget;
> +    CopyMem (Target, &LastTarget, sizeof LastTarget);
> +    return EFI_SUCCESS;
> +  }
> +
>    return EFI_NOT_FOUND;
>  }
>  
> @@ -189,6 +322,17 @@ LsiScsiControllerStart (
>  
>    Dev->Signature = LSI_SCSI_DEV_SIGNATURE;
>  
> +  STATIC_ASSERT (
> +    FixedPcdGet8 (PcdLsiScsiMaxTargetLimit) < 8,
> +    "LSI 53C895A supports targets [0..7]"
> +    );
> +  STATIC_ASSERT (
> +    FixedPcdGet8 (PcdLsiScsiMaxLunLimit) < 128,
> +    "LSI 53C895A supports LUNs [0..128]"
> +    );

(1) The condition on the LUN limit, and the error message for the same,
are not consistent. The PCD is an inclusive limit. We assert that the
PCD is strictly smaller than 128. Therefore the highest permitted PCD
value is 127. Therefore the highest permitted LUN (because the PCD is
inclusive) is 127. Therefore the error message should advertize
"[0..127]", not "[0..128]". In other words, LUN 128 itself is not valid.

If LUN 128 *is* valid, and so PCD=128 too is valid, then the condition
should be updated, to say "< 129".

> +  Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);
> +  Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);
> +
>    //
>    // Host adapter channel, doesn't exist
>    //
> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
> index c194dfbf3347..6c6ed25f1c33 100644
> --- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
> +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
> @@ -14,6 +14,8 @@
>  
>  typedef struct {
>    UINT32                          Signature;
> +  UINT8                           MaxTarget;
> +  UINT8                           MaxLun;
>    EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
>    EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
>  } LSI_SCSI_DEV;
> @@ -23,6 +25,7 @@ typedef struct {
>  #define LSI_SCSI_FROM_PASS_THRU(PassThruPtr) \
>    CR (PassThruPtr, LSI_SCSI_DEV, PassThru, LSI_SCSI_DEV_SIGNATURE)
>  
> +
>  //
>  // Probe, start and stop functions of this driver, called by the DXE core for
>  // specific devices.

(2) You missed point (4) in my v1 review -- the above newline is
spurious, so it should be removed from this patch. (It should either be
removed completely, or squashed into the patch that introduces the
LSI_SCSI_FROM_PASS_THRU macro.)

With (1) and (2) fixed:

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

Thanks
Laszlo

> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
> index 14f9c68308cc..6111449577a8 100644
> --- a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
> +++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
> @@ -27,7 +27,9 @@ [Packages]
>  [LibraryClasses]
>    BaseLib
>    BaseMemoryLib
> +  DebugLib
>    MemoryAllocationLib
> +  PcdLib
>    UefiBootServicesTableLib
>    UefiDriverEntryPoint
>    UefiLib
> @@ -35,3 +37,7 @@ [LibraryClasses]
>  [Protocols]
>    gEfiExtScsiPassThruProtocolGuid        ## BY_START
>    gEfiPciIoProtocolGuid                  ## TO_START
> +
> +[FixedPcd]
> +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit   ## CONSUMES
> +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit      ## CONSUMES
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index 2b0f137cbcce..ca13a3cb11d3 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -174,6 +174,11 @@ [PcdsFixedAtBuild]
>    ## Microseconds to stall between polling for MptScsi request result
>    gUefiOvmfPkgTokenSpaceGuid.PcdMptScsiStallPerPollUsec|5|UINT32|0x3a
>  
> +  ## Set the *inclusive* number of targets and LUNs that LsiScsi exposes for
> +  #  scan by ScsiBusDxe.
> +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit|7|UINT8|0x3b
> +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit|0|UINT8|0x3c
> +
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogBase|0x0|UINT32|0x8
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogSize|0x0|UINT32|0x9
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize|0x0|UINT32|0xa
> 


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

* Re: [PATCH v2 07/12] OvmfPkg/LsiScsiDxe: Open PciIo protocol and initialize the device
  2020-07-16  7:46 ` [PATCH v2 07/12] OvmfPkg/LsiScsiDxe: Open PciIo protocol and initialize the device Gary Lin
@ 2020-07-16 16:07   ` Laszlo Ersek
  0 siblings, 0 replies; 21+ messages in thread
From: Laszlo Ersek @ 2020-07-16 16:07 UTC (permalink / raw)
  To: Gary Lin, devel; +Cc: Jordan Justen, Ard Biesheuvel

On 07/16/20 09:46, Gary Lin wrote:
> Open PciIo protocol and use it to initialize the device. The
> initialization of LSI 53C895A is simple: just set the SRST bit in
> Interrupt Status Zero register to reset the device.
> 
> v2:
>   - Use the BITx macros for the bit constants
>   - Add the closing of PciIo protocol in LsiScsiControllerStop()
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>  OvmfPkg/Include/IndustryStandard/LsiScsi.h |  21 ++++
>  OvmfPkg/LsiScsiDxe/LsiScsi.c               | 136 ++++++++++++++++++++-
>  OvmfPkg/LsiScsiDxe/LsiScsi.h               |   3 +
>  3 files changed, 159 insertions(+), 1 deletion(-)

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

Thanks
Laszlo

> 
> diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> index c09e864a1f39..185e553c8eb4 100644
> --- a/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> +++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> @@ -17,4 +17,25 @@
>  #define LSI_LOGIC_PCI_VENDOR_ID   0x1000
>  #define LSI_53C895A_PCI_DEVICE_ID 0x0012
>  
> +//
> +// LSI 53C895A Registers
> +//
> +#define LSI_REG_DSTAT             0x0C
> +#define LSI_REG_ISTAT0            0x14
> +#define LSI_REG_DSP               0x2C
> +#define LSI_REG_SIST0             0x42
> +#define LSI_REG_SIST1             0x43
> +
> +//
> +// The status bits for Interrupt Status Zero (ISTAT0)
> +//
> +#define LSI_ISTAT0_DIP            BIT0
> +#define LSI_ISTAT0_SIP            BIT1
> +#define LSI_ISTAT0_INTF           BIT2
> +#define LSI_ISTAT0_CON            BIT3
> +#define LSI_ISTAT0_SEM            BIT4
> +#define LSI_ISTAT0_SIGP           BIT5
> +#define LSI_ISTAT0_SRST           BIT6
> +#define LSI_ISTAT0_ABRT           BIT7
> +
>  #endif // _LSI_SCSI_H_
> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> index 989bda88d209..b21387db6e5a 100644
> --- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
> +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> @@ -25,6 +25,33 @@
>  
>  #include "LsiScsi.h"
>  
> +STATIC
> +EFI_STATUS
> +Out8 (
> +  IN LSI_SCSI_DEV *Dev,
> +  IN UINT32       Addr,
> +  IN UINT8        Data
> +  )
> +{
> +  return Dev->PciIo->Io.Write (
> +                          Dev->PciIo,
> +                          EfiPciIoWidthUint8,
> +                          PCI_BAR_IDX0,
> +                          Addr,
> +                          1,
> +                          &Data
> +                          );
> +}
> +
> +STATIC
> +EFI_STATUS
> +LsiScsiReset (
> +  IN LSI_SCSI_DEV *Dev
> +  )
> +{
> +  return Out8 (Dev, LSI_REG_ISTAT0, LSI_ISTAT0_SRST);
> +}
> +
>  //
>  // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
>  // for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
> @@ -243,6 +270,21 @@ LsiScsiGetNextTarget (
>    return EFI_NOT_FOUND;
>  }
>  
> +STATIC
> +VOID
> +EFIAPI
> +LsiScsiExitBoot (
> +  IN  EFI_EVENT Event,
> +  IN  VOID      *Context
> +  )
> +{
> +  LSI_SCSI_DEV *Dev;
> +
> +  Dev = Context;
> +  DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
> +  LsiScsiReset (Dev);
> +}
> +
>  //
>  // Probe, start and stop functions of this driver, called by the DXE core for
>  // specific devices.
> @@ -333,6 +375,58 @@ LsiScsiControllerStart (
>    Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);
>    Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);
>  
> +  Status = gBS->OpenProtocol (
> +                  ControllerHandle,
> +                  &gEfiPciIoProtocolGuid,
> +                  (VOID **)&Dev->PciIo,
> +                  This->DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    goto FreePool;
> +  }
> +
> +  Status = Dev->PciIo->Attributes (
> +                         Dev->PciIo,
> +                         EfiPciIoAttributeOperationGet,
> +                         0,
> +                         &Dev->OrigPciAttrs
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    goto CloseProtocol;
> +  }
> +
> +  //
> +  // Enable I/O Space & Bus-Mastering
> +  //
> +  Status = Dev->PciIo->Attributes (
> +                         Dev->PciIo,
> +                         EfiPciIoAttributeOperationEnable,
> +                         (EFI_PCI_IO_ATTRIBUTE_IO |
> +                          EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
> +                         NULL
> +                         );
> +  if (EFI_ERROR (Status)) {
> +    goto CloseProtocol;
> +  }
> +
> +  Status = LsiScsiReset (Dev);
> +  if (EFI_ERROR (Status)) {
> +    goto RestoreAttributes;
> +  }
> +
> +  Status = gBS->CreateEvent (
> +                  EVT_SIGNAL_EXIT_BOOT_SERVICES,
> +                  TPL_CALLBACK,
> +                  &LsiScsiExitBoot,
> +                  Dev,
> +                  &Dev->ExitBoot
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    goto UninitDev;
> +  }
> +
>    //
>    // Host adapter channel, doesn't exist
>    //
> @@ -357,11 +451,33 @@ LsiScsiControllerStart (
>                    &Dev->PassThru
>                    );
>    if (EFI_ERROR (Status)) {
> -    goto FreePool;
> +    goto CloseExitBoot;
>    }
>  
>    return EFI_SUCCESS;
>  
> +CloseExitBoot:
> +  gBS->CloseEvent (Dev->ExitBoot);
> +
> +UninitDev:
> +  LsiScsiReset (Dev);
> +
> +RestoreAttributes:
> +  Dev->PciIo->Attributes (
> +                Dev->PciIo,
> +                EfiPciIoAttributeOperationSet,
> +                Dev->OrigPciAttrs,
> +                NULL
> +                );
> +
> +CloseProtocol:
> +  gBS->CloseProtocol (
> +         ControllerHandle,
> +         &gEfiPciIoProtocolGuid,
> +         This->DriverBindingHandle,
> +         ControllerHandle
> +         );
> +
>  FreePool:
>    FreePool (Dev);
>  
> @@ -404,6 +520,24 @@ LsiScsiControllerStop (
>      return Status;
>    }
>  
> +  gBS->CloseEvent (Dev->ExitBoot);
> +
> +  LsiScsiReset (Dev);
> +
> +  Dev->PciIo->Attributes (
> +                Dev->PciIo,
> +                EfiPciIoAttributeOperationSet,
> +                Dev->OrigPciAttrs,
> +                NULL
> +                );
> +
> +  gBS->CloseProtocol (
> +         ControllerHandle,
> +         &gEfiPciIoProtocolGuid,
> +         This->DriverBindingHandle,
> +         ControllerHandle
> +         );
> +
>    FreePool (Dev);
>  
>    return Status;
> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
> index 6c6ed25f1c33..8c2acff6e86f 100644
> --- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
> +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
> @@ -14,6 +14,9 @@
>  
>  typedef struct {
>    UINT32                          Signature;
> +  UINT64                          OrigPciAttrs;
> +  EFI_EVENT                       ExitBoot;
> +  EFI_PCI_IO_PROTOCOL             *PciIo;
>    UINT8                           MaxTarget;
>    UINT8                           MaxLun;
>    EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
> 


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

* Re: [PATCH v2 08/12] OvmfPkg/LsiScsiDxe: Map DMA buffer
  2020-07-16  7:46 ` [PATCH v2 08/12] OvmfPkg/LsiScsiDxe: Map DMA buffer Gary Lin
@ 2020-07-16 16:11   ` Laszlo Ersek
  0 siblings, 0 replies; 21+ messages in thread
From: Laszlo Ersek @ 2020-07-16 16:11 UTC (permalink / raw)
  To: Gary Lin, devel; +Cc: Jordan Justen, Ard Biesheuvel

On 07/16/20 09:46, Gary Lin wrote:
> Map DMA buffer and perpare for the implementation of LsiScsiPassThru().
> 
> v2:
>   - Replace 0x10000 with SIZE_64KB macro for the DMA buffer data array
>   - Remove DUAL_ADDRESS_CYCLE from PciIo since we don't really need
>     64-bit DMA address
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  OvmfPkg/LsiScsiDxe/LsiScsi.c | 62 +++++++++++++++++++++++++++++++++++-
>  OvmfPkg/LsiScsiDxe/LsiScsi.h | 14 ++++++++
>  2 files changed, 75 insertions(+), 1 deletion(-)

looks good, thanks


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

* Re: [PATCH v2 06/12] OvmfPkg/LsiScsiDxe: Report Targets and LUNs
  2020-07-16 15:04   ` Laszlo Ersek
@ 2020-07-16 16:19     ` Laszlo Ersek
  0 siblings, 0 replies; 21+ messages in thread
From: Laszlo Ersek @ 2020-07-16 16:19 UTC (permalink / raw)
  To: Gary Lin, devel; +Cc: Jordan Justen, Ard Biesheuvel

On 07/16/20 17:04, Laszlo Ersek wrote:
> On 07/16/20 09:46, Gary Lin wrote:
>> Implement LsiScsiGetNextTargetLun(), LsiScsiBuildDevicePath(),
>> LsiScsiGetTargetLun(), and LsiScsiGetNextTarget() to report Targets and
>> LUNs and build the device path.
>>
>> This commit also introduces two PCD value: PcdLsiScsiMaxTargetLimit and
>> PcdLsiScsiMaxLunLimit as the limits for Targets and LUNs.
>>
>> v2:
>>   - Zero out (*Target) in LsiScsiGetTargetLun()
>>   - Use CopyMem() instead of the one-byte shortcut to copy target from
>>     ScsiDevicePath->Pun
>>   - Add asserts for PcdLsiScsiMaxTargetLimit and PcdLsiScsiMaxLunLimit
>>
>> Cc: Jordan Justen <jordan.l.justen@intel.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
>> Signed-off-by: Gary Lin <glin@suse.com>
>> ---
>>  OvmfPkg/LsiScsiDxe/LsiScsi.c      | 148 +++++++++++++++++++++++++++++-
>>  OvmfPkg/LsiScsiDxe/LsiScsi.h      |   3 +
>>  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf |   6 ++
>>  OvmfPkg/OvmfPkg.dec               |   5 +
>>  4 files changed, 160 insertions(+), 2 deletions(-)
>>
>> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
>> index 67fadb411e85..989bda88d209 100644
>> --- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
>> +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
>> @@ -15,6 +15,7 @@
>>  #include <Library/BaseMemoryLib.h>
>>  #include <Library/DebugLib.h>
>>  #include <Library/MemoryAllocationLib.h>
>> +#include <Library/PcdLib.h>
>>  #include <Library/UefiBootServicesTableLib.h>
>>  #include <Library/UefiLib.h>
>>  #include <Protocol/PciIo.h>
>> @@ -53,6 +54,49 @@ LsiScsiGetNextTargetLun (
>>    IN OUT UINT64                      *Lun
>>    )
>>  {
>> +  LSI_SCSI_DEV *Dev;
>> +  UINTN        Idx;
>> +  UINT8        *Target;
>> +  UINT16       LastTarget;
>> +
>> +  //
>> +  // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
>> +  //
>> +  Target = *TargetPointer;
>> +
>> +  //
>> +  // Search for first non-0xFF byte. If not found, return first target & LUN.
>> +  //
>> +  for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)
>> +    ;
>> +  if (Idx == TARGET_MAX_BYTES) {
>> +    SetMem (Target, TARGET_MAX_BYTES, 0x00);
>> +    *Lun = 0;
>> +    return EFI_SUCCESS;
>> +  }
>> +
>> +  CopyMem (&LastTarget, Target, sizeof LastTarget);
>> +
>> +  //
>> +  // increment (target, LUN) pair if valid on input
>> +  //
>> +  Dev = LSI_SCSI_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;
>> +    CopyMem (Target, &LastTarget, sizeof LastTarget);
>> +    return EFI_SUCCESS;
>> +  }
>> +
>>    return EFI_NOT_FOUND;
>>  }
>>  
>> @@ -65,7 +109,34 @@ LsiScsiBuildDevicePath (
>>    IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath
>>    )
>>  {
>> -  return EFI_NOT_FOUND;
>> +  UINT16           TargetValue;
>> +  LSI_SCSI_DEV     *Dev;
>> +  SCSI_DEVICE_PATH *ScsiDevicePath;
>> +
>> +  if (DevicePath == NULL) {
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  CopyMem (&TargetValue, Target, sizeof TargetValue);
>> +  Dev = LSI_SCSI_FROM_PASS_THRU (This);
>> +  if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun || Lun > 0xFFFF) {
>> +    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;
>>  }
>>  
>>  EFI_STATUS
>> @@ -77,7 +148,33 @@ LsiScsiGetTargetLun (
>>    OUT UINT64                          *Lun
>>    )
>>  {
>> -  return EFI_UNSUPPORTED;
>> +  SCSI_DEVICE_PATH *ScsiDevicePath;
>> +  LSI_SCSI_DEV     *Dev;
>> +  UINT8            *Target;
>> +
>> +  if (DevicePath == NULL || TargetPointer == NULL || *TargetPointer == 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 = LSI_SCSI_FROM_PASS_THRU (This);
>> +  if (ScsiDevicePath->Pun > Dev->MaxTarget ||
>> +      ScsiDevicePath->Lun > Dev->MaxLun) {
>> +    return EFI_NOT_FOUND;
>> +  }
>> +
>> +  Target = *TargetPointer;
>> +  ZeroMem (Target, TARGET_MAX_BYTES);
>> +  CopyMem (Target, &ScsiDevicePath->Pun, sizeof ScsiDevicePath->Pun);
>> +  *Lun = ScsiDevicePath->Lun;
>> +
>> +  return EFI_SUCCESS;
>>  }
>>  
>>  EFI_STATUS
>> @@ -107,6 +204,42 @@ LsiScsiGetNextTarget (
>>    IN OUT UINT8                       **TargetPointer
>>    )
>>  {
>> +  LSI_SCSI_DEV *Dev;
>> +  UINTN        Idx;
>> +  UINT8        *Target;
>> +  UINT16       LastTarget;
>> +
>> +  //
>> +  // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
>> +  //
>> +  Target = *TargetPointer;
>> +
>> +  //
>> +  // Search for first non-0xFF byte. If not found, return first target.
>> +  //
>> +  for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)
>> +    ;
>> +  if (Idx == TARGET_MAX_BYTES) {
>> +    SetMem (Target, TARGET_MAX_BYTES, 0x00);
>> +    return EFI_SUCCESS;
>> +  }
>> +
>> +  CopyMem (&LastTarget, Target, sizeof LastTarget);
>> +
>> +  //
>> +  // increment target if valid on input
>> +  //
>> +  Dev = LSI_SCSI_FROM_PASS_THRU (This);
>> +  if (LastTarget > Dev->MaxTarget) {
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  if (LastTarget < Dev->MaxTarget) {
>> +    ++LastTarget;
>> +    CopyMem (Target, &LastTarget, sizeof LastTarget);
>> +    return EFI_SUCCESS;
>> +  }
>> +
>>    return EFI_NOT_FOUND;
>>  }
>>  
>> @@ -189,6 +322,17 @@ LsiScsiControllerStart (
>>  
>>    Dev->Signature = LSI_SCSI_DEV_SIGNATURE;
>>  
>> +  STATIC_ASSERT (
>> +    FixedPcdGet8 (PcdLsiScsiMaxTargetLimit) < 8,
>> +    "LSI 53C895A supports targets [0..7]"
>> +    );
>> +  STATIC_ASSERT (
>> +    FixedPcdGet8 (PcdLsiScsiMaxLunLimit) < 128,
>> +    "LSI 53C895A supports LUNs [0..128]"
>> +    );
> 
> (1) The condition on the LUN limit, and the error message for the same,
> are not consistent. The PCD is an inclusive limit. We assert that the
> PCD is strictly smaller than 128. Therefore the highest permitted PCD
> value is 127. Therefore the highest permitted LUN (because the PCD is
> inclusive) is 127. Therefore the error message should advertize
> "[0..127]", not "[0..128]". In other words, LUN 128 itself is not valid.
> 
> If LUN 128 *is* valid, and so PCD=128 too is valid, then the condition
> should be updated, to say "< 129".

OK, reading through my v1 review, I've realized (again) that 127 is the
maximum valid LUN (and so the max PCD value), therefore the problem is
in the message, not in the check. Please modify the message to "[0..127]".

Thanks
Laszlo

> 
>> +  Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);
>> +  Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);
>> +
>>    //
>>    // Host adapter channel, doesn't exist
>>    //
>> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
>> index c194dfbf3347..6c6ed25f1c33 100644
>> --- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
>> +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
>> @@ -14,6 +14,8 @@
>>  
>>  typedef struct {
>>    UINT32                          Signature;
>> +  UINT8                           MaxTarget;
>> +  UINT8                           MaxLun;
>>    EFI_EXT_SCSI_PASS_THRU_MODE     PassThruMode;
>>    EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
>>  } LSI_SCSI_DEV;
>> @@ -23,6 +25,7 @@ typedef struct {
>>  #define LSI_SCSI_FROM_PASS_THRU(PassThruPtr) \
>>    CR (PassThruPtr, LSI_SCSI_DEV, PassThru, LSI_SCSI_DEV_SIGNATURE)
>>  
>> +
>>  //
>>  // Probe, start and stop functions of this driver, called by the DXE core for
>>  // specific devices.
> 
> (2) You missed point (4) in my v1 review -- the above newline is
> spurious, so it should be removed from this patch. (It should either be
> removed completely, or squashed into the patch that introduces the
> LSI_SCSI_FROM_PASS_THRU macro.)
> 
> With (1) and (2) fixed:
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> 
> Thanks
> Laszlo
> 
>> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
>> index 14f9c68308cc..6111449577a8 100644
>> --- a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
>> +++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
>> @@ -27,7 +27,9 @@ [Packages]
>>  [LibraryClasses]
>>    BaseLib
>>    BaseMemoryLib
>> +  DebugLib
>>    MemoryAllocationLib
>> +  PcdLib
>>    UefiBootServicesTableLib
>>    UefiDriverEntryPoint
>>    UefiLib
>> @@ -35,3 +37,7 @@ [LibraryClasses]
>>  [Protocols]
>>    gEfiExtScsiPassThruProtocolGuid        ## BY_START
>>    gEfiPciIoProtocolGuid                  ## TO_START
>> +
>> +[FixedPcd]
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit   ## CONSUMES
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit      ## CONSUMES
>> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
>> index 2b0f137cbcce..ca13a3cb11d3 100644
>> --- a/OvmfPkg/OvmfPkg.dec
>> +++ b/OvmfPkg/OvmfPkg.dec
>> @@ -174,6 +174,11 @@ [PcdsFixedAtBuild]
>>    ## Microseconds to stall between polling for MptScsi request result
>>    gUefiOvmfPkgTokenSpaceGuid.PcdMptScsiStallPerPollUsec|5|UINT32|0x3a
>>  
>> +  ## Set the *inclusive* number of targets and LUNs that LsiScsi exposes for
>> +  #  scan by ScsiBusDxe.
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit|7|UINT8|0x3b
>> +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit|0|UINT8|0x3c
>> +
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogBase|0x0|UINT32|0x8
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogSize|0x0|UINT32|0x9
>>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize|0x0|UINT32|0xa
>>
> 


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

* Re: [PATCH v2 10/12] OvmfPkg/LsiScsiDxe: Process the SCSI Request Packet
  2020-07-16  7:46 ` [PATCH v2 10/12] OvmfPkg/LsiScsiDxe: Process the " Gary Lin
@ 2020-07-16 17:37   ` Laszlo Ersek
  2020-07-17  2:28     ` Gary Lin
  0 siblings, 1 reply; 21+ messages in thread
From: Laszlo Ersek @ 2020-07-16 17:37 UTC (permalink / raw)
  To: Gary Lin, devel; +Cc: Jordan Justen, Ard Biesheuvel

On 07/16/20 09:46, Gary Lin wrote:
> This is the second part of LsiScsiPassThru(). LsiScsiProcessRequest() is
> added to translate the SCSI Request Packet into the LSI 53C895A
> commands. This function utilizes the so-called Script buffer to transmit
> a series of commands to the chip and then polls the DMA Status (DSTAT)
> register until the Scripts Interrupt Instruction Received (SIR) bit
> sets. Once the script is done, the SCSI Request Packet will be modified
> to reflect the result of the script.
> 
> v2:
>   - Use the BITx macros for the most of LSI_* constants
>   - Fix a typo: contorller => controller
>   - Add SeaBIOS lsi-scsi driver as one of the references of the script
>   - Cast the result of sizeof to UINT32 for the instructions of the
>     script
>   - Drop the backslashes
>   - Replace LSI_SCSI_DMA_ADDR_LOW with LSI_SCSI_DMA_ADDR since we
>     already removed DUAL_ADDRESS_CYCLE
>   - Add more comments for the script
>   - Fix the check of the script size at the end of the script
>   - Always set SenseDataLength to 0 to avoid the caller to access
>     SenseData
>   - Improve the error handling in LsiScsiProcessRequest()
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>  OvmfPkg/Include/IndustryStandard/LsiScsi.h |  63 ++++
>  OvmfPkg/LsiScsiDxe/LsiScsi.c               | 336 ++++++++++++++++++++-
>  OvmfPkg/LsiScsiDxe/LsiScsi.h               |  21 ++
>  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf          |   3 +
>  OvmfPkg/OvmfPkg.dec                        |   3 +
>  5 files changed, 425 insertions(+), 1 deletion(-)
> 
> diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> index 185e553c8eb4..9964bd40385c 100644
> --- a/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> +++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> @@ -26,6 +26,18 @@
>  #define LSI_REG_SIST0             0x42
>  #define LSI_REG_SIST1             0x43
>  
> +//
> +// The status bits for DMA Status (DSTAT)
> +//
> +#define LSI_DSTAT_IID             BIT0
> +#define LSI_DSTAT_R               BIT1
> +#define LSI_DSTAT_SIR             BIT2
> +#define LSI_DSTAT_SSI             BIT3
> +#define LSI_DSTAT_ABRT            BIT4
> +#define LSI_DSTAT_BF              BIT5
> +#define LSI_DSTAT_MDPE            BIT6
> +#define LSI_DSTAT_DFE             BIT7
> +
>  //
>  // The status bits for Interrupt Status Zero (ISTAT0)
>  //
> @@ -38,4 +50,55 @@
>  #define LSI_ISTAT0_SRST           BIT6
>  #define LSI_ISTAT0_ABRT           BIT7
>  
> +//
> +// The status bits for SCSI Interrupt Status Zero (SIST0)
> +//
> +#define LSI_SIST0_PAR             BIT0
> +#define LSI_SIST0_RST             BIT1
> +#define LSI_SIST0_UDC             BIT2
> +#define LSI_SIST0_SGE             BIT3
> +#define LSI_SIST0_RSL             BIT4
> +#define LSI_SIST0_SEL             BIT5
> +#define LSI_SIST0_CMP             BIT6
> +#define LSI_SIST0_MA              BIT7
> +
> +//
> +// The status bits for SCSI Interrupt Status One (SIST1)
> +//
> +#define LSI_SIST1_HTH             BIT0
> +#define LSI_SIST1_GEN             BIT1
> +#define LSI_SIST1_STO             BIT2
> +#define LSI_SIST1_R3              BIT3
> +#define LSI_SIST1_SBMC            BIT4
> +#define LSI_SIST1_R5              BIT5
> +#define LSI_SIST1_R6              BIT6
> +#define LSI_SIST1_R7              BIT7
> +
> +//
> +// LSI 53C895A Script Instructions
> +//
> +#define LSI_INS_TYPE_BLK          0x00000000
> +#define LSI_INS_TYPE_IO           BIT30
> +#define LSI_INS_TYPE_TC           BIT31
> +
> +#define LSI_INS_BLK_SCSIP_DAT_OUT 0x00000000
> +#define LSI_INS_BLK_SCSIP_DAT_IN  BIT24
> +#define LSI_INS_BLK_SCSIP_CMD     BIT25
> +#define LSI_INS_BLK_SCSIP_STAT    (BIT24 | BIT25)
> +#define LSI_INS_BLK_SCSIP_MSG_OUT (BIT25 | BIT26)
> +#define LSI_INS_BLK_SCSIP_MSG_IN  (BIT24 | BIT25 | BIT26)
> +
> +#define LSI_INS_IO_OPC_SEL        0x00000000
> +#define LSI_INS_IO_OPC_WAIT_RESEL BIT28
> +
> +#define LSI_INS_TC_CP             BIT17
> +#define LSI_INS_TC_JMP            BIT19
> +#define LSI_INS_TC_RA             BIT23
> +
> +#define LSI_INS_TC_OPC_JMP        0x00000000
> +#define LSI_INS_TC_OPC_INT        (BIT27 | BIT28)
> +
> +#define LSI_INS_TC_SCSIP_DAT_OUT  0x00000000
> +#define LSI_INS_TC_SCSIP_MSG_IN   (BIT24 | BIT25 | BIT26)
> +
>  #endif // _LSI_SCSI_H_
> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> index b3a88cc7119b..d5fe1d4ab3b8 100644
> --- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
> +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> @@ -43,6 +43,42 @@ Out8 (
>                            );
>  }
>  
> +STATIC
> +EFI_STATUS
> +Out32 (
> +  IN LSI_SCSI_DEV       *Dev,
> +  IN UINT32             Addr,
> +  IN UINT32             Data
> +  )
> +{
> +  return Dev->PciIo->Io.Write (
> +                          Dev->PciIo,
> +                          EfiPciIoWidthUint32,
> +                          PCI_BAR_IDX0,
> +                          Addr,
> +                          1,
> +                          &Data
> +                          );
> +}
> +
> +STATIC
> +EFI_STATUS
> +In8 (
> +  IN  LSI_SCSI_DEV *Dev,
> +  IN  UINT32       Addr,
> +  OUT UINT8        *Data
> +  )
> +{
> +  return Dev->PciIo->Io.Read (
> +                          Dev->PciIo,
> +                          EfiPciIoWidthUint8,
> +                          PCI_BAR_IDX0,
> +                          Addr,
> +                          1,
> +                          Data
> +                          );
> +}
> +
>  STATIC
>  EFI_STATUS
>  LsiScsiReset (
> @@ -141,6 +177,303 @@ LsiScsiCheckRequest (
>    return EFI_SUCCESS;
>  }
>  
> +/**
> +
> +  Interpret the request packet from the Extended SCSI Pass Thru Protocol and
> +  compose the script to submit the command and data to the controller.
> +
> +  @param[in] Dev          The LSI 53C895A SCSI device the packet targets.
> +
> +  @param[in] Target       The SCSI target controlled by the LSI 53C895A SCSI
> +                          device.
> +
> +  @param[in] Lun          The Logical Unit Number under the SCSI target.
> +
> +  @param[in out] Packet   The Extended SCSI Pass Thru Protocol packet.
> +
> +
> +  @retval EFI_SUCCESS  The Extended SCSI Pass Thru Protocol packet was valid.
> +
> +  @return              Otherwise, invalid or unsupported parameters were
> +                       detected. Status codes are meant for direct forwarding
> +                       by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()
> +                       implementation.
> +
> + **/
> +STATIC
> +EFI_STATUS
> +LsiScsiProcessRequest (
> +  IN LSI_SCSI_DEV                                   *Dev,
> +  IN UINT8                                          Target,
> +  IN UINT64                                         Lun,
> +  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
> +  )
> +{
> +  EFI_STATUS Status;
> +  UINT32     *Script;
> +  UINT8      *Cdb;
> +  UINT8      *MsgOut;
> +  UINT8      *MsgIn;
> +  UINT8      *ScsiStatus;
> +  UINT8      *Data;
> +  UINT8      DStat;
> +  UINT8      SIst0;
> +  UINT8      SIst1;
> +
> +  Script      = Dev->Dma->Script;
> +  Cdb         = Dev->Dma->Cdb;
> +  Data        = Dev->Dma->Data;
> +  MsgIn       = Dev->Dma->MsgIn;
> +  MsgOut      = &Dev->Dma->MsgOut;
> +  ScsiStatus  = &Dev->Dma->Status;
> +
> +  *ScsiStatus = 0xFF;
> +
> +  SetMem (Cdb, sizeof Dev->Dma->Cdb, 0x00);
> +  CopyMem (Cdb, Packet->Cdb, Packet->CdbLength);
> +
> +  //
> +  // Clean up the DMA buffer for the script.
> +  //
> +  SetMem (Script, sizeof Dev->Dma->Script, 0x00);
> +
> +  //
> +  // Compose the script to transfer data between the host and the device.
> +  //
> +  // References:
> +  //   * LSI53C895A PCI to Ultra2 SCSI Controller Version 2.2
> +  //     - Chapter 5 SCSI SCRIPT Instruction Set
> +  //   * SEABIOS lsi-scsi driver
> +  //
> +  // All instructions used here consist of 2 32bit words. The first word
> +  // contains the command to execute. The second word is loaded into the
> +  // DMA SCRIPTS Pointer Save (DSPS) register as either the DMA address
> +  // for data transmission or the address/offset for the jump command.
> +  // Some commands, such as the selection of the target, don't need to
> +  // transfer data through DMA or jump to another instruction, then DSPS
> +  // has to be zero.
> +  //
> +  // There are 3 major parts in this script. The first part (1~3) contains
> +  // the instructions to select target and LUN and send the SCSI command
> +  // from the request packet. The second part (4~7) is to handle the
> +  // potential disconnection and prepare for the data transmission. The
> +  // instructions in the third part (8~10) transmit the given data and
> +  // collect the result. Instruction 11 raises the interrupt and marks the
> +  // end of the script.
> +  //
> +
> +  //
> +  // 1. Select target.
> +  //
> +  *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_SEL | (UINT32)Target << 16;
> +  *Script++ = 0x00000000;
> +
> +  //
> +  // 2. Select LUN.
> +  //
> +  *MsgOut   = 0x80 | (UINT8) Lun; // 0x80: Identify bit
> +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_OUT |
> +              (UINT32)sizeof Dev->Dma->MsgOut;
> +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgOut);
> +
> +  //
> +  // 3. Send the SCSI Command.
> +  //
> +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_CMD |
> +              (UINT32)sizeof Dev->Dma->Cdb;
> +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, Cdb);
> +
> +  //
> +  // 4. Check whether the current SCSI phase is "Message In" or not
> +  //    and jump to 7 if it is.
> +  //    Note: LSI_INS_TC_RA stands for "Relative Address Mode", so the
> +  //          offset 0x18 in the second word means jumping forward
> +  //          3 (0x18/8) instructions.
> +  //
> +  *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_JMP |
> +              LSI_INS_TC_SCSIP_MSG_IN | LSI_INS_TC_RA |
> +              LSI_INS_TC_CP;
> +  *Script++ = 0x00000018;
> +
> +  //
> +  // 5. Read "Message" from the initiator to trigger reselect.
> +  //
> +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
> +              (UINT32)sizeof Dev->Dma->MsgIn;
> +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
> +
> +  //
> +  // 6. Wait reselect.
> +  //
> +  *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_WAIT_RESEL;
> +  *Script++ = 0x00000000;
> +
> +  //
> +  // 7. Read "Message" from the initiator again
> +  //
> +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
> +              (UINT32)sizeof Dev->Dma->MsgIn;
> +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
> +
> +  //
> +  // 8. Set the DMA command for the read/write operations.
> +  //    Note: Some requests, e.g. "TEST UNIT READY", do not come with
> +  //          allocated InDataBuffer or OutDataBuffer. We skip the DMA
> +  //          data command for those requests or this script would fail
> +  //          with LSI_SIST0_SGE due to the zero data length.
> +  //
> +  // LsiScsiCheckRequest() prevents both integer overflows in the command
> +  // opcodes, and buffer overflows.
> +  //
> +  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ &&
> +      Packet->InTransferLength > 0) {
> +    ASSERT (Packet->InTransferLength <= sizeof Dev->Dma->Data);
> +    *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_IN |
> +                Packet->InTransferLength;
> +    *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);
> +  } else if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE &&
> +             Packet->OutTransferLength > 0) {
> +    ASSERT (Packet->OutTransferLength <= sizeof Dev->Dma->Data);
> +    CopyMem (Data, Packet->OutDataBuffer, Packet->OutTransferLength);
> +    *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_OUT |
> +                Packet->OutTransferLength;
> +    *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);
> +  }

I understand the explanation, thanks.

However, we can still improve this code. The following sub-conditions:

  Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ

and

  Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE

are superfluous. What we care about are

  Packet->InTransferLength > 0

and

  Packet->OutTransferLength > 0

And the latter (length-based) conditions actually *imply* the former
(direction-based) conditions, because:

- LsiScsiCheckRequest() returns EFI_INVALID_PARAMETER if
  DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL

- LsiScsiCheckRequest() returns EFI_UNSUPPORTED if
  DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL

- LsiScsiCheckRequest() returns EFI_INVALID_PARAMETER if
  InTransferLength > 0, but
  DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE

- LsiScsiCheckRequest() returns EFI_INVALID_PARAMETER if
  OutTransferLength > 0, but
  DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ

This means that (InTransferLength > 0) guarantees
EFI_EXT_SCSI_DATA_DIRECTION_READ, and (OutTransferLength > 0) guarantees
EFI_EXT_SCSI_DATA_DIRECTION_WRITE.

(1) Therefore I suggest moving the respective sub-conditions from the
"if" statements into the dependent blocks, as assertions:

  if (Packet->InTransferLength > 0) {
    ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ);
    ASSERT (Packet->InTransferLength <= sizeof Dev->Dma->Data);
    ...
  } else if (Packet->OutTransferLength > 0) {
    ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE);
    ASSERT (Packet->OutTransferLength <= sizeof Dev->Dma->Data);
    ...
  }

> +
> +  //
> +  // 9. Get the SCSI status.
> +  //
> +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_STAT |
> +              (UINT32)sizeof Dev->Dma->Status;
> +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, Status);
> +
> +  //
> +  // 10. Get the SCSI message.
> +  //
> +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
> +              (UINT32)sizeof Dev->Dma->MsgIn;
> +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
> +
> +  //
> +  // 11. Raise the interrupt to end the script.
> +  //
> +  *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_INT |
> +              LSI_INS_TC_SCSIP_DAT_OUT | LSI_INS_TC_JMP;
> +  *Script++ = 0x00000000;
> +
> +  //
> +  // Make sure the size of the script doesn't exceed the buffer.
> +  //
> +  ASSERT (Script <= Dev->Dma->Script + ARRAY_SIZE (Dev->Dma->Script));
> +
> +  //
> +  // The controller starts to execute the script once the DMA Script
> +  // Pointer (DSP) register is set.
> +  //
> +  Status = Out32 (Dev, LSI_REG_DSP, LSI_SCSI_DMA_ADDR (Dev, Script));
> +  if (EFI_ERROR (Status)) {
> +    goto Error;
> +  }
> +
> +  //
> +  // Poll the device registers (DSTAT, SIST0, and SIST1) until the SIR
> +  // bit sets.
> +  //
> +  for(;;) {
> +    Status = In8 (Dev, LSI_REG_DSTAT, &DStat);
> +    if (EFI_ERROR (Status)) {
> +      goto Error;
> +    }
> +    Status = In8 (Dev, LSI_REG_SIST0, &SIst0);
> +    if (EFI_ERROR (Status)) {
> +      goto Error;
> +    }
> +    Status = In8 (Dev, LSI_REG_SIST1, &SIst1);
> +    if (EFI_ERROR (Status)) {
> +      goto Error;
> +    }
> +
> +    if (SIst0 != 0 || SIst1 != 0) {
> +      goto Error;
> +    }
> +
> +    //
> +    // Check the SIR (SCRIPTS Interrupt Instruction Received) bit.
> +    //
> +    if (DStat & LSI_DSTAT_SIR) {
> +      break;
> +    }
> +
> +    gBS->Stall (Dev->StallPerPollUsec);
> +  }
> +
> +  //
> +  // Check if everything is good.
> +  //   SCSI Message Code 0x00: COMMAND COMPLETE
> +  //   SCSI Status  Code 0x00: Good
> +  //
> +  if (MsgIn[0] != 0 || *ScsiStatus != 0) {
> +    goto Error;
> +  }
> +
> +  //
> +  // Copy Data to InDataBuffer if necessary.
> +  //
> +  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
> +    CopyMem (Packet->InDataBuffer, Data, Packet->InTransferLength);
> +  }
> +
> +  //
> +  // Always set SenseDataLength to 0.
> +  // The instructions of LSI53C895A doesn't reply sense data. Instead, it
> +  // relies on the SCSI command, "REQUEST SENSE", to get sense data. We set
> +  // SenseDataLength to 0 to notify ScsiDiskDxe that there is no sense data
> +  // written even if this request is processed successfully, so that It will
> +  // issue "REQUEST SENSE" later to retrieve sense data.
> +  //
> +  Packet->SenseDataLength   = 0;
> +  Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
> +  Packet->TargetStatus      = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
> +
> +  return EFI_SUCCESS;
> +
> +Error:
> +  DEBUG ((DEBUG_VERBOSE, "%a: dstat: %02X, sist0: %02X, sist1: %02X\n",
> +    __FUNCTION__, DStat, SIst0, SIst1));

The Error label may be reached without setting some (or even any) of
DStat, SIst0, SIst1.

(2) Please set all three of DStat, SIst0, and SIst1 to zero, near the
top of the function, with explicit assignments (not initialization).

> +  //
> +  // Update the request packet to reflect the status.
> +  //
> +  if (*ScsiStatus != 0xFF) {
> +    Packet->TargetStatus    = *ScsiStatus;
> +  } else {
> +    Packet->TargetStatus    = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;
> +  }
> +
> +  if (SIst0 & LSI_SIST0_PAR) {
> +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR;
> +  } else if (SIst0 & LSI_SIST0_RST) {
> +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;
> +  } else if (SIst0 & LSI_SIST0_UDC) {
> +    //
> +    // The target device is disconnected unexpectedly. According to UEFI spec,
> +    // this is TIMEOUT_COMMAND.
> +    //
> +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
> +  } else if (SIst0 & LSI_SIST0_SGE) {
> +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
> +  } else if (SIst1 & LSI_SIST1_HTH) {
> +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
> +  } else if (SIst1 & LSI_SIST1_GEN) {
> +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
> +  } else if (SIst1 & LSI_SIST1_STO) {
> +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
> +  } else {
> +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
> +  }

According to the UEFI spec, on EFI_DEVICE_ERROR (see below):

  See HostAdapterStatus, TargetStatus, SenseDataLength, and SenseData in
  that order for additional status information.

(3) Therefore, on this error branch, please also set SenseDataLength to
zero.

> +
> +  return EFI_DEVICE_ERROR;
> +}
> +
>  //
>  // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
>  // for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
> @@ -168,7 +501,7 @@ LsiScsiPassThru (
>      return Status;
>    }
>  
> -  return EFI_UNSUPPORTED;
> +  return LsiScsiProcessRequest (Dev, *Target, Lun, Packet);
>  }

The LsiScsiPassThru() function can now return EFI_SUCCESS, without
updating InTransferLength and OutTransferLength.

But sticking (for now) with EFI_UNSUPPORTED would also be wrong, because
(according to the UEFI spec) EFI_UNSUPPORTED means "The SCSI Request
Packet was not sent", and here we *did* talk to the device.

(4) So please squash the next patch -- "[PATCH v2 11/12]
OvmfPkg/LsiScsiDxe: Calculate the transferred bytes" -- into this one,
in the v3 series.

(The next patch, which handles the transfer lengths, is not large,
thankfully.)

For now I'll comment separately under that patch.

Thanks!
Laszlo

>  
>  EFI_STATUS
> @@ -474,6 +807,7 @@ LsiScsiControllerStart (
>      );
>    Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);
>    Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);
> +  Dev->StallPerPollUsec = PcdGet32 (PcdLsiScsiStallPerPollUsec);
>  
>    Status = gBS->OpenProtocol (
>                    ControllerHandle,
> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
> index 05deeed379fe..6ecf523f5a9e 100644
> --- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
> +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
> @@ -13,6 +13,11 @@
>  #define _LSI_SCSI_DXE_H_
>  
>  typedef struct {
> +  //
> +  // Allocate 32 UINT32 entries for the script and it's sufficient for
> +  // 16 instructions.
> +  //
> +  UINT32                          Script[32];
>    //
>    // The max size of CDB is 32.
>    //
> @@ -25,6 +30,18 @@ typedef struct {
>    //       Count (DBC), a 24-bit register, so the maximum is 0xFFFFFF (16MB-1).
>    //
>    UINT8                           Data[SIZE_64KB];
> +  //
> +  // For SCSI Message In phase
> +  //
> +  UINT8                           MsgIn[2];
> +  //
> +  // For SCSI Message Out phase
> +  //
> +  UINT8                           MsgOut;
> +  //
> +  // For SCSI Status phase
> +  //
> +  UINT8                           Status;
>  } LSI_SCSI_DMA_BUFFER;
>  
>  typedef struct {
> @@ -34,6 +51,7 @@ typedef struct {
>    EFI_PCI_IO_PROTOCOL             *PciIo;
>    UINT8                           MaxTarget;
>    UINT8                           MaxLun;
> +  UINT32                          StallPerPollUsec;
>    LSI_SCSI_DMA_BUFFER             *Dma;
>    EFI_PHYSICAL_ADDRESS            DmaPhysical;
>    VOID                            *DmaMapping;
> @@ -46,6 +64,9 @@ typedef struct {
>  #define LSI_SCSI_FROM_PASS_THRU(PassThruPtr) \
>    CR (PassThruPtr, LSI_SCSI_DEV, PassThru, LSI_SCSI_DEV_SIGNATURE)
>  
> +#define LSI_SCSI_DMA_ADDR(Dev, MemberName) \
> +  ((UINT32)(Dev->DmaPhysical + OFFSET_OF (LSI_SCSI_DMA_BUFFER, MemberName)))
> +
>  
>  //
>  // Probe, start and stop functions of this driver, called by the DXE core for
> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
> index 6111449577a8..4c7abcec618f 100644
> --- a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
> +++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
> @@ -41,3 +41,6 @@ [Protocols]
>  [FixedPcd]
>    gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit   ## CONSUMES
>    gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit      ## CONSUMES
> +
> +[Pcd]
> +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiStallPerPollUsec ## CONSUMES
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index ca13a3cb11d3..f16c00ad5b99 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -179,6 +179,9 @@ [PcdsFixedAtBuild]
>    gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit|7|UINT8|0x3b
>    gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit|0|UINT8|0x3c
>  
> +  ## Microseconds to stall between polling for LsiScsi request result
> +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiStallPerPollUsec|5|UINT32|0x3d
> +
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogBase|0x0|UINT32|0x8
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogSize|0x0|UINT32|0x9
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize|0x0|UINT32|0xa
> 


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

* Re: [PATCH v2 11/12] OvmfPkg/LsiScsiDxe: Calculate the transferred bytes
  2020-07-16  7:46 ` [PATCH v2 11/12] OvmfPkg/LsiScsiDxe: Calculate the transferred bytes Gary Lin
@ 2020-07-16 18:21   ` Laszlo Ersek
  2020-07-17  3:15     ` Gary Lin
  0 siblings, 1 reply; 21+ messages in thread
From: Laszlo Ersek @ 2020-07-16 18:21 UTC (permalink / raw)
  To: Gary Lin, devel; +Cc: Jordan Justen, Ard Biesheuvel

On 07/16/20 09:46, Gary Lin wrote:
> Calculate the transferred bytes during data phases based on the
> Cumulative SCSI Byte Count (CSBC) and update
> InTransferLength/OutTransferLength of the request packet.
> 
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
>  OvmfPkg/Include/IndustryStandard/LsiScsi.h |  1 +
>  OvmfPkg/LsiScsiDxe/LsiScsi.c               | 50 ++++++++++++++++++++++
>  2 files changed, 51 insertions(+)
> 
> diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> index 9964bd40385c..01d75323cdbc 100644
> --- a/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> +++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> @@ -25,6 +25,7 @@
>  #define LSI_REG_DSP               0x2C
>  #define LSI_REG_SIST0             0x42
>  #define LSI_REG_SIST1             0x43
> +#define LSI_REG_CSBC              0xDC
>  
>  //
>  // The status bits for DMA Status (DSTAT)
> diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> index d5fe1d4ab3b8..10483ed02bd7 100644
> --- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
> +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> @@ -79,6 +79,24 @@ In8 (
>                            );
>  }
>  
> +STATIC
> +EFI_STATUS
> +In32 (
> +  IN  LSI_SCSI_DEV *Dev,
> +  IN  UINT32       Addr,
> +  OUT UINT32       *Data
> +  )
> +{
> +  return Dev->PciIo->Io.Read (
> +                          Dev->PciIo,
> +                          EfiPciIoWidthUint32,
> +                          PCI_BAR_IDX0,
> +                          Addr,
> +                          1,
> +                          Data
> +                          );
> +}
> +
>  STATIC
>  EFI_STATUS
>  LsiScsiReset (
> @@ -219,6 +237,8 @@ LsiScsiProcessRequest (
>    UINT8      DStat;
>    UINT8      SIst0;
>    UINT8      SIst1;
> +  UINT32     Csbc;
> +  UINT32     CsbcBase;
>  
>    Script      = Dev->Dma->Script;
>    Cdb         = Dev->Dma->Cdb;
> @@ -232,6 +252,18 @@ LsiScsiProcessRequest (
>    SetMem (Cdb, sizeof Dev->Dma->Cdb, 0x00);
>    CopyMem (Cdb, Packet->Cdb, Packet->CdbLength);
>  
> +  //
> +  // Fetch the first Cumulative SCSI Byte Count (CSBC).
> +  //
> +  // CSBC is a cumulative counter of the actual number of bytes that has been

(1) typo: s/has been/have been/

> +  // transferred across the SCSI bus during data phases, i.e. it will not

(2) typo (I think): s/will not/will not count/

> +  // bytes sent in command, status, message in and out phases.
> +  //
> +  Status = In32 (Dev, LSI_REG_CSBC, &CsbcBase);
> +  if (EFI_ERROR (Status)) {
> +    return Status;

(3) IMO, we should not return directly, but jump to the Error label.

> +  }
> +
>    //
>    // Clean up the DMA buffer for the script.
>    //
> @@ -407,6 +439,24 @@ LsiScsiProcessRequest (
>      gBS->Stall (Dev->StallPerPollUsec);
>    }
>  
> +  //
> +  // Fetch CSBC again to calculate the transferred bytes and update
> +  // InTransferLength/OutTransferLength.
> +  //

This calculation matters for EFI_SUCCESS. But at this point we cannot
yet guarantee that we'll return EFI_SUCCESS.

(4) So I suggest postponing the CSBC re-fetch until after we're past the
last "goto Error" statement -- that is, just before "Copy Data to
InDataBuffer if necessary".

> +  // Note: The number of transferred bytes is bounded by
> +  //       "sizeof Dev->Dma->Data", so it's safe to subtract CsbcBase
> +  //       from Csbc.
> +  //

It's safe to perform the subtraction, but I think we should extend the
comment.

This register seems to be a 4-byte counter. It's not super difficult to
transfer more than 4GB even in UEFI, and so the counter might wrap around.

Luckily, when it wraps around, the subtraction will do exactly the right
thing. (And for that, it is indeed relevant that the max requestable
transfer size is smaller than (MAX_UINT32+1).)

Assume

  Csbc < CsbcBase

This means (a) the counter has wrapped, and (b) mathematically, the
difference

  Csbc - Csbcbase

is negative.

Given that we use UINT32 variables here, the resultant value (in C) will
be (per C standard):

  (MAX_UINT32 + 1) + (Csbc - Csbcbase)                               [1]

And that's perfect! Because, what does it mean that "CSBC wraps"? It
means that the mathematical meaning of the new CSBC value is:

  ((MAX_UINT32 + 1) + Csbc)

(It's just a different way to say that bit#32 is set in the mathematical
value.)

Consequently, for getting the right difference, we'd have to calculate:

  ((MAX_UINT32 + 1) + Csbc) - Csbcbase                               [2]

But that's exactly what the C language *already* gives us, in [1].


(5) So please append the following sentence to the comment:

  If the CSBC register wraps around, the correct difference is ensured
  by the standard C modular arithmetic.

(6) Furthermore, please dedicate a new variable to the difference:

  UINT32 Transferred;

  Transferred = Csbc - CsbcBase;

> +  Status = In32 (Dev, LSI_REG_CSBC, &Csbc);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }

(7) Again I think we should jump to the Error label.

> +  if (Packet->InTransferLength > 0) {
> +    Packet->InTransferLength = Csbc - CsbcBase;
> +  } else if (Packet->OutTransferLength > 0) {
> +    Packet->OutTransferLength = Csbc - CsbcBase;
> +  }
> +

(8) I'd recommend a sanity check -- it's unlikely that the device will
blatantly lie, but if it ever happens, we should not let it out.

We may only ever reduce the transfer length. Thus:

  if (Packet->InTransferLength > 0) {
    if (Transferred <= Packet->InTransferLength) {
      Packet->InTransferLength = Transferred;
    } else {
      goto Error;
    }
  } else if (Packet->OutTransferLength > 0) {
    if (Transferred <= Packet->OutTransferLength) {
      Packet->OutTransferLength = Transferred;
    } else {
      goto Error;
    }
  }

Thanks,
Laszlo

>    //
>    // Check if everything is good.
>    //   SCSI Message Code 0x00: COMMAND COMPLETE
> 


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

* Re: [PATCH v2 10/12] OvmfPkg/LsiScsiDxe: Process the SCSI Request Packet
  2020-07-16 17:37   ` Laszlo Ersek
@ 2020-07-17  2:28     ` Gary Lin
  0 siblings, 0 replies; 21+ messages in thread
From: Gary Lin @ 2020-07-17  2:28 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: devel, Jordan Justen, Ard Biesheuvel

On Thu, Jul 16, 2020 at 07:37:09PM +0200, Laszlo Ersek wrote:
> On 07/16/20 09:46, Gary Lin wrote:
> > This is the second part of LsiScsiPassThru(). LsiScsiProcessRequest() is
> > added to translate the SCSI Request Packet into the LSI 53C895A
> > commands. This function utilizes the so-called Script buffer to transmit
> > a series of commands to the chip and then polls the DMA Status (DSTAT)
> > register until the Scripts Interrupt Instruction Received (SIR) bit
> > sets. Once the script is done, the SCSI Request Packet will be modified
> > to reflect the result of the script.
> > 
> > v2:
> >   - Use the BITx macros for the most of LSI_* constants
> >   - Fix a typo: contorller => controller
> >   - Add SeaBIOS lsi-scsi driver as one of the references of the script
> >   - Cast the result of sizeof to UINT32 for the instructions of the
> >     script
> >   - Drop the backslashes
> >   - Replace LSI_SCSI_DMA_ADDR_LOW with LSI_SCSI_DMA_ADDR since we
> >     already removed DUAL_ADDRESS_CYCLE
> >   - Add more comments for the script
> >   - Fix the check of the script size at the end of the script
> >   - Always set SenseDataLength to 0 to avoid the caller to access
> >     SenseData
> >   - Improve the error handling in LsiScsiProcessRequest()
> > 
> > Cc: Jordan Justen <jordan.l.justen@intel.com>
> > Cc: Laszlo Ersek <lersek@redhat.com>
> > Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
> > Signed-off-by: Gary Lin <glin@suse.com>
> > ---
> >  OvmfPkg/Include/IndustryStandard/LsiScsi.h |  63 ++++
> >  OvmfPkg/LsiScsiDxe/LsiScsi.c               | 336 ++++++++++++++++++++-
> >  OvmfPkg/LsiScsiDxe/LsiScsi.h               |  21 ++
> >  OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf          |   3 +
> >  OvmfPkg/OvmfPkg.dec                        |   3 +
> >  5 files changed, 425 insertions(+), 1 deletion(-)
> > 
> > diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> > index 185e553c8eb4..9964bd40385c 100644
> > --- a/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> > +++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> > @@ -26,6 +26,18 @@
> >  #define LSI_REG_SIST0             0x42
> >  #define LSI_REG_SIST1             0x43
> >  
> > +//
> > +// The status bits for DMA Status (DSTAT)
> > +//
> > +#define LSI_DSTAT_IID             BIT0
> > +#define LSI_DSTAT_R               BIT1
> > +#define LSI_DSTAT_SIR             BIT2
> > +#define LSI_DSTAT_SSI             BIT3
> > +#define LSI_DSTAT_ABRT            BIT4
> > +#define LSI_DSTAT_BF              BIT5
> > +#define LSI_DSTAT_MDPE            BIT6
> > +#define LSI_DSTAT_DFE             BIT7
> > +
> >  //
> >  // The status bits for Interrupt Status Zero (ISTAT0)
> >  //
> > @@ -38,4 +50,55 @@
> >  #define LSI_ISTAT0_SRST           BIT6
> >  #define LSI_ISTAT0_ABRT           BIT7
> >  
> > +//
> > +// The status bits for SCSI Interrupt Status Zero (SIST0)
> > +//
> > +#define LSI_SIST0_PAR             BIT0
> > +#define LSI_SIST0_RST             BIT1
> > +#define LSI_SIST0_UDC             BIT2
> > +#define LSI_SIST0_SGE             BIT3
> > +#define LSI_SIST0_RSL             BIT4
> > +#define LSI_SIST0_SEL             BIT5
> > +#define LSI_SIST0_CMP             BIT6
> > +#define LSI_SIST0_MA              BIT7
> > +
> > +//
> > +// The status bits for SCSI Interrupt Status One (SIST1)
> > +//
> > +#define LSI_SIST1_HTH             BIT0
> > +#define LSI_SIST1_GEN             BIT1
> > +#define LSI_SIST1_STO             BIT2
> > +#define LSI_SIST1_R3              BIT3
> > +#define LSI_SIST1_SBMC            BIT4
> > +#define LSI_SIST1_R5              BIT5
> > +#define LSI_SIST1_R6              BIT6
> > +#define LSI_SIST1_R7              BIT7
> > +
> > +//
> > +// LSI 53C895A Script Instructions
> > +//
> > +#define LSI_INS_TYPE_BLK          0x00000000
> > +#define LSI_INS_TYPE_IO           BIT30
> > +#define LSI_INS_TYPE_TC           BIT31
> > +
> > +#define LSI_INS_BLK_SCSIP_DAT_OUT 0x00000000
> > +#define LSI_INS_BLK_SCSIP_DAT_IN  BIT24
> > +#define LSI_INS_BLK_SCSIP_CMD     BIT25
> > +#define LSI_INS_BLK_SCSIP_STAT    (BIT24 | BIT25)
> > +#define LSI_INS_BLK_SCSIP_MSG_OUT (BIT25 | BIT26)
> > +#define LSI_INS_BLK_SCSIP_MSG_IN  (BIT24 | BIT25 | BIT26)
> > +
> > +#define LSI_INS_IO_OPC_SEL        0x00000000
> > +#define LSI_INS_IO_OPC_WAIT_RESEL BIT28
> > +
> > +#define LSI_INS_TC_CP             BIT17
> > +#define LSI_INS_TC_JMP            BIT19
> > +#define LSI_INS_TC_RA             BIT23
> > +
> > +#define LSI_INS_TC_OPC_JMP        0x00000000
> > +#define LSI_INS_TC_OPC_INT        (BIT27 | BIT28)
> > +
> > +#define LSI_INS_TC_SCSIP_DAT_OUT  0x00000000
> > +#define LSI_INS_TC_SCSIP_MSG_IN   (BIT24 | BIT25 | BIT26)
> > +
> >  #endif // _LSI_SCSI_H_
> > diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> > index b3a88cc7119b..d5fe1d4ab3b8 100644
> > --- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
> > +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> > @@ -43,6 +43,42 @@ Out8 (
> >                            );
> >  }
> >  
> > +STATIC
> > +EFI_STATUS
> > +Out32 (
> > +  IN LSI_SCSI_DEV       *Dev,
> > +  IN UINT32             Addr,
> > +  IN UINT32             Data
> > +  )
> > +{
> > +  return Dev->PciIo->Io.Write (
> > +                          Dev->PciIo,
> > +                          EfiPciIoWidthUint32,
> > +                          PCI_BAR_IDX0,
> > +                          Addr,
> > +                          1,
> > +                          &Data
> > +                          );
> > +}
> > +
> > +STATIC
> > +EFI_STATUS
> > +In8 (
> > +  IN  LSI_SCSI_DEV *Dev,
> > +  IN  UINT32       Addr,
> > +  OUT UINT8        *Data
> > +  )
> > +{
> > +  return Dev->PciIo->Io.Read (
> > +                          Dev->PciIo,
> > +                          EfiPciIoWidthUint8,
> > +                          PCI_BAR_IDX0,
> > +                          Addr,
> > +                          1,
> > +                          Data
> > +                          );
> > +}
> > +
> >  STATIC
> >  EFI_STATUS
> >  LsiScsiReset (
> > @@ -141,6 +177,303 @@ LsiScsiCheckRequest (
> >    return EFI_SUCCESS;
> >  }
> >  
> > +/**
> > +
> > +  Interpret the request packet from the Extended SCSI Pass Thru Protocol and
> > +  compose the script to submit the command and data to the controller.
> > +
> > +  @param[in] Dev          The LSI 53C895A SCSI device the packet targets.
> > +
> > +  @param[in] Target       The SCSI target controlled by the LSI 53C895A SCSI
> > +                          device.
> > +
> > +  @param[in] Lun          The Logical Unit Number under the SCSI target.
> > +
> > +  @param[in out] Packet   The Extended SCSI Pass Thru Protocol packet.
> > +
> > +
> > +  @retval EFI_SUCCESS  The Extended SCSI Pass Thru Protocol packet was valid.
> > +
> > +  @return              Otherwise, invalid or unsupported parameters were
> > +                       detected. Status codes are meant for direct forwarding
> > +                       by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()
> > +                       implementation.
> > +
> > + **/
> > +STATIC
> > +EFI_STATUS
> > +LsiScsiProcessRequest (
> > +  IN LSI_SCSI_DEV                                   *Dev,
> > +  IN UINT8                                          Target,
> > +  IN UINT64                                         Lun,
> > +  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
> > +  )
> > +{
> > +  EFI_STATUS Status;
> > +  UINT32     *Script;
> > +  UINT8      *Cdb;
> > +  UINT8      *MsgOut;
> > +  UINT8      *MsgIn;
> > +  UINT8      *ScsiStatus;
> > +  UINT8      *Data;
> > +  UINT8      DStat;
> > +  UINT8      SIst0;
> > +  UINT8      SIst1;
> > +
> > +  Script      = Dev->Dma->Script;
> > +  Cdb         = Dev->Dma->Cdb;
> > +  Data        = Dev->Dma->Data;
> > +  MsgIn       = Dev->Dma->MsgIn;
> > +  MsgOut      = &Dev->Dma->MsgOut;
> > +  ScsiStatus  = &Dev->Dma->Status;
> > +
> > +  *ScsiStatus = 0xFF;
> > +
> > +  SetMem (Cdb, sizeof Dev->Dma->Cdb, 0x00);
> > +  CopyMem (Cdb, Packet->Cdb, Packet->CdbLength);
> > +
> > +  //
> > +  // Clean up the DMA buffer for the script.
> > +  //
> > +  SetMem (Script, sizeof Dev->Dma->Script, 0x00);
> > +
> > +  //
> > +  // Compose the script to transfer data between the host and the device.
> > +  //
> > +  // References:
> > +  //   * LSI53C895A PCI to Ultra2 SCSI Controller Version 2.2
> > +  //     - Chapter 5 SCSI SCRIPT Instruction Set
> > +  //   * SEABIOS lsi-scsi driver
> > +  //
> > +  // All instructions used here consist of 2 32bit words. The first word
> > +  // contains the command to execute. The second word is loaded into the
> > +  // DMA SCRIPTS Pointer Save (DSPS) register as either the DMA address
> > +  // for data transmission or the address/offset for the jump command.
> > +  // Some commands, such as the selection of the target, don't need to
> > +  // transfer data through DMA or jump to another instruction, then DSPS
> > +  // has to be zero.
> > +  //
> > +  // There are 3 major parts in this script. The first part (1~3) contains
> > +  // the instructions to select target and LUN and send the SCSI command
> > +  // from the request packet. The second part (4~7) is to handle the
> > +  // potential disconnection and prepare for the data transmission. The
> > +  // instructions in the third part (8~10) transmit the given data and
> > +  // collect the result. Instruction 11 raises the interrupt and marks the
> > +  // end of the script.
> > +  //
> > +
> > +  //
> > +  // 1. Select target.
> > +  //
> > +  *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_SEL | (UINT32)Target << 16;
> > +  *Script++ = 0x00000000;
> > +
> > +  //
> > +  // 2. Select LUN.
> > +  //
> > +  *MsgOut   = 0x80 | (UINT8) Lun; // 0x80: Identify bit
> > +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_OUT |
> > +              (UINT32)sizeof Dev->Dma->MsgOut;
> > +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgOut);
> > +
> > +  //
> > +  // 3. Send the SCSI Command.
> > +  //
> > +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_CMD |
> > +              (UINT32)sizeof Dev->Dma->Cdb;
> > +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, Cdb);
> > +
> > +  //
> > +  // 4. Check whether the current SCSI phase is "Message In" or not
> > +  //    and jump to 7 if it is.
> > +  //    Note: LSI_INS_TC_RA stands for "Relative Address Mode", so the
> > +  //          offset 0x18 in the second word means jumping forward
> > +  //          3 (0x18/8) instructions.
> > +  //
> > +  *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_JMP |
> > +              LSI_INS_TC_SCSIP_MSG_IN | LSI_INS_TC_RA |
> > +              LSI_INS_TC_CP;
> > +  *Script++ = 0x00000018;
> > +
> > +  //
> > +  // 5. Read "Message" from the initiator to trigger reselect.
> > +  //
> > +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
> > +              (UINT32)sizeof Dev->Dma->MsgIn;
> > +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
> > +
> > +  //
> > +  // 6. Wait reselect.
> > +  //
> > +  *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_WAIT_RESEL;
> > +  *Script++ = 0x00000000;
> > +
> > +  //
> > +  // 7. Read "Message" from the initiator again
> > +  //
> > +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
> > +              (UINT32)sizeof Dev->Dma->MsgIn;
> > +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
> > +
> > +  //
> > +  // 8. Set the DMA command for the read/write operations.
> > +  //    Note: Some requests, e.g. "TEST UNIT READY", do not come with
> > +  //          allocated InDataBuffer or OutDataBuffer. We skip the DMA
> > +  //          data command for those requests or this script would fail
> > +  //          with LSI_SIST0_SGE due to the zero data length.
> > +  //
> > +  // LsiScsiCheckRequest() prevents both integer overflows in the command
> > +  // opcodes, and buffer overflows.
> > +  //
> > +  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ &&
> > +      Packet->InTransferLength > 0) {
> > +    ASSERT (Packet->InTransferLength <= sizeof Dev->Dma->Data);
> > +    *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_IN |
> > +                Packet->InTransferLength;
> > +    *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);
> > +  } else if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE &&
> > +             Packet->OutTransferLength > 0) {
> > +    ASSERT (Packet->OutTransferLength <= sizeof Dev->Dma->Data);
> > +    CopyMem (Data, Packet->OutDataBuffer, Packet->OutTransferLength);
> > +    *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_OUT |
> > +                Packet->OutTransferLength;
> > +    *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);
> > +  }
> 
> I understand the explanation, thanks.
> 
> However, we can still improve this code. The following sub-conditions:
> 
>   Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ
> 
> and
> 
>   Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE
> 
> are superfluous. What we care about are
> 
>   Packet->InTransferLength > 0
> 
> and
> 
>   Packet->OutTransferLength > 0
> 
> And the latter (length-based) conditions actually *imply* the former
> (direction-based) conditions, because:
> 
> - LsiScsiCheckRequest() returns EFI_INVALID_PARAMETER if
>   DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
> 
> - LsiScsiCheckRequest() returns EFI_UNSUPPORTED if
>   DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL
> 
> - LsiScsiCheckRequest() returns EFI_INVALID_PARAMETER if
>   InTransferLength > 0, but
>   DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE
> 
> - LsiScsiCheckRequest() returns EFI_INVALID_PARAMETER if
>   OutTransferLength > 0, but
>   DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ
> 
> This means that (InTransferLength > 0) guarantees
> EFI_EXT_SCSI_DATA_DIRECTION_READ, and (OutTransferLength > 0) guarantees
> EFI_EXT_SCSI_DATA_DIRECTION_WRITE.
> 
> (1) Therefore I suggest moving the respective sub-conditions from the
> "if" statements into the dependent blocks, as assertions:
> 
>   if (Packet->InTransferLength > 0) {
>     ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ);
>     ASSERT (Packet->InTransferLength <= sizeof Dev->Dma->Data);
>     ...
>   } else if (Packet->OutTransferLength > 0) {
>     ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE);
>     ASSERT (Packet->OutTransferLength <= sizeof Dev->Dma->Data);
>     ...
>   }
> 
Thanks for the suggestion. This makes the if statements easier to read.
Will modify them in v3.

> > +
> > +  //
> > +  // 9. Get the SCSI status.
> > +  //
> > +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_STAT |
> > +              (UINT32)sizeof Dev->Dma->Status;
> > +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, Status);
> > +
> > +  //
> > +  // 10. Get the SCSI message.
> > +  //
> > +  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
> > +              (UINT32)sizeof Dev->Dma->MsgIn;
> > +  *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
> > +
> > +  //
> > +  // 11. Raise the interrupt to end the script.
> > +  //
> > +  *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_INT |
> > +              LSI_INS_TC_SCSIP_DAT_OUT | LSI_INS_TC_JMP;
> > +  *Script++ = 0x00000000;
> > +
> > +  //
> > +  // Make sure the size of the script doesn't exceed the buffer.
> > +  //
> > +  ASSERT (Script <= Dev->Dma->Script + ARRAY_SIZE (Dev->Dma->Script));
> > +
> > +  //
> > +  // The controller starts to execute the script once the DMA Script
> > +  // Pointer (DSP) register is set.
> > +  //
> > +  Status = Out32 (Dev, LSI_REG_DSP, LSI_SCSI_DMA_ADDR (Dev, Script));
> > +  if (EFI_ERROR (Status)) {
> > +    goto Error;
> > +  }
> > +
> > +  //
> > +  // Poll the device registers (DSTAT, SIST0, and SIST1) until the SIR
> > +  // bit sets.
> > +  //
> > +  for(;;) {
> > +    Status = In8 (Dev, LSI_REG_DSTAT, &DStat);
> > +    if (EFI_ERROR (Status)) {
> > +      goto Error;
> > +    }
> > +    Status = In8 (Dev, LSI_REG_SIST0, &SIst0);
> > +    if (EFI_ERROR (Status)) {
> > +      goto Error;
> > +    }
> > +    Status = In8 (Dev, LSI_REG_SIST1, &SIst1);
> > +    if (EFI_ERROR (Status)) {
> > +      goto Error;
> > +    }
> > +
> > +    if (SIst0 != 0 || SIst1 != 0) {
> > +      goto Error;
> > +    }
> > +
> > +    //
> > +    // Check the SIR (SCRIPTS Interrupt Instruction Received) bit.
> > +    //
> > +    if (DStat & LSI_DSTAT_SIR) {
> > +      break;
> > +    }
> > +
> > +    gBS->Stall (Dev->StallPerPollUsec);
> > +  }
> > +
> > +  //
> > +  // Check if everything is good.
> > +  //   SCSI Message Code 0x00: COMMAND COMPLETE
> > +  //   SCSI Status  Code 0x00: Good
> > +  //
> > +  if (MsgIn[0] != 0 || *ScsiStatus != 0) {
> > +    goto Error;
> > +  }
> > +
> > +  //
> > +  // Copy Data to InDataBuffer if necessary.
> > +  //
> > +  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
> > +    CopyMem (Packet->InDataBuffer, Data, Packet->InTransferLength);
> > +  }
> > +
> > +  //
> > +  // Always set SenseDataLength to 0.
> > +  // The instructions of LSI53C895A doesn't reply sense data. Instead, it
> > +  // relies on the SCSI command, "REQUEST SENSE", to get sense data. We set
> > +  // SenseDataLength to 0 to notify ScsiDiskDxe that there is no sense data
> > +  // written even if this request is processed successfully, so that It will
> > +  // issue "REQUEST SENSE" later to retrieve sense data.
> > +  //
> > +  Packet->SenseDataLength   = 0;
> > +  Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
> > +  Packet->TargetStatus      = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
> > +
> > +  return EFI_SUCCESS;
> > +
> > +Error:
> > +  DEBUG ((DEBUG_VERBOSE, "%a: dstat: %02X, sist0: %02X, sist1: %02X\n",
> > +    __FUNCTION__, DStat, SIst0, SIst1));
> 
> The Error label may be reached without setting some (or even any) of
> DStat, SIst0, SIst1.
> 
> (2) Please set all three of DStat, SIst0, and SIst1 to zero, near the
> top of the function, with explicit assignments (not initialization).
> 
Right. Will set them to zero in v3.

> > +  //
> > +  // Update the request packet to reflect the status.
> > +  //
> > +  if (*ScsiStatus != 0xFF) {
> > +    Packet->TargetStatus    = *ScsiStatus;
> > +  } else {
> > +    Packet->TargetStatus    = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;
> > +  }
> > +
> > +  if (SIst0 & LSI_SIST0_PAR) {
> > +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR;
> > +  } else if (SIst0 & LSI_SIST0_RST) {
> > +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;
> > +  } else if (SIst0 & LSI_SIST0_UDC) {
> > +    //
> > +    // The target device is disconnected unexpectedly. According to UEFI spec,
> > +    // this is TIMEOUT_COMMAND.
> > +    //
> > +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
> > +  } else if (SIst0 & LSI_SIST0_SGE) {
> > +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
> > +  } else if (SIst1 & LSI_SIST1_HTH) {
> > +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
> > +  } else if (SIst1 & LSI_SIST1_GEN) {
> > +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
> > +  } else if (SIst1 & LSI_SIST1_STO) {
> > +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
> > +  } else {
> > +    Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
> > +  }
> 
> According to the UEFI spec, on EFI_DEVICE_ERROR (see below):
> 
>   See HostAdapterStatus, TargetStatus, SenseDataLength, and SenseData in
>   that order for additional status information.
> 
> (3) Therefore, on this error branch, please also set SenseDataLength to
> zero.
> 
Will set SenseDataLength to 0 in v3.

> > +
> > +  return EFI_DEVICE_ERROR;
> > +}
> > +
> >  //
> >  // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
> >  // for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
> > @@ -168,7 +501,7 @@ LsiScsiPassThru (
> >      return Status;
> >    }
> >  
> > -  return EFI_UNSUPPORTED;
> > +  return LsiScsiProcessRequest (Dev, *Target, Lun, Packet);
> >  }
> 
> The LsiScsiPassThru() function can now return EFI_SUCCESS, without
> updating InTransferLength and OutTransferLength.
> 
> But sticking (for now) with EFI_UNSUPPORTED would also be wrong, because
> (according to the UEFI spec) EFI_UNSUPPORTED means "The SCSI Request
> Packet was not sent", and here we *did* talk to the device.
> 
> (4) So please squash the next patch -- "[PATCH v2 11/12]
> OvmfPkg/LsiScsiDxe: Calculate the transferred bytes" -- into this one,
> in the v3 series.
> 
> (The next patch, which handles the transfer lengths, is not large,
> thankfully.)
> 
Since the calculation wasn't in v1, I thought it's easier to review the
change in an extra patch :)
Will squash the patch in v3.

Gary Lin

> For now I'll comment separately under that patch.
> 
> Thanks!
> Laszlo
> 
> >  
> >  EFI_STATUS
> > @@ -474,6 +807,7 @@ LsiScsiControllerStart (
> >      );
> >    Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);
> >    Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);
> > +  Dev->StallPerPollUsec = PcdGet32 (PcdLsiScsiStallPerPollUsec);
> >  
> >    Status = gBS->OpenProtocol (
> >                    ControllerHandle,
> > diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
> > index 05deeed379fe..6ecf523f5a9e 100644
> > --- a/OvmfPkg/LsiScsiDxe/LsiScsi.h
> > +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
> > @@ -13,6 +13,11 @@
> >  #define _LSI_SCSI_DXE_H_
> >  
> >  typedef struct {
> > +  //
> > +  // Allocate 32 UINT32 entries for the script and it's sufficient for
> > +  // 16 instructions.
> > +  //
> > +  UINT32                          Script[32];
> >    //
> >    // The max size of CDB is 32.
> >    //
> > @@ -25,6 +30,18 @@ typedef struct {
> >    //       Count (DBC), a 24-bit register, so the maximum is 0xFFFFFF (16MB-1).
> >    //
> >    UINT8                           Data[SIZE_64KB];
> > +  //
> > +  // For SCSI Message In phase
> > +  //
> > +  UINT8                           MsgIn[2];
> > +  //
> > +  // For SCSI Message Out phase
> > +  //
> > +  UINT8                           MsgOut;
> > +  //
> > +  // For SCSI Status phase
> > +  //
> > +  UINT8                           Status;
> >  } LSI_SCSI_DMA_BUFFER;
> >  
> >  typedef struct {
> > @@ -34,6 +51,7 @@ typedef struct {
> >    EFI_PCI_IO_PROTOCOL             *PciIo;
> >    UINT8                           MaxTarget;
> >    UINT8                           MaxLun;
> > +  UINT32                          StallPerPollUsec;
> >    LSI_SCSI_DMA_BUFFER             *Dma;
> >    EFI_PHYSICAL_ADDRESS            DmaPhysical;
> >    VOID                            *DmaMapping;
> > @@ -46,6 +64,9 @@ typedef struct {
> >  #define LSI_SCSI_FROM_PASS_THRU(PassThruPtr) \
> >    CR (PassThruPtr, LSI_SCSI_DEV, PassThru, LSI_SCSI_DEV_SIGNATURE)
> >  
> > +#define LSI_SCSI_DMA_ADDR(Dev, MemberName) \
> > +  ((UINT32)(Dev->DmaPhysical + OFFSET_OF (LSI_SCSI_DMA_BUFFER, MemberName)))
> > +
> >  
> >  //
> >  // Probe, start and stop functions of this driver, called by the DXE core for
> > diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
> > index 6111449577a8..4c7abcec618f 100644
> > --- a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
> > +++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
> > @@ -41,3 +41,6 @@ [Protocols]
> >  [FixedPcd]
> >    gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit   ## CONSUMES
> >    gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit      ## CONSUMES
> > +
> > +[Pcd]
> > +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiStallPerPollUsec ## CONSUMES
> > diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> > index ca13a3cb11d3..f16c00ad5b99 100644
> > --- a/OvmfPkg/OvmfPkg.dec
> > +++ b/OvmfPkg/OvmfPkg.dec
> > @@ -179,6 +179,9 @@ [PcdsFixedAtBuild]
> >    gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit|7|UINT8|0x3b
> >    gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit|0|UINT8|0x3c
> >  
> > +  ## Microseconds to stall between polling for LsiScsi request result
> > +  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiStallPerPollUsec|5|UINT32|0x3d
> > +
> >    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogBase|0x0|UINT32|0x8
> >    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageEventLogSize|0x0|UINT32|0x9
> >    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize|0x0|UINT32|0xa
> > 
> 


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

* Re: [PATCH v2 11/12] OvmfPkg/LsiScsiDxe: Calculate the transferred bytes
  2020-07-16 18:21   ` Laszlo Ersek
@ 2020-07-17  3:15     ` Gary Lin
  0 siblings, 0 replies; 21+ messages in thread
From: Gary Lin @ 2020-07-17  3:15 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: devel, Jordan Justen, Ard Biesheuvel

On Thu, Jul 16, 2020 at 08:21:46PM +0200, Laszlo Ersek wrote:
> On 07/16/20 09:46, Gary Lin wrote:
> > Calculate the transferred bytes during data phases based on the
> > Cumulative SCSI Byte Count (CSBC) and update
> > InTransferLength/OutTransferLength of the request packet.
> > 
> > Cc: Jordan Justen <jordan.l.justen@intel.com>
> > Cc: Laszlo Ersek <lersek@redhat.com>
> > Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
> > Signed-off-by: Gary Lin <glin@suse.com>
> > ---
> >  OvmfPkg/Include/IndustryStandard/LsiScsi.h |  1 +
> >  OvmfPkg/LsiScsiDxe/LsiScsi.c               | 50 ++++++++++++++++++++++
> >  2 files changed, 51 insertions(+)
> > 
> > diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> > index 9964bd40385c..01d75323cdbc 100644
> > --- a/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> > +++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
> > @@ -25,6 +25,7 @@
> >  #define LSI_REG_DSP               0x2C
> >  #define LSI_REG_SIST0             0x42
> >  #define LSI_REG_SIST1             0x43
> > +#define LSI_REG_CSBC              0xDC
> >  
> >  //
> >  // The status bits for DMA Status (DSTAT)
> > diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> > index d5fe1d4ab3b8..10483ed02bd7 100644
> > --- a/OvmfPkg/LsiScsiDxe/LsiScsi.c
> > +++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
> > @@ -79,6 +79,24 @@ In8 (
> >                            );
> >  }
> >  
> > +STATIC
> > +EFI_STATUS
> > +In32 (
> > +  IN  LSI_SCSI_DEV *Dev,
> > +  IN  UINT32       Addr,
> > +  OUT UINT32       *Data
> > +  )
> > +{
> > +  return Dev->PciIo->Io.Read (
> > +                          Dev->PciIo,
> > +                          EfiPciIoWidthUint32,
> > +                          PCI_BAR_IDX0,
> > +                          Addr,
> > +                          1,
> > +                          Data
> > +                          );
> > +}
> > +
> >  STATIC
> >  EFI_STATUS
> >  LsiScsiReset (
> > @@ -219,6 +237,8 @@ LsiScsiProcessRequest (
> >    UINT8      DStat;
> >    UINT8      SIst0;
> >    UINT8      SIst1;
> > +  UINT32     Csbc;
> > +  UINT32     CsbcBase;
> >  
> >    Script      = Dev->Dma->Script;
> >    Cdb         = Dev->Dma->Cdb;
> > @@ -232,6 +252,18 @@ LsiScsiProcessRequest (
> >    SetMem (Cdb, sizeof Dev->Dma->Cdb, 0x00);
> >    CopyMem (Cdb, Packet->Cdb, Packet->CdbLength);
> >  
> > +  //
> > +  // Fetch the first Cumulative SCSI Byte Count (CSBC).
> > +  //
> > +  // CSBC is a cumulative counter of the actual number of bytes that has been
> 
> (1) typo: s/has been/have been/
> 
Will fix in v3.

> > +  // transferred across the SCSI bus during data phases, i.e. it will not
> 
> (2) typo (I think): s/will not/will not count/
> 
ditto

> > +  // bytes sent in command, status, message in and out phases.
> > +  //
> > +  Status = In32 (Dev, LSI_REG_CSBC, &CsbcBase);
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> 
> (3) IMO, we should not return directly, but jump to the Error label.
> 
Right, the request packet has to be modified on the error status.

> > +  }
> > +
> >    //
> >    // Clean up the DMA buffer for the script.
> >    //
> > @@ -407,6 +439,24 @@ LsiScsiProcessRequest (
> >      gBS->Stall (Dev->StallPerPollUsec);
> >    }
> >  
> > +  //
> > +  // Fetch CSBC again to calculate the transferred bytes and update
> > +  // InTransferLength/OutTransferLength.
> > +  //
> 
> This calculation matters for EFI_SUCCESS. But at this point we cannot
> yet guarantee that we'll return EFI_SUCCESS.
> 
> (4) So I suggest postponing the CSBC re-fetch until after we're past the
> last "goto Error" statement -- that is, just before "Copy Data to
> InDataBuffer if necessary".
> 
I thought InTransferLength/OutTransferLength may matter for the error
path. After checking UEFI spec again, it only matters for EFI_SUCCESS
and EFI_BAD_BUFFER_SIZE. The latter is handled in LsiScsiCheckRequest().
Will move the code down.

> > +  // Note: The number of transferred bytes is bounded by
> > +  //       "sizeof Dev->Dma->Data", so it's safe to subtract CsbcBase
> > +  //       from Csbc.
> > +  //
> 
> It's safe to perform the subtraction, but I think we should extend the
> comment.
> 
> This register seems to be a 4-byte counter. It's not super difficult to
> transfer more than 4GB even in UEFI, and so the counter might wrap around.
> 
> Luckily, when it wraps around, the subtraction will do exactly the right
> thing. (And for that, it is indeed relevant that the max requestable
> transfer size is smaller than (MAX_UINT32+1).)
> 
> Assume
> 
>   Csbc < CsbcBase
> 
> This means (a) the counter has wrapped, and (b) mathematically, the
> difference
> 
>   Csbc - Csbcbase
> 
> is negative.
> 
> Given that we use UINT32 variables here, the resultant value (in C) will
> be (per C standard):
> 
>   (MAX_UINT32 + 1) + (Csbc - Csbcbase)                               [1]
> 
> And that's perfect! Because, what does it mean that "CSBC wraps"? It
> means that the mathematical meaning of the new CSBC value is:
> 
>   ((MAX_UINT32 + 1) + Csbc)
> 
> (It's just a different way to say that bit#32 is set in the mathematical
> value.)
> 
> Consequently, for getting the right difference, we'd have to calculate:
> 
>   ((MAX_UINT32 + 1) + Csbc) - Csbcbase                               [2]
> 
> But that's exactly what the C language *already* gives us, in [1].
> 
> 
> (5) So please append the following sentence to the comment:
> 
>   If the CSBC register wraps around, the correct difference is ensured
>   by the standard C modular arithmetic.
> 
Fair enough. It's always good to have more comments :)

> (6) Furthermore, please dedicate a new variable to the difference:
> 
>   UINT32 Transferred;
> 
>   Transferred = Csbc - CsbcBase;
> 
Ok, it's more readable. Will add it in v3.

> > +  Status = In32 (Dev, LSI_REG_CSBC, &Csbc);
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> 
> (7) Again I think we should jump to the Error label.
> 
Will fix it in v3.

> > +  if (Packet->InTransferLength > 0) {
> > +    Packet->InTransferLength = Csbc - CsbcBase;
> > +  } else if (Packet->OutTransferLength > 0) {
> > +    Packet->OutTransferLength = Csbc - CsbcBase;
> > +  }
> > +
> 
> (8) I'd recommend a sanity check -- it's unlikely that the device will
> blatantly lie, but if it ever happens, we should not let it out.
> 
> We may only ever reduce the transfer length. Thus:
> 
>   if (Packet->InTransferLength > 0) {
>     if (Transferred <= Packet->InTransferLength) {
>       Packet->InTransferLength = Transferred;
>     } else {
>       goto Error;
>     }
>   } else if (Packet->OutTransferLength > 0) {
>     if (Transferred <= Packet->OutTransferLength) {
>       Packet->OutTransferLength = Transferred;
>     } else {
>       goto Error;
>     }
>   }
> 
Thanks! This handles error cases well. Will do it in v3.

Gary Lin

> Thanks,
> Laszlo
> 
> >    //
> >    // Check if everything is good.
> >    //   SCSI Message Code 0x00: COMMAND COMPLETE
> > 
> 


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

end of thread, other threads:[~2020-07-17  3:15 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-07-16  7:45 [PATCH v2 00/12] Introduce LsiScsi driver to OvmfPkg Gary Lin
2020-07-16  7:45 ` [PATCH v2 01/12] OvmfPkg/LsiScsiDxe: Create the empty driver Gary Lin
2020-07-16  7:45 ` [PATCH v2 02/12] OvmfPkg/LsiScsiDxe: Install the skeleton of driver binding Gary Lin
2020-07-16  7:45 ` [PATCH v2 03/12] OvmfPkg/LsiScsiDxe: Report the name of the driver Gary Lin
2020-07-16  7:45 ` [PATCH v2 04/12] OvmfPkg/LsiScsiDxe: Probe PCI devices and look for LsiScsi Gary Lin
2020-07-16  7:46 ` [PATCH v2 05/12] OvmfPkg/LsiScsiDxe: Install stubbed EXT_SCSI_PASS_THRU Gary Lin
2020-07-16  7:46 ` [PATCH v2 06/12] OvmfPkg/LsiScsiDxe: Report Targets and LUNs Gary Lin
2020-07-16 15:04   ` Laszlo Ersek
2020-07-16 16:19     ` Laszlo Ersek
2020-07-16  7:46 ` [PATCH v2 07/12] OvmfPkg/LsiScsiDxe: Open PciIo protocol and initialize the device Gary Lin
2020-07-16 16:07   ` Laszlo Ersek
2020-07-16  7:46 ` [PATCH v2 08/12] OvmfPkg/LsiScsiDxe: Map DMA buffer Gary Lin
2020-07-16 16:11   ` Laszlo Ersek
2020-07-16  7:46 ` [PATCH v2 09/12] OvmfPkg/LsiScsiDxe: Examine the incoming SCSI Request Packet Gary Lin
2020-07-16  7:46 ` [PATCH v2 10/12] OvmfPkg/LsiScsiDxe: Process the " Gary Lin
2020-07-16 17:37   ` Laszlo Ersek
2020-07-17  2:28     ` Gary Lin
2020-07-16  7:46 ` [PATCH v2 11/12] OvmfPkg/LsiScsiDxe: Calculate the transferred bytes Gary Lin
2020-07-16 18:21   ` Laszlo Ersek
2020-07-17  3:15     ` Gary Lin
2020-07-16  7:46 ` [PATCH v2 12/12] Maintainers.txt: Add Gary Lin as the reviewer for LsiScsi driver Gary Lin

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