]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ScsiBus/ScsiDisk enhancement for no_media state.
authorerictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 14 Jun 2011 02:11:34 +0000 (02:11 +0000)
committererictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 14 Jun 2011 02:11:34 +0000 (02:11 +0000)
Ahci enumeration logic tuning for boot performance.

Signed-off-by:erictian
Reviewed-by:qianouyang, hhuan13

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11820 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c

index a36d03e827a9512e6c658214cdd8950505b5c65a..b83babf0812b6ac4948a08519f5c36e9fae834eb 100644 (file)
@@ -1273,12 +1273,12 @@ AhciStartCommand (
   if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
     if ((Capability & BIT24) != 0) {\r
       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
-      AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL);\r
+      AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);\r
 \r
       AhciWaitMemSet (\r
         PciIo,\r
         Offset,\r
-        EFI_AHCI_PORT_CMD_COL,\r
+        EFI_AHCI_PORT_CMD_CLO,\r
         0,\r
         Timeout\r
         );\r
@@ -1816,7 +1816,6 @@ AhciPacketCommandExecute (
   EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;\r
   EFI_ATA_STATUS_BLOCK         AtaStatusBlock;\r
   BOOLEAN                      Read;\r
-  UINT8                        Retry;\r
 \r
   if (Packet == NULL || Packet->Cdb == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1860,35 +1859,21 @@ AhciPacketCommandExecute (
                NULL\r
                );\r
   } else {\r
-    //\r
-    // READ_CAPACITY cmd may execute failure. Retry 5 times\r
-    //\r
-    if (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_READ_CAPACITY) {\r
-      Retry = 5;\r
-    } else {\r
-      Retry = 1;\r
-    }\r
-    do {\r
-      Status = AhciPioTransfer (\r
-                 PciIo,\r
-                 AhciRegisters,\r
-                 Port,\r
-                 PortMultiplier,\r
-                 Packet->Cdb,\r
-                 Packet->CdbLength,\r
-                 Read,\r
-                 &AtaCommandBlock,\r
-                 &AtaStatusBlock,\r
-                 Buffer,\r
-                 Length,\r
-                 Packet->Timeout, \r
-                 NULL\r
-                 );\r
-      if (!EFI_ERROR (Status)) {\r
-        break;\r
-      }\r
-      Retry--;\r
-    } while (Retry != 0);\r
+    Status = AhciPioTransfer (\r
+               PciIo,\r
+               AhciRegisters,\r
+               Port,\r
+               PortMultiplier,\r
+               Packet->Cdb,\r
+               Packet->CdbLength,\r
+               Read,\r
+               &AtaCommandBlock,\r
+               &AtaStatusBlock,\r
+               Buffer,\r
+               Length,\r
+               Packet->Timeout, \r
+               NULL\r
+               );\r
   }\r
   return Status;\r
 }\r
