diff --git a/OvmfPkg/Include/IndustryStandard/LsiScsi.h b/OvmfPkg/Include/IndustryStandard/LsiScsi.h index c09e864a1f..185e553c8e 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 1727792406..a9c107c04e 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 6c6ed25f1c..8c2acff6e8 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;