]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/MptScsiDxe: Initialize hardware
authorNikita Leshenko <nikita.leshchenko@oracle.com>
Mon, 4 May 2020 21:06:05 +0000 (00:06 +0300)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Tue, 5 May 2020 20:43:02 +0000 (20:43 +0000)
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>
OvmfPkg/Include/IndustryStandard/FusionMptScsi.h
OvmfPkg/MptScsiDxe/MptScsi.c

index df9bdc2f0348cb50f3db7100b7136711a1c893b9..655d629d902e3c9041a3100ecd36372ebaa75765 100644 (file)
 #define LSI_SAS1068_PCI_DEVICE_ID 0x0054\r
 #define LSI_SAS1068E_PCI_DEVICE_ID 0x0058\r
 \r
+#define MPT_REG_DOORBELL  0x00\r
+#define MPT_REG_WRITE_SEQ 0x04\r
+#define MPT_REG_HOST_DIAG 0x08\r
+#define MPT_REG_TEST      0x0c\r
+#define MPT_REG_DIAG_DATA 0x10\r
+#define MPT_REG_DIAG_ADDR 0x14\r
+#define MPT_REG_ISTATUS   0x30\r
+#define MPT_REG_IMASK     0x34\r
+#define MPT_REG_REQ_Q     0x40\r
+#define MPT_REG_REP_Q     0x44\r
+\r
+#define MPT_DOORBELL_RESET     0x40\r
+#define MPT_DOORBELL_HANDSHAKE 0x42\r
+\r
+#define MPT_IMASK_DOORBELL 0x01\r
+#define MPT_IMASK_REPLY    0x08\r
+\r
+#define MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST 0x00\r
+#define MPT_MESSAGE_HDR_FUNCTION_IOC_INIT        0x02\r
+\r
+#define MPT_SG_ENTRY_TYPE_SIMPLE 0x01\r
+\r
+#define MPT_IOC_WHOINIT_ROM_BIOS 0x02\r
+\r
+//\r
+// Device structures\r
+//\r
+\r
+#pragma pack (1)\r
+typedef struct {\r
+  UINT8     WhoInit;\r
+  UINT8     Reserved1;\r
+  UINT8     ChainOffset;\r
+  UINT8     Function;\r
+  UINT8     Flags;\r
+  UINT8     MaxDevices;\r
+  UINT8     MaxBuses;\r
+  UINT8     MessageFlags;\r
+  UINT32    MessageContext;\r
+  UINT16    ReplyFrameSize;\r
+  UINT16    Reserved2;\r
+  UINT32    HostMfaHighAddr;\r
+  UINT32    SenseBufferHighAddr;\r
+} MPT_IO_CONTROLLER_INIT_REQUEST;\r
+\r
+typedef struct {\r
+  UINT8     WhoInit;\r
+  UINT8     Reserved1;\r
+  UINT8     MessageLength;\r
+  UINT8     Function;\r
+  UINT8     Flags;\r
+  UINT8     MaxDevices;\r
+  UINT8     MaxBuses;\r
+  UINT8     MessageFlags;\r
+  UINT32    MessageContext;\r
+  UINT16    Reserved2;\r
+  UINT16    IocStatus;\r
+  UINT32    IocLogInfo;\r
+} MPT_IO_CONTROLLER_INIT_REPLY;\r
+\r
+typedef struct {\r
+  UINT8     TargetId;\r
+  UINT8     Bus;\r
+  UINT8     ChainOffset;\r
+  UINT8     Function;\r
+  UINT8     CdbLength;\r
+  UINT8     SenseBufferLength;\r
+  UINT8     Reserved;\r
+  UINT8     MessageFlags;\r
+  UINT32    MessageContext;\r
+  UINT8     Lun[8];\r
+  UINT32    Control;\r
+  UINT8     Cdb[16];\r
+  UINT32    DataLength;\r
+  UINT32    SenseBufferLowAddress;\r
+} MPT_SCSI_IO_REQUEST;\r
+\r
+typedef struct {\r
+  UINT32    Length:             24;\r
+  UINT32    EndOfList:          1;\r
+  UINT32    Is64BitAddress:     1;\r
+  //\r
+  // True when the buffer contains data to be transfered. Otherwise it's the\r
+  // destination buffer\r
+  //\r
+  UINT32    BufferContainsData: 1;\r
+  UINT32    LocalAddress:       1;\r
+  UINT32    ElementType:        2;\r
+  UINT32    EndOfBuffer:        1;\r
+  UINT32    LastElement:        1;\r
+  UINT64    DataBufferAddress;\r
+} MPT_SG_ENTRY_SIMPLE;\r
+\r
+typedef struct {\r
+  UINT8     TargetId;\r
+  UINT8     Bus;\r
+  UINT8     MessageLength;\r
+  UINT8     Function;\r
+  UINT8     CdbLength;\r
+  UINT8     SenseBufferLength;\r
+  UINT8     Reserved;\r
+  UINT8     MessageFlags;\r
+  UINT32    MessageContext;\r
+  UINT8     ScsiStatus;\r
+  UINT8     ScsiState;\r
+  UINT16    IocStatus;\r
+  UINT32    IocLogInfo;\r
+  UINT32    TransferCount;\r
+  UINT32    SenseCount;\r
+  UINT32    ResponseInfo;\r
+} MPT_SCSI_IO_REPLY;\r
+\r
+typedef struct {\r
+  MPT_SCSI_IO_REQUEST Header;\r
+  MPT_SG_ENTRY_SIMPLE Sg;\r
+} MPT_SCSI_REQUEST_WITH_SG;\r
+#pragma pack ()\r
+\r
+typedef union {\r
+  MPT_SCSI_IO_REPLY        Data;\r
+  UINT64                   Uint64; // 8 byte alignment required by HW\r
+} MPT_SCSI_IO_REPLY_ALIGNED;\r
+\r
+typedef union {\r
+  MPT_SCSI_REQUEST_WITH_SG Data;\r
+  UINT64                   Uint64; // 8 byte alignment required by HW\r
+} MPT_SCSI_REQUEST_ALIGNED;\r
+\r
 #endif // __FUSION_MPT_SCSI_H__\r