@@ -2165,7 +2150,8 @@ AhciModeInitialization (
   EFI_ATA_DEVICE_TYPE              DeviceType;\r
   EFI_ATA_COLLECTIVE_MODE          *SupportedModes;\r
   EFI_ATA_TRANSFER_MODE            TransferMode;\r
-  \r
+  UINT32                           PhyDetectDelay;\r
+\r
   if (Instance == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -2173,7 +2159,7 @@ AhciModeInitialization (
   PciIo   = Instance->PciIo;\r
   IdeInit = Instance->IdeControllerInit;\r
 \r
-  Status = AhciReset (PciIo, ATA_ATAPI_TIMEOUT); \r
+  Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT); \r
 \r
   if (EFI_ERROR (Status)) {\r
     return EFI_DEVICE_ERROR;\r
@@ -2193,14 +2179,14 @@ AhciModeInitialization (
   // Get the number of command slots per port supported by this HBA.\r
   //\r
   MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
-  Support64Bit         = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
+  MaxPortNumber        = (UINT8) ((Capability & 0x1F) + 1);\r
+  Support64Bit         = (BOOLEAN) (((Capability & EFI_AHCI_CAP_S64A) != 0) ? TRUE : FALSE);\r
 \r
   //\r
   // Get the bit map of those ports exposed by this HBA.\r
   // It indicates which ports that the HBA supports are available for software to use. \r
   //\r
   PortImplementBitMap  = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
-  MaxPortNumber        = (UINT8) ((Capability & 0x1F) + 1);\r
   \r
   AhciRegisters = &Instance->AhciRegisters;\r
   Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
@@ -2210,191 +2196,227 @@ AhciModeInitialization (
   }\r
 \r
   for (Port = 0; Port < MaxPortNumber; Port ++) {  \r
-    Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
-  \r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
-    AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
-    AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
-  \r
-    //\r
-    // Single task envrionment, we only use one command table for all port\r
-    //\r
-    Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
-  \r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
-    AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
-    AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
-  \r
     if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
+      IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
+\r
+      //\r
+      // Initialize FIS Base Address Register and Command List Base Address Register for use.\r
+      //\r
+      Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+      AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
+      AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
+\r
+      Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+      AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
+      AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
+\r
       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
-  \r
-      if ((Capability & EFI_AHCI_PORT_CMD_ASP) != 0) {\r
-        AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
-      }\r
       Data = AhciReadReg (PciIo, Offset);\r
       if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
         AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
       }\r
-  \r
-      AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE|EFI_AHCI_PORT_CMD_COL|EFI_AHCI_PORT_CMD_ST));\r
-    }\r
-  \r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
-    AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_MASK));\r
\r
-    AhciAndReg (PciIo, Offset,(UINT32) ~(EFI_AHCI_PORT_SCTL_IPM_PSD));\r
-    AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_PSD);\r
-  \r
-    AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_SSD));\r
-    AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_SSD);\r
-  \r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
-    AhciAndReg (PciIo, Offset, 0);\r
-  \r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
-    AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
-  }\r
 \r
