From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from aserp2120.oracle.com (aserp2120.oracle.com [141.146.126.78]) by mx.groups.io with SMTP id smtpd.web11.15697.1588626188659946202 for ; Mon, 04 May 2020 14:03:08 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@oracle.com header.s=corp-2020-01-29 header.b=cx6x3fDm; spf=pass (domain: oracle.com, ip: 141.146.126.78, mailfrom: nikita.leshchenko@oracle.com) Received: from pps.filterd (aserp2120.oracle.com [127.0.0.1]) by aserp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 044L35YM080364; Mon, 4 May 2020 21:03:05 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=corp-2020-01-29; bh=Y2b0tM8OfF3FIgnB0ybHcfNvJuCmBu9n39w219+LuoY=; b=cx6x3fDmIP6LvjrJb1UUgPD4osIsLm4ZFrokzIWoLXFX/4TIp3NbtHXinqPIGNSMI/eS 3CjSSBHLVZ+SW0jQ6oHWVTL7jlaiwZCpR3Mqo/LUqdvuMxGBQxlz5HNvRio1b6+kZ22i dr6da/DorgyPull+hQQ2stlTvRFZbOZb3nIoIvHZXixrQMtjyiJewIY3jRTkivfhCrkg wevti928BUhkhgjB/qi4+HAps7r1Ey38c6nUzpAhKNL28rdMWmASgotju9pRlkUjXELQ zrtMslDHipFUyMBn5hwYwNzRsvmfUr0VYKsRfynl4vgS9yktIiGz5v2D9FtwqXhF2NX0 8g== Received: from userp3020.oracle.com (userp3020.oracle.com [156.151.31.79]) by aserp2120.oracle.com with ESMTP id 30s0tm9b4s-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 04 May 2020 21:02:58 +0000 Received: from pps.filterd (userp3020.oracle.com [127.0.0.1]) by userp3020.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 044L2ZFX179493; Mon, 4 May 2020 21:02:58 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by userp3020.oracle.com with ESMTP id 30sjjwubag-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 04 May 2020 21:02:57 +0000 Received: from abhmp0011.oracle.com (abhmp0011.oracle.com [141.146.116.17]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 044L2uJL011408; Mon, 4 May 2020 21:02:57 GMT Received: from spark.ravello.local (/213.57.127.2) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Mon, 04 May 2020 14:02:56 -0700 From: "Nikita Leshenko" To: devel@edk2.groups.io Cc: Nikita Leshenko , liran.alon@oracle.com, aaron.young@oracle.com, Jordan Justen , Laszlo Ersek , Ard Biesheuvel Subject: [PATCH v6 10/12] OvmfPkg/MptScsiDxe: Initialize hardware Date: Tue, 5 May 2020 00:06:05 +0300 Message-Id: <20200504210607.144434-11-nikita.leshchenko@oracle.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200504210607.144434-1-nikita.leshchenko@oracle.com> References: <20200504210607.144434-1-nikita.leshchenko@oracle.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9611 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=0 mlxscore=0 phishscore=0 bulkscore=0 malwarescore=0 spamscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2003020000 definitions=main-2005040164 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9611 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 malwarescore=0 mlxscore=0 priorityscore=1501 lowpriorityscore=0 spamscore=0 suspectscore=0 phishscore=0 clxscore=1015 bulkscore=0 mlxlogscore=999 adultscore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2003020000 definitions=main-2005040164 Content-Transfer-Encoding: 8bit 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 --- .../Include/IndustryStandard/FusionMptScsi.h | 128 +++++++++++ OvmfPkg/MptScsiDxe/MptScsi.c | 198 +++++++++++++++++- 2 files changed, 325 insertions(+), 1 deletion(-) diff --git a/OvmfPkg/Include/IndustryStandard/FusionMptScsi.h b/OvmfPkg/Include/IndustryStandard/FusionMptScsi.h index df9bdc2f0348..655d629d902e 100644 --- a/OvmfPkg/Include/IndustryStandard/FusionMptScsi.h +++ b/OvmfPkg/Include/IndustryStandard/FusionMptScsi.h @@ -20,4 +20,132 @@ #define LSI_SAS1068_PCI_DEVICE_ID 0x0054 #define LSI_SAS1068E_PCI_DEVICE_ID 0x0058 +#define MPT_REG_DOORBELL 0x00 +#define MPT_REG_WRITE_SEQ 0x04 +#define MPT_REG_HOST_DIAG 0x08 +#define MPT_REG_TEST 0x0c +#define MPT_REG_DIAG_DATA 0x10 +#define MPT_REG_DIAG_ADDR 0x14 +#define MPT_REG_ISTATUS 0x30 +#define MPT_REG_IMASK 0x34 +#define MPT_REG_REQ_Q 0x40 +#define MPT_REG_REP_Q 0x44 + +#define MPT_DOORBELL_RESET 0x40 +#define MPT_DOORBELL_HANDSHAKE 0x42 + +#define MPT_IMASK_DOORBELL 0x01 +#define MPT_IMASK_REPLY 0x08 + +#define MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST 0x00 +#define MPT_MESSAGE_HDR_FUNCTION_IOC_INIT 0x02 + +#define MPT_SG_ENTRY_TYPE_SIMPLE 0x01 + +#define MPT_IOC_WHOINIT_ROM_BIOS 0x02 + +// +// Device structures +// + +#pragma pack (1) +typedef struct { + UINT8 WhoInit; + UINT8 Reserved1; + UINT8 ChainOffset; + UINT8 Function; + UINT8 Flags; + UINT8 MaxDevices; + UINT8 MaxBuses; + UINT8 MessageFlags; + UINT32 MessageContext; + UINT16 ReplyFrameSize; + UINT16 Reserved2; + UINT32 HostMfaHighAddr; + UINT32 SenseBufferHighAddr; +} MPT_IO_CONTROLLER_INIT_REQUEST; + +typedef struct { + UINT8 WhoInit; + UINT8 Reserved1; + UINT8 MessageLength; + UINT8 Function; + UINT8 Flags; + UINT8 MaxDevices; + UINT8 MaxBuses; + UINT8 MessageFlags; + UINT32 MessageContext; + UINT16 Reserved2; + UINT16 IocStatus; + UINT32 IocLogInfo; +} MPT_IO_CONTROLLER_INIT_REPLY; + +typedef struct { + UINT8 TargetId; + UINT8 Bus; + UINT8 ChainOffset; + UINT8 Function; + UINT8 CdbLength; + UINT8 SenseBufferLength; + UINT8 Reserved; + UINT8 MessageFlags; + UINT32 MessageContext; + UINT8 Lun[8]; + UINT32 Control; + UINT8 Cdb[16]; + UINT32 DataLength; + UINT32 SenseBufferLowAddress; +} MPT_SCSI_IO_REQUEST; + +typedef struct { + UINT32 Length: 24; + UINT32 EndOfList: 1; + UINT32 Is64BitAddress: 1; + // + // True when the buffer contains data to be transfered. Otherwise it's the + // destination buffer + // + UINT32 BufferContainsData: 1; + UINT32 LocalAddress: 1; + UINT32 ElementType: 2; + UINT32 EndOfBuffer: 1; + UINT32 LastElement: 1; + UINT64 DataBufferAddress; +} MPT_SG_ENTRY_SIMPLE; + +typedef struct { + UINT8 TargetId; + UINT8 Bus; + UINT8 MessageLength; + UINT8 Function; + UINT8 CdbLength; + UINT8 SenseBufferLength; + UINT8 Reserved; + UINT8 MessageFlags; + UINT32 MessageContext; + UINT8 ScsiStatus; + UINT8 ScsiState; + UINT16 IocStatus; + UINT32 IocLogInfo; + UINT32 TransferCount; + UINT32 SenseCount; + UINT32 ResponseInfo; +} MPT_SCSI_IO_REPLY; + +typedef struct { + MPT_SCSI_IO_REQUEST Header; + MPT_SG_ENTRY_SIMPLE Sg; +} MPT_SCSI_REQUEST_WITH_SG; +#pragma pack () + +typedef union { + MPT_SCSI_IO_REPLY Data; + UINT64 Uint64; // 8 byte alignment required by HW +} MPT_SCSI_IO_REPLY_ALIGNED; + +typedef union { + MPT_SCSI_REQUEST_WITH_SG Data; + UINT64 Uint64; // 8 byte alignment required by HW +} MPT_SCSI_REQUEST_ALIGNED; + #endif // __FUSION_MPT_SCSI_H__ diff --git a/OvmfPkg/MptScsiDxe/MptScsi.c b/OvmfPkg/MptScsiDxe/MptScsi.c index 289bd9fc372b..2cc69b88dab3 100644 --- a/OvmfPkg/MptScsiDxe/MptScsi.c +++ b/OvmfPkg/MptScsiDxe/MptScsi.c @@ -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, -- 2.20.1