]> git.proxmox.com Git - mirror_smartmontools-debian.git/blobdiff - atacmds.cpp
Imported Upstream version 5.39.1+svn3077
[mirror_smartmontools-debian.git] / atacmds.cpp
index 06024e5231b195b34ce9c161cedf3685af7d64dd..663a5854dd7713583a2bde1eef35cc7aaf2c7703 100644 (file)
@@ -37,7 +37,7 @@
 #include "utility.h"
 #include "dev_ata_cmd_set.h" // for parsed_ata_device
 
-const char * atacmds_cpp_cvsid = "$Id: atacmds.cpp 3040 2010-01-18 20:57:39Z chrfranke $"
+const char * atacmds_cpp_cvsid = "$Id: atacmds.cpp 3065 2010-02-10 22:16:50Z chrfranke $"
                                  ATACMDS_H_CVSID;
 
 // for passing global control variables
@@ -2214,6 +2214,13 @@ int ataReadSCTTempHist(ata_device * device, ata_sct_temperature_history_table *
   cmd.function_code = 1; // Read table
   cmd.table_id      = 2; // Temperature History Table
 
+  // swap endian order if needed
+  if (isbigendian()) {
+    swapx(&cmd.action_code);
+    swapx(&cmd.function_code);
+    swapx(&cmd.table_id);
+  }
+
   // write command via SMART log page 0xe0
   if (smartcommandhandler(device, WRITE_LOG, 0xe0, (char *)&cmd)){
     syserror("Error Write SCT Data Table command failed");
@@ -2276,6 +2283,15 @@ int ataSetSCTTempInterval(ata_device * device, unsigned interval, bool persisten
   cmd.state         = interval;
   cmd.option_flags  = (persistent ? 0x01 : 0x00);
 
+  // swap endian order if needed
+  if (isbigendian()) {
+    swapx(&cmd.action_code);
+    swapx(&cmd.function_code);
+    swapx(&cmd.feature_code);
+    swapx(&cmd.state);
+    swapx(&cmd.option_flags);
+  }
+
   // write command via SMART log page 0xe0
   if (smartcommandhandler(device, WRITE_LOG, 0xe0, (char *)&cmd)){
     syserror("Error Write SCT Feature Control Command failed");
@@ -2294,6 +2310,96 @@ int ataSetSCTTempInterval(ata_device * device, unsigned interval, bool persisten
   return 0;
 }
 
+// Get/Set SCT Error Recovery Control
+static int ataGetSetSCTErrorRecoveryControltime(ata_device * device, unsigned type,
+                                                bool set, unsigned short & time_limit)
+{
+  // Check initial status
+  ata_sct_status_response sts;
+  if (ataReadSCTStatus(device, &sts))
+    return -1;
+
+  // Do nothing if other SCT command is executing
+  if (sts.ext_status_code == 0xffff) {
+    pout("Another SCT command is executing, abort Error Recovery Control\n"
+         "(SCT ext_status_code 0x%04x, action_code=%u, function_code=%u)\n",
+      sts.ext_status_code, sts.action_code, sts.function_code);
+    return -1;
+  }
+
+  ata_sct_error_recovery_control_command cmd; memset(&cmd, 0, sizeof(cmd));
+  // CAUTION: DO NOT CHANGE THIS VALUE (SOME ACTION CODES MAY ERASE DISK)
+  cmd.action_code    = 3; // Error Recovery Control command
+  cmd.function_code  = (set ? 1 : 2); // 1=Set timer, 2=Get timer
+  cmd.selection_code = type; // 1=Read timer, 2=Write timer
+  if (set)
+    cmd.time_limit   = time_limit;
+
+  // swap endian order if needed
+  if (isbigendian()) {
+    swapx(&cmd.action_code);
+    swapx(&cmd.function_code);
+    swapx(&cmd.selection_code);
+    swapx(&cmd.time_limit);
+  }
+
+  // write command via SMART log page 0xe0
+  // TODO: Debug output
+  ata_cmd_in in;
+  in.in_regs.command = ATA_SMART_CMD;
+  in.in_regs.lba_high = SMART_CYL_HI; in.in_regs.lba_mid = SMART_CYL_LOW;
+  in.in_regs.features = ATA_SMART_WRITE_LOG_SECTOR;
+  in.in_regs.lba_low = 0xe0;
+  in.set_data_out(&cmd, 1);
+
+  if (!set)
+    // Time limit returned in ATA registers
+    in.out_needed.sector_count = in.out_needed.lba_low = true;
+
+  ata_cmd_out out;
+  if (!device->ata_pass_through(in, out)) {
+    pout("Error Write SCT Error Recovery Control Command failed: %s\n", device->get_errmsg());
+    return -1;
+  }
+
+  // re-read and check SCT status
+  if (ataReadSCTStatus(device, &sts))
+    return -1;
+
+  if (!(sts.ext_status_code == 0 && sts.action_code == 3 && sts.function_code == (set ? 1 : 2))) {
+    pout("Error unexcepted SCT status 0x%04x (action_code=%u, function_code=%u)\n",
+      sts.ext_status_code, sts.action_code, sts.function_code);
+    return -1;
+  }
+
+  if (!set) {
+    // Check whether registers are properly returned by ioctl()
+    if (!(out.out_regs.sector_count.is_set() && out.out_regs.lba_low.is_set())) {
+      // TODO: Output register support should be checked within each ata_pass_through()
+      // implementation before command is issued.
+      pout("Error SMART WRITE LOG does not return COUNT and LBA_LOW register\n");
+      return -1;
+    }
+    // Return value to caller
+    time_limit = out.out_regs.sector_count | (out.out_regs.lba_low << 8);
+  }
+
+  return 0;
+}
+
+// Get SCT Error Recovery Control
+int ataGetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsigned short & time_limit)
+{
+  return ataGetSetSCTErrorRecoveryControltime(device, type, false/*get*/, time_limit);
+}
+
+// Set SCT Error Recovery Control
+int ataSetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsigned short time_limit)
+{
+  return ataGetSetSCTErrorRecoveryControltime(device, type, true/*set*/, time_limit);
+}
+
+
 // Print one self-test log entry.
 // Returns true if self-test showed an error.
 bool ataPrintSmartSelfTestEntry(unsigned testnum, unsigned char test_type,