-  //\r
-  // Stall for 100 milliseconds.\r
-  //\r
-  MicroSecondDelay(100000);\r
-  \r
-  IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
-  \r
-  for (Port = 0; Port < MaxPortNumber; Port ++) {  \r
-    if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
-    \r
-      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
-      Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
+      if ((Capability & EFI_AHCI_CAP_SSS) != 0) {\r
+        AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
+      }\r
+\r
+      //\r
+      // Disable aggressive power management.\r
+      //\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
+      AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
+      //\r
+      // Disable the reporting of the corresponding interrupt to system software.\r
+      //\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
+      AhciAndReg (PciIo, Offset, 0);\r
 \r
-      if (Data == 0) {\r
+      //\r
+      // Now inform the IDE Controller Init Module.\r
+      //\r
+      IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
+\r
+      //\r
+      // Enable FIS Receive DMA engine for the first D2H FIS.\r
+      //\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+      AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
+      Status = AhciWaitMemSet (\r
+                 PciIo, \r
+                 Offset,\r
+                 EFI_AHCI_PORT_CMD_FR,\r
+                 EFI_AHCI_PORT_CMD_FR,\r
+                 EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
         continue;\r
       }\r
+\r
       //\r
-      // Found device in the port\r
+      // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.\r
+      // It's the requirment from SATA1.0a spec section 5.2.\r
       //\r
-      if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
-        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
-\r
-        Status = AhciWaitMemSet (\r
-                   PciIo, \r
-                   Offset,\r
-                   0x0000FFFF,\r
-                   0x00000101,\r
-                   ATA_ATAPI_TIMEOUT\r
-                   );\r
-        if (EFI_ERROR (Status)) {\r
-          continue;\r
+      PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
+      do {\r
+        Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
+        if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {\r
+          break;\r
         }\r
 \r
+        MicroSecondDelay (1000);\r
+        PhyDetectDelay--;\r
+      } while (PhyDetectDelay > 0);\r
+\r
+      if (PhyDetectDelay == 0) {\r
         //\r
-        // Now inform the IDE Controller Init Module.\r
+        // No device detected at this port.\r
         //\r
-        IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
+        continue;\r
+      }\r
 \r
-        Data = AhciReadReg (PciIo, Offset);\r
+      //\r
+      // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ\r
+      // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.\r
+      //\r
+      PhyDetectDelay = 16 * 1000;\r
+      do {\r
+        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
+        if (AhciReadReg(PciIo, Offset) != 0) {\r
+          AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset));\r
+        }\r
+        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
 \r
-        if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
-          Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
+        Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;\r
+        if (Data == 0) {\r
+          break;\r
+        }\r
 \r
-          if (EFI_ERROR (Status)) {\r
-            continue;\r
-          }\r
+        MicroSecondDelay (1000);\r
+        PhyDetectDelay--;\r
+      } while (PhyDetectDelay > 0);\r
+      \r
+      if (PhyDetectDelay == 0) {\r
+        continue;\r
+      }\r
 \r
-          DeviceType = EfiIdeCdrom;\r
-        } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
-          Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
+      //\r
+      // When the first D2H register FIS is received, the content of PxSIG register is updated.\r
+      //\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
+      Status = AhciWaitMemSet (\r
+                 PciIo, \r
+                 Offset,\r
+                 0x0000FFFF,\r
+                 0x00000101,\r
+                 EFI_TIMER_PERIOD_SECONDS(16)\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
 \r
-          if (EFI_ERROR (Status)) {\r
-            REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
-            continue;\r
-          }\r
+      Data = AhciReadReg (PciIo, Offset);\r
+      if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
+        Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
 \r
-          DeviceType = EfiIdeHarddisk;\r
-        } else {\r
+        if (EFI_ERROR (Status)) {\r
           continue;\r
         }\r
 \r
-        DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
-            Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
-\r
-        //\r
-        // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
-        //\r
-        if (DeviceType == EfiIdeHarddisk) {\r
-          AhciAtaSmartSupport (\r
-            PciIo,\r
-            AhciRegisters,\r
-            Port,\r
-            0,\r
-            &Buffer,\r
-            NULL\r
-            );\r
-        }\r
-\r
-        //\r
-        // Submit identify data to IDE controller init driver\r
-        //\r
-        IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
+        DeviceType = EfiIdeCdrom;\r
+      } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
+        Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
 \r
-        //\r
-        // Now start to config ide device parameter and transfer mode.\r
-        //\r
-        Status = IdeInit->CalculateMode (\r
-                            IdeInit,\r
-                            Port,\r
-                            0,\r
-                            &SupportedModes\r
-                            );\r
         if (EFI_ERROR (Status)) {\r
-          DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
+          REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
           continue;\r
         }\r
 \r
-        //\r
-        // Set best supported PIO mode on this IDE device\r
-        //\r
-        if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
-          TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
-        } else {\r
-          TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
-        }\r
+        DeviceType = EfiIdeHarddisk;\r
+      } else {\r
+        continue;\r
+      }\r
+      DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
+              Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
 \r
-        TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
-    \r
-        //\r
-        // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
-        // be set together. Only one DMA mode can be set to a device. If setting\r
-        // DMA mode operation fails, we can continue moving on because we only use\r
-        // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
-        //\r
-        if (SupportedModes->UdmaMode.Valid) {\r
-          TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
-          TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
-        } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
-          TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
-          TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;  \r
-        }\r
+      //\r
+      // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
+      //\r
+      if (DeviceType == EfiIdeHarddisk) {\r
+        AhciAtaSmartSupport (\r
+          PciIo,\r
+          AhciRegisters,\r
+          Port,\r
+          0,\r
+          &Buffer,\r
+          NULL\r
+          );\r
+      }\r
 \r
-        Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
+      //\r
+      // Submit identify data to IDE controller init driver\r
+      //\r
+      IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
 \r
