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>
This commit is contained in:
Nikita Leshenko
2020-05-05 00:06:05 +03:00
committed by mergify[bot]
parent ecdbdba636
commit 81cada9892
2 changed files with 325 additions and 1 deletions

View File

@@ -44,6 +44,192 @@ typedef struct {
#define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
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,