#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
#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
));\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
&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
return Status;\r
}\r
\r
+ MptScsiReset (Dev);\r
+\r
Dev->PciIo->Attributes (\r
Dev->PciIo,\r
EfiPciIoAttributeOperationSet,\r