-        if (EFI_ERROR (Status)) {\r
-          DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
-          continue;\r
-        }\r
-        //\r
-        // Found a ATA or ATAPI device, add it into the device list.\r
-        //\r
-        CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
-        if (DeviceType == EfiIdeHarddisk) {\r
-          REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
-        }\r
+      //\r
+      // Now start to config ide device parameter and transfer mode.\r
+      //\r
+      Status = IdeInit->CalculateMode (\r
+                          IdeInit,\r
+                          Port,\r
+                          0,\r
+                          &SupportedModes\r
+                          );\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Set best supported PIO mode on this IDE device\r
+      //\r
+      if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
+        TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
+      } else {\r
+        TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
+      }\r
+\r
+      TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
+\r
+      //\r
+      // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
+      // be set together. Only one DMA mode can be set to a device. If setting\r
+      // DMA mode operation fails, we can continue moving on because we only use\r
+      // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
+      //\r
+      if (SupportedModes->UdmaMode.Valid) {\r
+        TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
+        TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
+      } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
+        TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
+        TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;  \r
+      }\r
+\r
+      Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Found a ATA or ATAPI device, add it into the device list.\r
+      //\r
+      CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
+      if (DeviceType == EfiIdeHarddisk) {\r
+        REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
       }\r
     }\r
   }\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
index 9c4a9397e9a84400f60cebc158cae5602592abd4..032b97cd2f2226b7a32fb1b72071ede321434827 100644 (file)
@@ -17,6 +17,8 @@
 #define EFI_AHCI_BAR_INDEX                     0x05\r
 \r
 #define EFI_AHCI_CAPABILITY_OFFSET             0x0000\r
+#define   EFI_AHCI_CAP_SSS                     BIT27\r
+#define   EFI_AHCI_CAP_S64A                    BIT31\r
 #define EFI_AHCI_GHC_OFFSET                    0x0004\r
 #define   EFI_AHCI_GHC_RESET                   BIT0\r
 #define   EFI_AHCI_GHC_IE                      BIT1\r
@@ -34,6 +36,19 @@ typedef union {
   UINT64    Uint64;\r
 } DATA_64;\r
 \r
+//\r
+// Refer SATA1.0a spec section 5.2, the Phy detection time should be less than 10ms.\r
+//\r
+#define  EFI_AHCI_BUS_PHY_DETECT_TIMEOUT       10\r
+//\r
+// Refer SATA1.0a spec, the FIS enable time should be less than 500ms.\r
+//\r
+#define  EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT    EFI_TIMER_PERIOD_MILLISECONDS(500)\r
+//\r
+// Refer SATA1.0a spec, the bus reset time should be less than 1s.\r
+//\r
+#define  EFI_AHCI_BUS_RESET_TIMEOUT            EFI_TIMER_PERIOD_SECONDS(1)\r
+\r
 #define  EFI_AHCI_ATAPI_DEVICE_SIG             0xEB140000\r
 #define  EFI_AHCI_ATA_DEVICE_SIG               0x00000000\r
 #define  EFI_AHCI_PORT_MULTIPLIER_SIG          0x96690000\r