index 289bd9fc372bccb9b760805e4ac288bc722ec31e..2cc69b88dab39d4094e86bcffd1b8ae65b53566a 100644 (file)
@@ -44,6 +44,192 @@ typedef struct {
 #define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \\r
   CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)\r
 \r
+//\r
+// Hardware functions\r
+//\r
+\r
+STATIC\r
+EFI_STATUS\r
+Out32 (\r
+  IN MPT_SCSI_DEV       *Dev,\r
+  IN UINT32             Addr,\r
+  IN UINT32             Data\r
+  )\r
+{\r
+  return Dev->PciIo->Io.Write (\r
+                          Dev->PciIo,\r
+                          EfiPciIoWidthUint32,\r
+                          PCI_BAR_IDX0,\r
+                          Addr,\r
+                          1,\r
+                          &Data\r
+                          );\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+In32 (\r
+  IN  MPT_SCSI_DEV       *Dev,\r
+  IN  UINT32             Addr,\r
+  OUT UINT32             *Data\r
+  )\r
+{\r
+  return Dev->PciIo->Io.Read (\r
+                          Dev->PciIo,\r
+                          EfiPciIoWidthUint32,\r
+                          PCI_BAR_IDX0,\r
+                          Addr,\r
+                          1,\r
+                          Data\r
+                          );\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+MptDoorbell (\r
+  IN MPT_SCSI_DEV       *Dev,\r
+  IN UINT8              DoorbellFunc,\r
+  IN UINT8              DoorbellArg\r
+  )\r
+{\r
+  return Out32 (\r
+           Dev,\r
+           MPT_REG_DOORBELL,\r
+           (((UINT32)DoorbellFunc) << 24) | (DoorbellArg << 16)\r
+           );\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+MptScsiReset (\r
+  IN MPT_SCSI_DEV       *Dev\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  // Reset hardware\r
+  //\r
+  Status = MptDoorbell (Dev, MPT_DOORBELL_RESET, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Mask interrupts\r
+  //\r
+  Status = Out32 (Dev, MPT_REG_IMASK, MPT_IMASK_DOORBELL | MPT_IMASK_REPLY);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Clear interrupt status\r
+  //\r
+  Status = Out32 (Dev, MPT_REG_ISTATUS, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+MptScsiInit (\r
+  IN MPT_SCSI_DEV       *Dev\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  union {\r
+    MPT_IO_CONTROLLER_INIT_REQUEST Data;\r
+    UINT32                         Uint32;\r
+  } AlignedReq;\r
+  MPT_IO_CONTROLLER_INIT_REQUEST   *Req;\r
+  MPT_IO_CONTROLLER_INIT_REPLY     Reply;\r
+  UINT8                            *ReplyBytes;\r
+  UINT32                           ReplyWord;\r
+\r
+  Req = &AlignedReq.Data;\r
+\r
+  Status = MptScsiReset (Dev);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ZeroMem (Req, sizeof (*Req));\r
+  ZeroMem (&Reply, sizeof (Reply));\r
+  Req->WhoInit = MPT_IOC_WHOINIT_ROM_BIOS;\r
+  Req->Function = MPT_MESSAGE_HDR_FUNCTION_IOC_INIT;\r
+  STATIC_ASSERT (\r
+    FixedPcdGet8 (PcdMptScsiMaxTargetLimit) < 255,\r
+    "Req supports 255 targets only (max target is 254)"\r
+    );\r
+  Req->MaxDevices = Dev->MaxTarget + 1;\r
+  Req->MaxBuses = 1;\r
+\r
+  //\r
+  // Send controller init through doorbell\r
+  //\r
+  STATIC_ASSERT (\r
+    sizeof (*Req) % sizeof (UINT32) == 0,\r
+    "Req must be multiple of UINT32"\r
+    );\r
+  STATIC_ASSERT (\r
+    sizeof (*Req) / sizeof (UINT32) <= MAX_UINT8,\r
+    "Req must fit in MAX_UINT8 Dwords"\r
+    );\r
+  Status = MptDoorbell (\r
+             Dev,\r
+             MPT_DOORBELL_HANDSHAKE,\r
+             (UINT8)(sizeof (*Req) / sizeof (UINT32))\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  Status = Dev->PciIo->Io.Write (\r
+                            Dev->PciIo,\r
+                            EfiPciIoWidthFifoUint32,\r
+                            PCI_BAR_IDX0,\r
+                            MPT_REG_DOORBELL,\r
+                            sizeof (*Req) / sizeof (UINT32),\r
+                            Req\r
+                            );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Read reply through doorbell\r
+  // Each 32bit (Dword) read produces 16bit (Word) of data\r
+  //\r
+  // The reply is read back to complete the doorbell function but it\r
+  // isn't useful because it doesn't contain relevant data or status\r
+  // codes.\r
+  //\r
+  STATIC_ASSERT (\r
+    sizeof (Reply) % sizeof (UINT16) == 0,\r
+    "Reply must be multiple of UINT16"\r
+    );\r
+  ReplyBytes = (UINT8 *)&Reply;\r
+  while (ReplyBytes != (UINT8 *)(&Reply + 1)) {\r
+    Status = In32 (Dev, MPT_REG_DOORBELL, &ReplyWord);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    CopyMem (ReplyBytes, &ReplyWord, sizeof (UINT16));\r
+    ReplyBytes += sizeof (UINT16);\r
+  }\r
+\r
+  //\r
+  // Clear interrupts generated by doorbell reply\r
+  //\r
+  Status = Out32 (Dev, MPT_REG_ISTATUS, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 //\r
 // Ext SCSI Pass Thru\r
 //\r
@@ -383,6 +569,11 @@ MptScsiControllerStart (
       ));\r
   }\r
 \r
+  Status = MptScsiInit (Dev);\r
+  if (EFI_ERROR (Status)) {\r
+    goto RestoreAttributes;\r
+  }\r
+\r
   //\r
   // Host adapter channel, doesn't exist\r
   //\r
@@ -407,11 +598,14 @@ MptScsiControllerStart (
                   &Dev->PassThru\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    goto RestoreAttributes;\r
+    goto UninitDev;\r
   }\r
 \r
   return EFI_SUCCESS;\r
 \r
+UninitDev:\r
+  MptScsiReset (Dev);\r
+\r
 RestoreAttributes:\r
   Dev->PciIo->Attributes (\r
                 Dev->PciIo,\r
@@ -471,6 +665,8 @@ MptScsiControllerStop (
     return Status;\r
   }\r
 \r
+  MptScsiReset (Dev);\r
+\r
   Dev->PciIo->Attributes (\r
                 Dev->PciIo,\r
                 EfiPciIoAttributeOperationSet,\r