]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
S.M.A.R.T feature enable
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
index 06b280a001af3f48506388228f29c4f557629822..92449f40c6b602da49db3c234fb0a7cbbef6eada 100644 (file)
@@ -1249,6 +1249,191 @@ AhciReset (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
+\r
+  @param  PciIo               The PCI IO protocol instance.\r
+  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port                The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param  AtaStatusBlock      A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+  @retval EFI_SUCCESS     Successfully get the return status of S.M.A.R.T command execution.\r
+  @retval Others          Fail to get return status data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciAtaSmartReturnStatusCheck (\r
+  IN EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  IN EFI_AHCI_REGISTERS          *AhciRegisters,\r
+  IN UINT8                       Port,\r
+  IN UINT8                       PortMultiplier,\r
+  IN OUT EFI_ATA_STATUS_BLOCK    *AtaStatusBlock\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_ATA_COMMAND_BLOCK   AtaCommandBlock;\r
+  UINT8                   LBAMid;\r
+  UINT8                   LBAHigh;\r
+  UINTN                   FisBaseAddr;\r
+  UINT32                  Value;\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+  AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;\r
+  AtaCommandBlock.AtaFeatures     = ATA_SMART_RETURN_STATUS;\r
+  AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;\r
+  AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+  //\r
+  // Send S.M.A.R.T Read Return Status command to device\r
+  //\r
+  Status = AhciNonDataTransfer (\r
+             PciIo,\r
+             AhciRegisters,\r
+             (UINT8)Port,\r
+             (UINT8)PortMultiplier,\r
+             NULL,\r
+             0,\r
+             &AtaCommandBlock,\r
+             AtaStatusBlock,\r
+             ATA_ATAPI_TIMEOUT\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+\r
+  Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
+\r
+  if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
+    LBAMid  = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];\r
+    LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];\r
+\r
+    if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
+      //\r
+      // The threshold exceeded condition is not detected by the device\r
+      //\r
+      DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
+\r
+    } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
+      //\r
+      // The threshold exceeded condition is detected by the device\r
+      //\r
+      DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Enable SMART command of the disk if supported.\r
+\r
+  @param  PciIo               The PCI IO protocol instance.\r
+  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port                The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param  IdentifyData        A pointer to data buffer which is used to contain IDENTIFY data.\r
+  @param  AtaStatusBlock      A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciAtaSmartSupport (\r
+  IN EFI_PCI_IO_PROTOCOL           *PciIo,\r
+  IN EFI_AHCI_REGISTERS            *AhciRegisters,\r
+  IN UINT8                         Port,\r
+  IN UINT8                         PortMultiplier,\r
+  IN EFI_IDENTIFY_DATA             *IdentifyData,  \r
+  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_ATA_COMMAND_BLOCK    AtaCommandBlock;\r
+\r
+  //\r
+  // Detect if the device supports S.M.A.R.T.\r
+  //\r
+  if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
+    //\r
+    // S.M.A.R.T is not supported by the device\r
+    //\r
+    DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n", \r
+            Port, PortMultiplier));\r
+  } else {\r
+    //\r
+    // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
+    //\r
+    if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
+      ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+      AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;\r
+      AtaCommandBlock.AtaFeatures     = ATA_SMART_ENABLE_OPERATION;\r
+      AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;\r
+      AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+      //\r
+      // Send S.M.A.R.T Enable command to device\r
+      //\r
+      Status = AhciNonDataTransfer (\r
+                 PciIo,\r
+                 AhciRegisters,\r
+                 (UINT8)Port,\r
+                 (UINT8)PortMultiplier,\r
+                 NULL,\r
+                 0,\r
+                 &AtaCommandBlock,\r
+                 AtaStatusBlock,\r
+                 ATA_ATAPI_TIMEOUT\r
+                 );\r
+\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Send S.M.A.R.T AutoSave command to device\r
+        //\r
+        ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+        AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;\r
+        AtaCommandBlock.AtaFeatures     = 0xD2;\r
+        AtaCommandBlock.AtaSectorCount  = 0xF1;\r
+        AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;\r
+        AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+        Status = AhciNonDataTransfer (\r
+                   PciIo,\r
+                   AhciRegisters,\r
+                   (UINT8)Port,\r
+                   (UINT8)PortMultiplier,\r
+                   NULL,\r
+                   0,\r
+                   &AtaCommandBlock,\r
+                   AtaStatusBlock,\r
+                   ATA_ATAPI_TIMEOUT\r
+                   );\r
+\r
+        if (!EFI_ERROR (Status)) {\r
+          Status = AhciAtaSmartReturnStatusCheck (\r
+                     PciIo,\r
+                     AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplier,\r
+                     AtaStatusBlock\r
+                     );\r
+        }\r
+      }\r
+    }\r
+    DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n", \r
+            Port, PortMultiplier));\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
 /**\r
   Send Buffer cmd to specific device.\r
     \r
@@ -1947,6 +2132,20 @@ AhciModeInitialization (
         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