@@ -103,7 +118,7 @@ typedef union {
 #define   EFI_AHCI_PORT_CMD_ST                 BIT0\r
 #define   EFI_AHCI_PORT_CMD_SUD                BIT1\r
 #define   EFI_AHCI_PORT_CMD_POD                BIT2\r
-#define   EFI_AHCI_PORT_CMD_COL                BIT3\r
+#define   EFI_AHCI_PORT_CMD_CLO                BIT3\r
 #define   EFI_AHCI_PORT_CMD_CR                 BIT15\r
 #define   EFI_AHCI_PORT_CMD_FRE                BIT4\r
 #define   EFI_AHCI_PORT_CMD_FR                 BIT14\r
index e6d963672ebef3685052b7ac2321711ae207c2d2..bfb36df828db77c9d2f71a0e86c16c65f12d8b6e 100644 (file)
@@ -1026,10 +1026,63 @@ ScsiScanCreateDevice (
   EFI_STATUS                Status;\r
   SCSI_IO_DEV               *ScsiIoDevice;\r
   EFI_DEVICE_PATH_PROTOCOL  *ScsiDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;\r
+  EFI_HANDLE                 DeviceHandle;\r
+\r
+  DevicePath          = NULL;\r
+  RemainingDevicePath = NULL;\r
+  ScsiDevicePath      = NULL;\r
+  ScsiIoDevice        = NULL;\r
+\r
+  //\r
+  // Build Device Path\r
+  //\r
+  if (ScsiBusDev->ExtScsiSupport){\r
+    Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath (\r
+                                             ScsiBusDev->ExtScsiInterface,\r
+                                             &TargetId->ScsiId.ExtScsi[0],\r
+                                             Lun,\r
+                                             &ScsiDevicePath\r
+                                             );\r
+  } else {\r
+    Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (\r
+                                           ScsiBusDev->ScsiInterface,\r
+                                           TargetId->ScsiId.Scsi,\r
+                                           Lun,\r
+                                           &ScsiDevicePath\r
+                                           );\r
+  }\r
+\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DevicePath = AppendDevicePathNode (\r
+                 ScsiBusDev->DevicePath,\r
+                 ScsiDevicePath\r
+                 );\r
+\r
+  if (DevicePath == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ErrorExit;\r
+  }\r
+\r
+  DeviceHandle = NULL;\r
+  RemainingDevicePath = DevicePath;\r
+  Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
+  if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
+    //\r
+    // The device has been started, directly return to fast boot.\r
+    //\r
+    Status = EFI_ALREADY_STARTED;\r
+    goto ErrorExit;\r
+  }\r
 \r
   ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));\r
   if (ScsiIoDevice == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ErrorExit;\r
   }\r
 \r
   ScsiIoDevice->Signature                 = SCSI_IO_DEV_SIGNATURE;\r
@@ -1053,52 +1106,12 @@ ScsiScanCreateDevice (
   ScsiIoDevice->ScsiIo.ResetDevice        = ScsiResetDevice;\r
   ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;\r
 \r
-\r
   if (!DiscoverScsiDevice (ScsiIoDevice)) {\r
-    FreePool (ScsiIoDevice);\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ErrorExit;\r
   }\r
 \r
-  //\r
-  // Set Device Path\r
-  //\r
-  ScsiDevicePath = NULL;\r
-  if (ScsiIoDevice->ExtScsiSupport){\r
-    Status = ScsiIoDevice->ExtScsiPassThru->BuildDevicePath (\r
-                                          ScsiIoDevice->ExtScsiPassThru,\r
-                                          &ScsiIoDevice->Pun.ScsiId.ExtScsi[0],\r
-                                          ScsiIoDevice->Lun,\r
-                                          &ScsiDevicePath\r
-                                          );\r
-  } else {\r
-    Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (\r
-                                          ScsiIoDevice->ScsiPassThru,\r
-                                          ScsiIoDevice->Pun.ScsiId.Scsi,\r
-                                          ScsiIoDevice->Lun,\r
-                                          &ScsiDevicePath\r
-                                          );\r
-  }\r
-\r
-  if (EFI_ERROR(Status)) {\r
-    FreePool (ScsiIoDevice);\r
-    return Status;\r
-  }\r
-\r
-  ScsiIoDevice->DevicePath = AppendDevicePathNode (\r
-                              ScsiBusDev->DevicePath,\r
-                              ScsiDevicePath\r
-                              );\r
-  //\r
-  // The memory space for ScsiDevicePath is allocated in\r
-  // ScsiPassThru->BuildDevicePath() function; It is no longer used\r
-  // after EfiAppendDevicePathNode,so free the memory it occupies.\r
-  //\r
-  FreePool (ScsiDevicePath);\r
-\r
-  if (ScsiIoDevice->DevicePath == NULL) {\r
-    FreePool (ScsiIoDevice);\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+  ScsiIoDevice->DevicePath = DevicePath;\r
 \r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &ScsiIoDevice->Handle,\r
@@ -1109,31 +1122,48 @@ ScsiScanCreateDevice (
                   NULL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    FreePool (ScsiIoDevice->DevicePath);\r
-    FreePool (ScsiIoDevice);\r
-    return EFI_OUT_OF_RESOURCES;\r
+    goto ErrorExit;\r
   } else {\r
     if (ScsiBusDev->ExtScsiSupport) {\r
       gBS->OpenProtocol (\r
-            Controller,\r
-            &gEfiExtScsiPassThruProtocolGuid,\r
-            (VOID **) &(ScsiBusDev->ExtScsiInterface),\r
-            This->DriverBindingHandle,\r
-            ScsiIoDevice->Handle,\r
-            EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
-            );\r
+             Controller,\r
+             &gEfiExtScsiPassThruProtocolGuid,\r
+             (VOID **) &(ScsiBusDev->ExtScsiInterface),\r
+             This->DriverBindingHandle,\r
+             ScsiIoDevice->Handle,\r
+             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+             );\r
      } else {\r
       gBS->OpenProtocol (\r
-            Controller,\r
-            &gEfiScsiPassThruProtocolGuid,\r
-            (VOID **) &(ScsiBusDev->ScsiInterface),\r
-            This->DriverBindingHandle,\r
-            ScsiIoDevice->Handle,\r
-            EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
-            );\r
+             Controller,\r
+             &gEfiScsiPassThruProtocolGuid,\r
+             (VOID **) &(ScsiBusDev->ScsiInterface),\r
+             This->DriverBindingHandle,\r
+             ScsiIoDevice->Handle,\r
+             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+             );\r
      }\r
   }\r
   return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+  \r
