diff options
author | Nikita Leshenko <nikita.leshchenko@oracle.com> | 2020-05-05 00:06:05 +0300 |
---|---|---|
committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2020-05-05 20:43:02 +0000 |
commit | 81cada9892cc4bf3725009c5fb836115da10b1c8 (patch) | |
tree | 6340acef4a60a5e094d158034a22ff7f2b82636c /OvmfPkg/MptScsiDxe | |
parent | ecdbdba636b6bac706641ca47aa973193079a3cc (diff) | |
download | edk2-81cada9892cc4bf3725009c5fb836115da10b1c8.zip edk2-81cada9892cc4bf3725009c5fb836115da10b1c8.tar.gz edk2-81cada9892cc4bf3725009c5fb836115da10b1c8.tar.bz2 |
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.c | 198 |
1 files changed, 197 insertions, 1 deletions
diff --git a/OvmfPkg/MptScsiDxe/MptScsi.c b/OvmfPkg/MptScsiDxe/MptScsi.c index 289bd9f..2cc69b8 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,
|