]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ata.c
fixed the following problems:
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / IdeBusDxe / ata.c
index ec546bb6b24b41121e56297db0907aa815bffefa..3a7271ec4723b855ad0b40f988d20fad2b49c7e6 100644 (file)
@@ -56,6 +56,7 @@ ATAIdentify (
   EFI_IDENTIFY_DATA *AtaIdentifyPointer;\r
   UINT32            Capacity;\r
   UINT8             DeviceSelect;\r
+  UINTN                                Retry;\r
 \r
   //\r
   //  AtaIdentifyPointer is used for accommodating returned IDENTIFY data of\r
@@ -68,81 +69,101 @@ ATAIdentify (
   //  and receive data from device\r
   //\r
   DeviceSelect  = (UINT8) ((IdeDev->Device) << 4);\r
-  Status = AtaPioDataIn (\r
-            IdeDev,\r
-            (VOID *) AtaIdentifyPointer,\r
-            sizeof (EFI_IDENTIFY_DATA),\r
-            ATA_CMD_IDENTIFY_DRIVE,\r
-            DeviceSelect,\r
-            0,\r
-            0,\r
-            0,\r
-            0\r
-            );\r
-  //\r
-  // If ATA Identify command succeeds, then according to the received\r
-  // IDENTIFY data,\r
-  // identify the device type ( ATA or not ).\r
-  // If ATA device, fill the information in IdeDev.\r
-  // If not ATA device, return IDE_DEVICE_ERROR\r
-  //\r
-  if (!EFI_ERROR (Status)) {\r
-\r
-    IdeDev->pIdData = AtaIdentifyPointer;\r
 \r
+  \r
+  Retry = 3;\r
+  while (Retry > 0) {  \r
+    Status = AtaPioDataIn (\r
+              IdeDev,\r
+              (VOID *) AtaIdentifyPointer,\r
+              sizeof (EFI_IDENTIFY_DATA),\r
+              ATA_CMD_IDENTIFY_DRIVE,\r
+              DeviceSelect,\r
+              0,\r
+              0,\r
+              0,\r
+              0\r
+              );\r
     //\r
-    // Print ATA Module Name\r
+    // If ATA Identify command succeeds, then according to the received\r
+    // IDENTIFY data,\r
+    // identify the device type ( ATA or not ).\r
+    // If ATA device, fill the information in IdeDev.\r
+    // If not ATA device, return IDE_DEVICE_ERROR\r
     //\r
-    PrintAtaModuleName (IdeDev);\r
+    if (!EFI_ERROR (Status)) {\r
+\r
+      IdeDev->pIdData = AtaIdentifyPointer;\r
 \r
-    //\r
-    // bit 15 of pAtaIdentify->config is used to identify whether device is\r
-    // ATA device or ATAPI device.\r
-    // if 0, means ATA device; if 1, means ATAPI device.\r
-    //\r
-    if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) {\r
       //\r
-      // Detect if support S.M.A.R.T. If yes, enable it as default\r
+      // Print ATA Module Name\r
       //\r
-      AtaSMARTSupport (IdeDev);\r
+      PrintAtaModuleName (IdeDev);\r
 \r
       //\r
-      // Check whether this device needs 48-bit addressing (ATAPI-6 ata device)\r
+      // bit 15 of pAtaIdentify->config is used to identify whether device is\r
+      // ATA device or ATAPI device.\r
+      // if 0, means ATA device; if 1, means ATAPI device.\r
       //\r
-      Status = AtaAtapi6Identify (IdeDev);\r
-      if (!EFI_ERROR (Status)) {\r
+      if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) {\r
         //\r
-        // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify()\r
+        // Detect if support S.M.A.R.T. If yes, enable it as default\r
         //\r
-        return EFI_SUCCESS;\r
-      }\r
-      //\r
-      // This is a hard disk <= 120GB capacity, treat it as normal hard disk\r
-      //\r
-      IdeDev->Type = IdeHardDisk;\r
+        AtaSMARTSupport (IdeDev);\r
 \r
-      //\r
-      // Block Media Information:\r
-      // Media->LogicalPartition , Media->WriteCaching will be filled\r
-      // in the DiscoverIdeDevcie() function.\r
-      //\r
-      IdeDev->BlkIo.Media->IoAlign        = 4;\r
-      IdeDev->BlkIo.Media->MediaId        = 1;\r
-      IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
-      IdeDev->BlkIo.Media->MediaPresent   = TRUE;\r
-      IdeDev->BlkIo.Media->ReadOnly       = FALSE;\r
-      IdeDev->BlkIo.Media->BlockSize      = 0x200;\r
+        //\r
+        // Check whether this device needs 48-bit addressing (ATAPI-6 ata device)\r
+        //\r
+        Status = AtaAtapi6Identify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          //\r
+          // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify()\r
+          //\r
+          return EFI_SUCCESS;\r
+        } else if (Status == EFI_DEVICE_ERROR) {\r
+                 //\r
+                 // Some disk with big capacity (>200GB) is slow when being identified\r
+                 // and will return all zero for word83.\r
+                 // We try twice at first. If it fails, we do a SoftRest and try again.\r
+                 //\r
+                 Retry--;\r
+                 if (Retry == 1) {\r
+                   //\r
+                   // Do a SoftRest before the third attempt.\r
+                   //\r
+                   AtaSoftReset (IdeDev);\r
+                 }\r
+                 continue;\r
+           }\r
+        //\r
+        // This is a hard disk <= 120GB capacity, treat it as normal hard disk\r
+        //\r
+        IdeDev->Type = IdeHardDisk;\r
 \r
-      //\r
-      // Calculate device capacity\r
-      //\r
-      Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) |\r
+        //\r
+        // Block Media Information:\r
+        // Media->LogicalPartition , Media->WriteCaching will be filled\r
+        // in the DiscoverIdeDevcie() function.\r
+        //\r
+        IdeDev->BlkIo.Media->IoAlign        = 4;\r
+        IdeDev->BlkIo.Media->MediaId        = 1;\r
+        IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
+        IdeDev->BlkIo.Media->MediaPresent   = TRUE;\r
+        IdeDev->BlkIo.Media->ReadOnly       = FALSE;\r
+        IdeDev->BlkIo.Media->BlockSize      = 0x200;\r
+\r
+        //\r
+        // Calculate device capacity\r
+        //\r
+        Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) |\r
                   AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ;\r
-      IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r
+        IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r
 \r
-      return EFI_SUCCESS;\r
+        return EFI_SUCCESS;\r
+      }\r
 \r
     }\r