+  //\r
+  // The memory space for ScsiDevicePath is allocated in\r
+  // ScsiPassThru->BuildDevicePath() function; It is no longer used\r
+  // after AppendDevicePathNode,so free the memory it occupies.\r
+  //\r
+  FreePool (ScsiDevicePath);\r
+\r
+  if (DevicePath != NULL) {\r
+    FreePool (DevicePath);\r
+  }\r
+\r
+  if (ScsiIoDevice != NULL) {\r
+    FreePool (ScsiIoDevice);\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 \r
@@ -1158,6 +1188,8 @@ DiscoverScsiDevice (
   UINT8                 TargetStatus;\r
   EFI_SCSI_SENSE_DATA   SenseData;\r
   EFI_SCSI_INQUIRY_DATA InquiryData;\r
+  UINT8                 MaxRetry;\r
+  UINT8                 Index;\r
 \r
   HostAdapterStatus = 0;\r
   TargetStatus      = 0;\r
@@ -1166,21 +1198,34 @@ DiscoverScsiDevice (
   //\r
   InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
   SenseDataLength   = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);\r
+  ZeroMem (&InquiryData, InquiryDataLength);\r
+\r
+  MaxRetry = 2;\r
+  for (Index = 0; Index < MaxRetry; Index++) {\r
+    Status = ScsiInquiryCommand (\r
+              &ScsiIoDevice->ScsiIo,\r
+              EFI_TIMER_PERIOD_SECONDS (1),\r
+              (VOID *) &SenseData,\r
+              &SenseDataLength,\r
+              &HostAdapterStatus,\r
+              &TargetStatus,\r
+              (VOID *) &InquiryData,\r
+              &InquiryDataLength,\r
+              FALSE\r
+              );\r
+    if (!EFI_ERROR (Status)) {\r
+      break;\r
+    } else if ((Status == EFI_BAD_BUFFER_SIZE) || \r
+               (Status == EFI_INVALID_PARAMETER) ||\r
+               (Status == EFI_UNSUPPORTED)) {\r
+      return FALSE;\r
+    }\r
+  }\r
 \r
-  Status = ScsiInquiryCommand (\r
-            &ScsiIoDevice->ScsiIo,\r
-            EFI_TIMER_PERIOD_SECONDS (1),\r
-            (VOID *) &SenseData,\r
-            &SenseDataLength,\r
-            &HostAdapterStatus,\r
-            &TargetStatus,\r
-            (VOID *) &InquiryData,\r
-            &InquiryDataLength,\r
-            FALSE\r
-            );\r
-  if (EFI_ERROR (Status) && Status != EFI_BAD_BUFFER_SIZE) {\r
+  if (Index == MaxRetry) {\r
     return FALSE;\r
   }\r
+  \r
   //\r
   // Retrieved inquiry data successfully\r
   //\r
index f0e10997daa885ea9c39099ae5ae5c7d9bdd27b9..e9a7788faf862dbf4b31adaf8524e171659f6712 100644 (file)
@@ -166,6 +166,9 @@ ScsiDiskDriverBindingStart (
   UINT8                 Index;\r
   UINT8                 MaxRetry;\r
   BOOLEAN               NeedRetry;\r
+  BOOLEAN               MustReadCapacity;\r
+\r
+  MustReadCapacity = TRUE;\r
 \r
   ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));\r
   if (ScsiDiskDevice == NULL) {\r
@@ -199,10 +202,12 @@ ScsiDiskDriverBindingStart (
   switch (ScsiDiskDevice->DeviceType) {\r
   case EFI_SCSI_TYPE_DISK:\r
     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
+    MustReadCapacity = TRUE;\r
     break;\r
 \r
   case EFI_SCSI_TYPE_CDROM:\r
     ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;\r
+    MustReadCapacity = FALSE;\r
     break;\r
   }\r
   //\r
@@ -249,7 +254,7 @@ ScsiDiskDriverBindingStart (
   // The second parameter "TRUE" means must\r
   // retrieve media capacity\r
   //\r
-  Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp);\r
+  Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);\r
   if (!EFI_ERROR (Status)) {\r
     //\r
     // Determine if Block IO should be produced on this controller handle\r
@@ -710,6 +715,7 @@ ScsiDiskDetectMedia (
   CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));\r
   *MediaChange        = FALSE;\r
   MaxRetry            = 3;\r
+  Action              = ACTION_NO_ACTION;\r
 \r
   for (Index = 0; Index < MaxRetry; Index++) {\r
     Status = ScsiDiskTestUnitReady (\r
@@ -719,7 +725,19 @@ ScsiDiskDetectMedia (
               &NumberOfSenseKeys\r
               );\r
     if (!EFI_ERROR (Status)) {\r
-      break;\r
+      Status = DetectMediaParsingSenseKeys (\r
+                 ScsiDiskDevice,\r
+                 SenseData,\r
+                 NumberOfSenseKeys,\r
+                 &Action\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      } else if (Action == ACTION_RETRY_COMMAND_LATER) {\r
+        continue;\r
+      } else {\r
+        break;\r
+      }\r
     }\r
 \r
     if (!NeedRetry) {\r
@@ -731,22 +749,11 @@ ScsiDiskDetectMedia (
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  Status = DetectMediaParsingSenseKeys (\r
-            ScsiDiskDevice,\r
-            SenseData,\r
-            NumberOfSenseKeys,\r
-            &Action\r
-            );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
   //\r
   // ACTION_NO_ACTION: need not read capacity\r
   // other action code: need read capacity\r
   //\r
-  if (Action == ACTION_NO_ACTION) {\r
-    NeedReadCapacity = FALSE;\r
-  } else {\r
+  if (Action == ACTION_READ_CAPACITY) {\r
     NeedReadCapacity = TRUE;\r
   }\r
 \r
@@ -1205,6 +1212,11 @@ DetectMediaParsingSenseKeys (
     return EFI_SUCCESS;\r
   }\r
 \r
+  if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {\r
+    *Action = ACTION_RETRY_COMMAND_LATER;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {\r
     ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
     ScsiDiskDevice->BlkIo.Media->LastBlock    = 0;\r