From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsi.c | 1210 +++++++++++++++++++++++++++ roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsi.h | 202 +++++ roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf | 46 + 3 files changed, 1458 insertions(+) create mode 100644 roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsi.c create mode 100644 roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsi.h create mode 100644 roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf (limited to 'roms/edk2/OvmfPkg/LsiScsiDxe') diff --git a/roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsi.c b/roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsi.c new file mode 100644 index 000000000..ed5fc3bfd --- /dev/null +++ b/roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsi.c @@ -0,0 +1,1210 @@ +/** @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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +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 ( + 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 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; + UINT32 Csbc; + UINT32 CsbcBase; + UINT32 Transferred; + + 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; + + DStat = 0; + SIst0 = 0; + SIst1 = 0; + + 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 have been + // transferred across the SCSI bus during data phases, i.e. it will not + // count bytes sent in command, status, message in and out phases. + // + Status = In32 (Dev, LSI_REG_CSBC, &CsbcBase); + if (EFI_ERROR (Status)) { + goto Error; + } + + // + // 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->InTransferLength > 0) { + ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ); + 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->OutTransferLength > 0) { + ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE); + 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; + } + + // + // 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. If the CSBC register wraps around, the correct + // difference is ensured by the standard C modular arithmetic. + // + Status = In32 (Dev, LSI_REG_CSBC, &Csbc); + if (EFI_ERROR (Status)) { + goto Error; + } + + Transferred = Csbc - CsbcBase; + 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; + } + } + + // + // 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 don'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; + } + + // + // SenseData may be used to inspect the error. Since we don't set sense data, + // SenseDataLength has to be 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; + } + + return LsiScsiProcessRequest (Dev, *Target, Lun, Packet); +} + +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; + } + + Target = *TargetPointer; + ZeroMem (Target, TARGET_MAX_BYTES); + CopyMem (Target, &ScsiDevicePath->Pun, sizeof 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; + + STATIC_ASSERT ( + FixedPcdGet8 (PcdLsiScsiMaxTargetLimit) < 8, + "LSI 53C895A supports targets [0..7]" + ); + STATIC_ASSERT ( + FixedPcdGet8 (PcdLsiScsiMaxLunLimit) < 128, + "LSI 53C895A supports LUNs [0..127]" + ); + 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; + } + + // + // 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/roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsi.h b/roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsi.h new file mode 100644 index 000000000..6ecf523f5 --- /dev/null +++ b/roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsi.h @@ -0,0 +1,202 @@ +/** @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. 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]; + // + // 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(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 +// + +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/roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf b/roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf new file mode 100644 index 000000000..4c7abcec6 --- /dev/null +++ b/roms/edk2/OvmfPkg/LsiScsiDxe/LsiScsiDxe.inf @@ -0,0 +1,46 @@ +## @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 + LsiScsi.h + +[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 -- cgit