#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