]> git.proxmox.com Git - mirror_edk2.git/commitdiff
S.M.A.R.T feature enable
authorerictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 28 Oct 2010 07:44:11 +0000 (07:44 +0000)
committererictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 28 Oct 2010 07:44:11 +0000 (07:44 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10985 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.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
index bdbf3ab450c7d9638e837bd979799292a56b3a16..50b95a6713263bb2d00e8d6c2e49c52b339d91f8 100644 (file)
@@ -2090,6 +2090,170 @@ SetDriveParameters (
   return Status;\r
 }\r
 \r
+/**\r
+  Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
+\r
+  @param Instance         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param Channel          The channel number of device.\r
+  @param Device           The device number of device.\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
+IdeAtaSmartReturnStatusCheck (\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN     UINT8                         Channel,\r
+  IN     UINT8                         Device,\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
+\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
+  AtaCommandBlock.AtaDeviceHead   = (UINT8) ((Device << 0x4) | 0xe0);\r
+\r
+  //\r
+  // Send S.M.A.R.T Read Return Status command to device\r
+  //\r
+  Status = AtaNonDataCommandIn (\r
+             Instance->PciIo,\r
+             &Instance->IdeRegisters[Channel],\r
+             &AtaCommandBlock,\r
+             AtaStatusBlock,\r
+             ATA_ATAPI_TIMEOUT\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  LBAMid  = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderLsb);\r
+  LBAHigh = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderMsb);\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
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Enable SMART command of the disk if supported.\r
+\r
+  @param Instance         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param Channel          The channel number of device.\r
+  @param Device           The device number of device.\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
+IdeAtaSmartSupport (\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN     UINT8                         Channel,\r
+  IN     UINT8                         Device,\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 [%a] channel [%a] device!\n", \r
+            (Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));\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
+\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
+      AtaCommandBlock.AtaDeviceHead   = (UINT8) ((Device << 0x4) | 0xe0);\r
+\r
+      //\r
+      // Send S.M.A.R.T Enable command to device\r
+      //\r
+      Status = AtaNonDataCommandIn (\r
+                 Instance->PciIo,\r
+                 &Instance->IdeRegisters[Channel],\r
+                 &AtaCommandBlock,\r
+                 AtaStatusBlock,\r
+                 ATA_ATAPI_TIMEOUT\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
+        AtaCommandBlock.AtaDeviceHead   = (UINT8) ((Device << 0x4) | 0xe0);\r
+\r
+        Status = AtaNonDataCommandIn (\r
+                   Instance->PciIo,\r
+                   &Instance->IdeRegisters[Channel],\r
+                   &AtaCommandBlock,\r
+                   AtaStatusBlock,\r
+                   ATA_ATAPI_TIMEOUT\r
+                   );\r
+        if (!EFI_ERROR (Status)) {\r
+          Status = IdeAtaSmartReturnStatusCheck (\r
+                     Instance,\r
+                     Channel,\r
+                     Device,\r
+                     AtaStatusBlock\r
+                     );\r
+        }\r
+      }\r
+    }\r
+\r
+    DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at [%a] channel [%a] device!\n", \r
+           (Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));\r
+\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
 /**\r
   Sends out an ATA Identify Command to the specified device.\r
 \r
@@ -2333,6 +2497,19 @@ DetectAndConfigIdeDevice (
             (IdeChannel == 1) ? "secondary" : "primary  ", (IdeDevice == 1) ? "slave " : "master",\r
             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
+      IdeAtaSmartSupport (\r
+        Instance,\r
+        IdeChannel,\r
+        IdeDevice,\r
+        &Buffer,\r
+        NULL\r
+        );\r
+    }\r
+\r
     //\r
     // Submit identify data to IDE controller init driver\r
     //\r