This commit introduces the driver for LSI 53C895A SCSI Controller which,
so that OVMF can access the devices attached to the emulated "lsi" SCSI
controller.

Cc: Jordan Justen <jordan.l.jus...@intel.com>
Cc: Laszlo Ersek <ler...@redhat.com>
Cc: Ard Biesheuvel <ard.biesheu...@arm.com>
Signed-off-by: Gary Lin <g...@suse.com>
---
Although lsi is now considered obsolete in QEMU, I wrote this driver
mainly for learning the UEFI SCSI driver and ... FUN! The majority of
the code is actually borrowed from VirtioScsci and MptScsi, and I mainly
focus on LsiScsiPassThru().

If it's fine to add this driver into OvmfPkg, I'll start to split this
patch into smaller pieces to make it easier to review.
 
---
 OvmfPkg/Include/IndustryStandard/LsiScsi.h |   80 ++
 OvmfPkg/LsiScsiDxe/LsiScsi.c               | 1120 ++++++++++++++++++++
 OvmfPkg/LsiScsiDxe/LsiScsi.h               |  199 ++++
 OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf          |   45 +
 OvmfPkg/OvmfPkg.dec                        |    9 +
 OvmfPkg/OvmfPkgIa32.dsc                    |    4 +
 OvmfPkg/OvmfPkgIa32.fdf                    |    3 +
 OvmfPkg/OvmfPkgIa32X64.dsc                 |    4 +
 OvmfPkg/OvmfPkgIa32X64.fdf                 |    3 +
 OvmfPkg/OvmfPkgX64.dsc                     |    4 +
 OvmfPkg/OvmfPkgX64.fdf                     |    3 +
 11 files changed, 1474 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

diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h 
b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
new file mode 100644
index 000000000000..cbf049c18310
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/LsiScsi.h
@@ -0,0 +1,80 @@
+/** @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

+

+//

+// 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 DMA Status (DSTAT)

+//

+#define LSI_DSTAT_IID             0x01

+#define LSI_DSTAT_R               0x02

+#define LSI_DSTAT_SIR             0x04

+#define LSI_DSTAT_SSI             0x08

+#define LSI_DSTAT_ABRT            0x10

+#define LSI_DSTAT_BF              0x20

+#define LSI_DSTAT_MDPE            0x40

+#define LSI_DSTAT_DFE             0x80

+

+//

+// The status bits for Interrupt Status Zero (ISTAT0)

+//

+#define LSI_ISTAT0_DIP            0x01

+#define LSI_ISTAT0_SIP            0x02

+#define LSI_ISTAT0_INTF           0x04

+#define LSI_ISTAT0_CON            0x08

+#define LSI_ISTAT0_SEM            0x10

+#define LSI_ISTAT0_SIGP           0x20

+#define LSI_ISTAT0_SRST           0x40

+#define LSI_ISTAT0_ABRT           0x80

+

+//

+// LSI 53C895A Script Instructions

+//

+#define LSI_INS_TYPE_BLK          0x00000000

+#define LSI_INS_TYPE_IO           0x40000000

+#define LSI_INS_TYPE_TC           0x80000000

+

+#define LSI_INS_BLK_SCSIP_DAT_OUT 0x00000000

+#define LSI_INS_BLK_SCSIP_DAT_IN  0x01000000

+#define LSI_INS_BLK_SCSIP_CMD     0x02000000

+#define LSI_INS_BLK_SCSIP_STAT    0x03000000

+#define LSI_INS_BLK_SCSIP_MSG_OUT 0x06000000

+#define LSI_INS_BLK_SCSIP_MSG_IN  0x07000000

+

+#define LSI_INS_IO_OPC_SEL        0x00000000

+#define LSI_INS_IO_OPC_WAIT_RESEL 0x10000000

+

+#define LSI_INS_TC_CP             0x00020000

+#define LSI_INS_TC_JMP            0x00080000

+#define LSI_INS_TC_RA             0x00800000

+

+#define LSI_INS_TC_OPC_JMP        0x00000000

+#define LSI_INS_TC_OPC_INT        0x18000000

+

+#define LSI_INS_TC_SCSIP_DAT_OUT  0x00000000

+#define LSI_INS_TC_SCSIP_MSG_IN   0x07000000

+

+#endif // _LSI_SCSI_H_

diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.c b/OvmfPkg/LsiScsiDxe/LsiScsi.c
new file mode 100644
index 000000000000..a226a0e789da
--- /dev/null
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.c
@@ -0,0 +1,1120 @@
+/** @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 <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/PcdLib.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"

+

+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

+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 (

+  IN LSI_SCSI_DEV *Dev

+  )

+{

+  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;

+}

+

+/**

+

+  Interpret the request packet from the Extended SCSI Pass Thru Protocol and

+  compose the script to submit the command and data to the contorller.

+

+  @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);

+

+  //

+  // Compose the script to transfer data between the host and the device.

+  //

+  // Reference:

+  //   LSI53C895A PCI to Ultra2 SCSI Controller Version 2.2

+  //   - Chapter 5 SCSI SCRIPT Instruction Set

+  //

+  // 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.

+  //

+  // The controller starts to execute the script once the DMA Script

+  // Pointer (DSP) register is set.

+  //

+  SetMem (Script, sizeof Dev->Dma->Script, 0x00);

+

+  //

+  // Select target.

+  //

+  *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_SEL | (UINT32)Target << 16;

+  *Script++ = 0x00000000;

+

+  //

+  // Select lun.

+  //

+  *MsgOut   = 0x80 | (UINT8) Lun; // 0x80: Identify bit

+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_OUT | \

+              sizeof Dev->Dma->MsgOut;

+  *Script++ = LSI_SCSI_DMA_ADDR_LOW (Dev, MsgOut);

+

+  //

+  // Send the SCSI Command.

+  //

+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_CMD | \

+              sizeof Dev->Dma->Cdb;

+  *Script++ = LSI_SCSI_DMA_ADDR_LOW (Dev, Cdb);

+

+  //

+  // Handle disconnect

+  //

+  // Check whether the current SCSI phase is "Message In" or not.

+  // If not, try to enter the "Message In" phase to reconnect to the

+  // device.

+  //

+  *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;

+  //

+  // Read "Message" from the initiator to trigger reselect.

+  //

+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN | \

+              sizeof Dev->Dma->MsgIn;

+  *Script++ = LSI_SCSI_DMA_ADDR_LOW (Dev, MsgIn);

+  //

+  // Wait reselect.

+  //

+  *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_WAIT_RESEL;

+  *Script++ = 0x00000000;

+  //

+  // Read "Message" from the initiator again.

+  //

+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN | \

+              sizeof Dev->Dma->MsgIn;

+  *Script++ = LSI_SCSI_DMA_ADDR_LOW (Dev, MsgIn);

+

+  //

+  // Set the DMA command for the read/write operations.

+  //

+  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ &&

+      Packet->InTransferLength > 0) {

+    *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_IN | \

+                Packet->InTransferLength;

+    *Script++ = LSI_SCSI_DMA_ADDR_LOW (Dev, Data);

+  } else if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE &&

+             Packet->OutTransferLength > 0) {

+    // LsiScsiCheckRequest() guarantees that OutTransferLength is no

+    // larger than sizeof Dev->Dma->Data, so we can safely copy the

+    // the data to 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_LOW (Dev, Data);

+  }

+

+  //

+  // Get the SCSI status.

+  //

+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_STAT | \

+              sizeof Dev->Dma->Status;

+  *Script++ = LSI_SCSI_DMA_ADDR_LOW (Dev, Status);

+

+  //

+  // Get the SCSI message.

+  //

+  *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN | \

+              sizeof Dev->Dma->MsgIn;

+  *Script++ = LSI_SCSI_DMA_ADDR_LOW (Dev, MsgIn);

+

+  //

+  // 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 script doesn't exceed the size.

+  //

+  ASSERT (Script < Dev->Dma->Script + sizeof Dev->Dma->Script);

+

+  //

+  // Execute the script.

+  //

+  Status = Out32 (Dev, LSI_REG_DSP, LSI_SCSI_DMA_ADDR_LOW(Dev, Script));

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  //

+  // 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) {

+    //

+    // Copy Data to InDataBuffer if necessary.

+    //

+    if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {

+      CopyMem (Packet->InDataBuffer, Data, Packet->InTransferLength);

+    }

+

+    //

+    // The controller doesn't return sense data when replying "TEST UNIT 
READY",

+    // so we have to set SenseDataLength to 0 to notify ScsiIo to issue

+    // "REQUEST SENSE" for the sense data.

+    //

+    if (Cdb[0] == 0x00) {

+      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;

+  }

+  Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;

+  Packet->InTransferLength  = 0;

+  Packet->OutTransferLength = 0;

+  Packet->SenseDataLength   = 0;

+

+  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,

+// 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   Status;

+  LSI_SCSI_DEV *Dev;

+

+  Dev = LSI_SCSI_FROM_PASS_THRU (This);

+  Status = LsiScsiCheckRequest (Dev, *Target, Lun, Packet);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Status = LsiScsiProcessRequest (Dev, *Target, Lun, Packet);

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+LsiScsiGetNextTargetLun (

+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,

+  IN OUT UINT8                       **TargetPointer,

+  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;

+}

+

+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

+  )

+{

+  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

+EFIAPI

+LsiScsiGetTargetLun (

+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,

+  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,

+  OUT UINT8                           **TargetPointer,

+  OUT UINT64                          *Lun

+  )

+{

+  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;

+  }

+

+  //

+  // This device support 8 targets only, so it's enough to set the LSB

+  // of Target.

+  //

+  Target = *TargetPointer;

+  *Target = (UINT8)ScsiDevicePath->Pun;

+  *Lun = ScsiDevicePath->Lun;

+

+  return EFI_SUCCESS;

+}

+

+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

+  )

+{

+  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;

+}

+

+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.

+//

+// 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          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

+EFIAPI

+LsiScsiControllerStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL *This,

+  IN EFI_HANDLE                  ControllerHandle,

+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL

+  )

+{

+  EFI_STATUS           Status;

+  LSI_SCSI_DEV         *Dev;

+  UINTN                Pages;

+  UINTN                BytesMapped;

+

+  Dev = AllocateZeroPool (sizeof (*Dev));

+  if (Dev == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  Dev->Signature = LSI_SCSI_DEV_SIGNATURE;

+

+  Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);

+  Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);

+  Dev->StallPerPollUsec = PcdGet32 (PcdLsiScsiStallPerPollUsec);

+

+  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;

+  }

+

+  //

+  // Signal device supports 64-bit DMA addresses

+  //

+  Status = Dev->PciIo->Attributes (

+                         Dev->PciIo,

+                         EfiPciIoAttributeOperationEnable,

+                         EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,

+                         NULL

+                         );

+  if (EFI_ERROR (Status)) {

+    //

+    // Warn user that device will only be using 32-bit DMA addresses.

+    //

+    // Note that this does not prevent the device/driver from working

+    // and therefore we only warn and continue as usual.

+    //

+    DEBUG ((

+      DEBUG_WARN,

+      "%a: failed to enable 64-bit DMA addresses\n",

+      __FUNCTION__

+      ));

+  }

+

+  //

+  // 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,

+                  &LsiScsiExitBoot,

+                  Dev,

+                  &Dev->ExitBoot

+                  );

+  if (EFI_ERROR (Status)) {

+    goto UninitDev;

+  }

+

+  //

+  // 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 CloseExitBoot;

+  }

+

+  return EFI_SUCCESS;

+

+CloseExitBoot:

+  gBS->CloseEvent (Dev->ExitBoot);

+

+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,

+                EfiPciIoAttributeOperationSet,

+                Dev->OrigPciAttrs,

+                NULL

+                );

+

+CloseProtocol:

+  gBS->CloseProtocol (

+         ControllerHandle,

+         &gEfiPciIoProtocolGuid,

+         This->DriverBindingHandle,

+         ControllerHandle

+         );

+

+FreePool:

+  FreePool (Dev);

+

+  return Status;

+}

+

+EFI_STATUS

+EFIAPI

+LsiScsiControllerStop (

+  IN EFI_DRIVER_BINDING_PROTOCOL *This,

+  IN EFI_HANDLE                  ControllerHandle,

+  IN UINTN                       NumberOfChildren,

+  IN EFI_HANDLE                  *ChildHandleBuffer

+  )

+{

+  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;

+  }

+

+  gBS->CloseEvent (Dev->ExitBoot);

+

+  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,

+                Dev->OrigPciAttrs,

+                NULL

+                );

+

+  gBS->CloseProtocol (

+         ControllerHandle,

+         &gEfiPciIoProtocolGuid,

+         This->DriverBindingHandle,

+         ControllerHandle

+         );

+

+  FreePool (Dev);

+

+  return Status;

+}

+

+//

+// 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

+};

+

+

+//

+// 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

+//

+EFI_STATUS

+EFIAPI

+LsiScsiEntryPoint (

+  IN EFI_HANDLE       ImageHandle,

+  IN EFI_SYSTEM_TABLE *SystemTable

+  )

+{

+  return EfiLibInstallDriverBindingComponentName2 (

+           ImageHandle,

+           SystemTable,

+           &gDriverBinding,

+           ImageHandle, // The handle to install onto

+           &gComponentName,

+           &gComponentName2

+           );

+}

diff --git a/OvmfPkg/LsiScsiDxe/LsiScsi.h b/OvmfPkg/LsiScsiDxe/LsiScsi.h
new file mode 100644
index 000000000000..1a16ef9f7795
--- /dev/null
+++ b/OvmfPkg/LsiScsiDxe/LsiScsi.h
@@ -0,0 +1,199 @@
+/** @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_

+

+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.

+  //

+  UINT8                           Cdb[32];

+  //

+  // Allocate 64KB for read/write buffer.

+  //

+  UINT8                           Data[0x10000];

+  //

+  // 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 {

+  UINT32                          Signature;

+  UINT64                          OrigPciAttrs;

+  EFI_EVENT                       ExitBoot;

+  EFI_PCI_IO_PROTOCOL             *PciIo;

+  UINT8                           MaxTarget;

+  UINT8                           MaxLun;

+  UINT32                          StallPerPollUsec;

+  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;

+

+#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)

+

+#define LSI_SCSI_DMA_ADDR_LOW(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

+// 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

+//

+

+STATIC

+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

+  );

+

+

+//

+// 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

+// 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_

diff --git a/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf 
b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
new file mode 100644
index 000000000000..10f7f0eebd0e
--- /dev/null
+++ b/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf
@@ -0,0 +1,45 @@
+## @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

+  OvmfPkg/OvmfPkg.dec

+

+[LibraryClasses]

+  BaseLib

+  BaseMemoryLib

+  DebugLib

+  MemoryAllocationLib

+  PcdLib

+  UefiBootServicesTableLib

+  UefiDriverEntryPoint

+  UefiLib

+

+[Protocols]

+  gEfiExtScsiPassThruProtocolGuid        ## BY_START

+  gEfiPciIoProtocolGuid                  ## TO_START

+

+[FixedPcd]

+  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxTargetLimit   ## CONSUMES

+  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiMaxLunLimit      ## CONSUMES

+

+[Pcd]

+  gUefiOvmfPkgTokenSpaceGuid.PcdLsiScsiStallPerPollUsec ## CONSUMES

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 65bb2bb0eb4c..ddf81f2bbcb8 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -174,6 +174,15 @@ [PcdsFixedAtBuild]
   ## Microseconds to stall between polling for MptScsi request result

   gUefiOvmfPkgTokenSpaceGuid.PcdMptScsiStallPerPollUsec|5|UINT32|0x40

 

+  ## 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

+

+  ## 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

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index d0df9cbbfb2b..ea1940fc354b 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         = TRUE

 

   #

   # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to

@@ -775,6 +776,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 b3ae62fee92b..2cc8cb8053c6 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         = TRUE

 

   #

   # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to

@@ -789,6 +790,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 f7fe75ebf531..2708ce0d2df5 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         = TRUE

 

   #

   # Flash size selection. Setting FD_SIZE_IN_KB on the command line directly to

@@ -785,6 +786,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


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#61210): https://edk2.groups.io/g/devel/message/61210
Mute This Topic: https://groups.io/mt/74836137/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to