summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/MptScsiDxe
diff options
context:
space:
mode:
authorNikita Leshenko <nikita.leshchenko@oracle.com>2020-05-05 00:06:05 +0300
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2020-05-05 20:43:02 +0000
commit81cada9892cc4bf3725009c5fb836115da10b1c8 (patch)
tree6340acef4a60a5e094d158034a22ff7f2b82636c /OvmfPkg/MptScsiDxe
parentecdbdba636b6bac706641ca47aa973193079a3cc (diff)
downloadedk2-81cada9892cc4bf3725009c5fb836115da10b1c8.tar.gz
edk2-81cada9892cc4bf3725009c5fb836115da10b1c8.tar.bz2
edk2-81cada9892cc4bf3725009c5fb836115da10b1c8.zip
OvmfPkg/MptScsiDxe: Initialize hardware
Reset and send the IO controller initialization request. The reply is read back to complete the doorbell function but it isn't useful to us because it doesn't contain relevant data or status codes. See "LSI53C1030 PCI-X to Dual Channel Ultra320 SCSI Multifunction Controller" technical manual for more information. Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2390 Signed-off-by: Nikita Leshenko <nikita.leshchenko@oracle.com> Message-Id: <20200504210607.144434-11-nikita.leshchenko@oracle.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Diffstat (limited to 'OvmfPkg/MptScsiDxe')
-rw-r--r--OvmfPkg/MptScsiDxe/MptScsi.c198
1 files changed, 197 insertions, 1 deletions
diff --git a/OvmfPkg/MptScsiDxe/MptScsi.c b/OvmfPkg/MptScsiDxe/MptScsi.c
index 289bd9fc37..2cc69b88da 100644
--- a/OvmfPkg/MptScsiDxe/MptScsi.c
+++ b/OvmfPkg/MptScsiDxe/MptScsi.c
@@ -45,6 +45,192 @@ typedef struct {
CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)
//
+// Hardware functions
+//
+
+STATIC
+EFI_STATUS
+Out32 (
+ IN MPT_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
+In32 (
+ IN MPT_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
+MptDoorbell (
+ IN MPT_SCSI_DEV *Dev,
+ IN UINT8 DoorbellFunc,
+ IN UINT8 DoorbellArg
+ )
+{
+ return Out32 (
+ Dev,
+ MPT_REG_DOORBELL,
+ (((UINT32)DoorbellFunc) << 24) | (DoorbellArg << 16)
+ );
+}
+
+STATIC
+EFI_STATUS
+MptScsiReset (
+ IN MPT_SCSI_DEV *Dev
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Reset hardware
+ //
+ Status = MptDoorbell (Dev, MPT_DOORBELL_RESET, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Mask interrupts
+ //
+ Status = Out32 (Dev, MPT_REG_IMASK, MPT_IMASK_DOORBELL | MPT_IMASK_REPLY);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Clear interrupt status
+ //
+ Status = Out32 (Dev, MPT_REG_ISTATUS, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MptScsiInit (
+ IN MPT_SCSI_DEV *Dev
+ )
+{
+ EFI_STATUS Status;
+ union {
+ MPT_IO_CONTROLLER_INIT_REQUEST Data;
+ UINT32 Uint32;
+ } AlignedReq;
+ MPT_IO_CONTROLLER_INIT_REQUEST *Req;
+ MPT_IO_CONTROLLER_INIT_REPLY Reply;
+ UINT8 *ReplyBytes;
+ UINT32 ReplyWord;
+
+ Req = &AlignedReq.Data;
+
+ Status = MptScsiReset (Dev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (Req, sizeof (*Req));
+ ZeroMem (&Reply, sizeof (Reply));
+ Req->WhoInit = MPT_IOC_WHOINIT_ROM_BIOS;
+ Req->Function = MPT_MESSAGE_HDR_FUNCTION_IOC_INIT;
+ STATIC_ASSERT (
+ FixedPcdGet8 (PcdMptScsiMaxTargetLimit) < 255,
+ "Req supports 255 targets only (max target is 254)"
+ );
+ Req->MaxDevices = Dev->MaxTarget + 1;
+ Req->MaxBuses = 1;
+
+ //
+ // Send controller init through doorbell
+ //
+ STATIC_ASSERT (
+ sizeof (*Req) % sizeof (UINT32) == 0,
+ "Req must be multiple of UINT32"
+ );
+ STATIC_ASSERT (
+ sizeof (*Req) / sizeof (UINT32) <= MAX_UINT8,
+ "Req must fit in MAX_UINT8 Dwords"
+ );
+ Status = MptDoorbell (
+ Dev,
+ MPT_DOORBELL_HANDSHAKE,
+ (UINT8)(sizeof (*Req) / sizeof (UINT32))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = Dev->PciIo->Io.Write (
+ Dev->PciIo,
+ EfiPciIoWidthFifoUint32,
+ PCI_BAR_IDX0,
+ MPT_REG_DOORBELL,
+ sizeof (*Req) / sizeof (UINT32),
+ Req
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Read reply through doorbell
+ // Each 32bit (Dword) read produces 16bit (Word) of data
+ //
+ // The reply is read back to complete the doorbell function but it
+ // isn't useful because it doesn't contain relevant data or status
+ // codes.
+ //
+ STATIC_ASSERT (
+ sizeof (Reply) % sizeof (UINT16) == 0,
+ "Reply must be multiple of UINT16"
+ );
+ ReplyBytes = (UINT8 *)&Reply;
+ while (ReplyBytes != (UINT8 *)(&Reply + 1)) {
+ Status = In32 (Dev, MPT_REG_DOORBELL, &ReplyWord);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CopyMem (ReplyBytes, &ReplyWord, sizeof (UINT16));
+ ReplyBytes += sizeof (UINT16);
+ }
+
+ //
+ // Clear interrupts generated by doorbell reply
+ //
+ Status = Out32 (Dev, MPT_REG_ISTATUS, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
// Ext SCSI Pass Thru
//
@@ -383,6 +569,11 @@ MptScsiControllerStart (
));
}
+ Status = MptScsiInit (Dev);
+ if (EFI_ERROR (Status)) {
+ goto RestoreAttributes;
+ }
+
//
// Host adapter channel, doesn't exist
//
@@ -407,11 +598,14 @@ MptScsiControllerStart (
&Dev->PassThru
);
if (EFI_ERROR (Status)) {
- goto RestoreAttributes;
+ goto UninitDev;
}
return EFI_SUCCESS;
+UninitDev:
+ MptScsiReset (Dev);
+
RestoreAttributes:
Dev->PciIo->Attributes (
Dev->PciIo,
@@ -471,6 +665,8 @@ MptScsiControllerStop (
return Status;
}
+ MptScsiReset (Dev);
+
Dev->PciIo->Attributes (
Dev->PciIo,
EfiPciIoAttributeOperationSet,