+       break;\r
   }\r
 \r
   gBS->FreePool (AtaIdentifyPointer);\r
@@ -167,8 +188,9 @@ ATAIdentify (
   and 48-bit addressing must be used\r
 \r
   @retval  EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but\r
-  the capacity is below 120G, 48bit addressing is not\r
-  needed\r
+  the capacity is below 120G, 48bit addressing is not needed\r
+\r
+  @retval  EFI_DEVICE_ERROR The identify data in IdeDev is incorrect\r
 \r
   @note\r
   This function must be called after DEVICE_IDENTITY command has been\r
@@ -191,6 +213,13 @@ AtaAtapi6Identify (
 \r
   Atapi6IdentifyStruct = IdeDev->pIdData;\r
 \r
+  if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & (BIT15 | BIT14)) != 0x4000) {\r
+    //\r
+    // Per ATA-6 spec, word83: bit15 is zero and bit14 is one\r
+    //\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
   if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & BIT10) == 0) {\r
     //\r
     // The device dosn't support 48 bit addressing\r
@@ -2298,18 +2327,17 @@ DoAtaUdma (
   }\r
 \r
   //\r
-  // Channel and device differential\r
+  // Select device\r
   //\r
   Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
 \r
   //\r
-  // Enable interrupt to support UDMA and Select device\r
+  // Enable interrupt to support UDMA\r
   //\r
   DeviceControl = 0;\r
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
 \r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
-\r
   if (IdePrimary == IdeDev->Channel) {\r
     IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
     IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
@@ -2324,6 +2352,31 @@ DoAtaUdma (
     }\r
   }\r
 \r
+  //\r
+  // Read BMIS register and clear ERROR and INTR bit\r
+  //\r
+  IdeDev->PciIo->Io.Read (\r
+                                         IdeDev->PciIo,\r
+                                         EfiPciIoWidthUint8,\r
+                                         EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                                         IoPortForBmis,\r
+                                         1,\r
+                                         &RegisterValue\r
+                                         );\r
+  \r
+  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+  \r
+  IdeDev->PciIo->Io.Write (\r
+                                         IdeDev->PciIo,\r
+                                         EfiPciIoWidthUint8,\r
+                                         EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                                         IoPortForBmis,\r
+                                         1,\r
+                                         &RegisterValue\r
+                                         );\r
+\r
+  Status = EFI_SUCCESS;\r
+  \r
   RemainBlockNum = NumberOfBlocks;\r
   while (RemainBlockNum > 0) {\r
 \r
@@ -2452,29 +2505,6 @@ DoAtaUdma (
                         &RegisterValue\r
                         );\r
 \r
-    //\r
-    // Read BMIS register and clear ERROR and INTR bit\r
-    //\r
-    IdeDev->PciIo->Io.Read (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmis,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\r
-\r
-    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-\r
-    IdeDev->PciIo->Io.Write (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmis,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\r
-\r
     if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {\r
       Status = AtaCommandIssueExt (\r
                  IdeDev,\r
@@ -2530,6 +2560,7 @@ DoAtaUdma (
     // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
     // So set the variable Count to 2000, for about 2 second timeout time.\r
     //\r
+    Status = EFI_SUCCESS;\r
     Count = 2000;\r
     while (TRUE) {\r
 \r
@@ -2543,31 +2574,8 @@ DoAtaUdma (
                           );\r
       if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {\r
         if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {\r
-          //\r
-          // Clear START bit of BMIC register before return EFI_DEVICE_ERROR\r
-          //\r
-          IdeDev->PciIo->Io.Read (\r
-                              IdeDev->PciIo,\r
-                              EfiPciIoWidthUint8,\r
-                              EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                              IoPortForBmic,\r
-                              1,\r
-                              &RegisterValue\r
-                              );\r
-\r
-          RegisterValue &= ~((UINT8)BMIC_START);\r
-\r
-          IdeDev->PciIo->Io.Write (\r
-                              IdeDev->PciIo,\r
-                              EfiPciIoWidthUint8,\r
-                              EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                              IoPortForBmic,\r
-                              1,\r
-                              &RegisterValue\r
-                              );\r
-          IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
-          IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
-          return EFI_DEVICE_ERROR;\r
+                 Status = EFI_DEVICE_ERROR;\r
+                 break;\r
         }\r
         break;\r
       }\r
@@ -2579,6 +2587,28 @@ DoAtaUdma (
     IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
     IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
     //\r
+    // Read BMIS register and clear ERROR and INTR bit\r
+    //\r
+    IdeDev->PciIo->Io.Read (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmis,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+\r
+    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmis,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+       //\r
     // Read Status Register of IDE device to clear interrupt\r
     //\r
     RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r
@@ -2609,6 +2639,9 @@ DoAtaUdma (
       return EFI_DEVICE_ERROR;\r
     }\r
 \r
+       if (EFI_ERROR (Status)) {\r
+         break;\r
+       }\r
     DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
     StartLba += NumberOfBlocks;\r
   }\r
@@ -2620,5 +2653,6 @@ DoAtaUdma (
   DeviceControl |= ATA_CTLREG_IEN_L;\r
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
+\r