diff --git a/smartmontools/CHANGELOG b/smartmontools/CHANGELOG
index 81f67a8701cb28514bb6a4915f42f68dba489d1e..825abeea5f3bd6857d741ae4b798c5e008c01825 100644
--- a/smartmontools/CHANGELOG
+++ b/smartmontools/CHANGELOG
@@ -43,13 +43,17 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [CF] Rework ATA SMART attribute check in smartctl and smartd.
+       smartd: Ignore normalized attribute value and threshold
+       if 'raw64' or 'hex64' format is selected.
+
   [CF] Add USB IDs of Iomega LPHD080-0, 2 Genesys Logic bridges and
        Initio 316000.
 
   [MS] knowndrives.cpp update: Hitachi Travelstar 5K320 series
 
   [CF] smartctl: Ignore normalized attribute value and threshold
-       if 'raw64' or 'hex24' format is selected.
+       if 'raw64' or 'hex64' format is selected.
 
   [CF] knowndrives.cpp updates:
        - add OCZ-Vertex raw64 attributes
diff --git a/smartmontools/atacmds.cpp b/smartmontools/atacmds.cpp
index ff2e2282a360fbc4a5dab569601fd0a889b742d9..c218cf0a21537ddc4ff1c5214c6bcfea39207126 100644
--- a/smartmontools/atacmds.cpp
+++ b/smartmontools/atacmds.cpp
@@ -1703,37 +1703,45 @@ int isSupportSelectiveSelfTest(const ata_smart_values * data)
    return data->offline_data_collection_capability & 0x40;
 }
 
-// This checks the n'th attribute in the attribute list, NOT the
-// attribute with id==n.  If the attribute does not exist, or the
-// attribute is > threshold, then returns zero.  If the attribute is
-// <= threshold (failing) then we the attribute number if it is a
-// prefail attribute.  Else we return minus the attribute number if it
-// is a usage attribute.
-int ataCheckAttribute(const ata_smart_values * data,
-                      const ata_smart_thresholds_pvt * thresholds,
-                      int n)
-{
-  if (n<0 || n>=NUMBER_ATA_SMART_ATTRIBUTES || !data || !thresholds)
-    return 0;
-  
-  // pointers to disk's values and vendor's thresholds
-  const ata_smart_attribute * disk = data->vendor_attributes+n;
-  const ata_smart_threshold_entry * thre = thresholds->thres_entries+n;
+// Get attribute state
+ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
+                                  const ata_smart_threshold_entry & thre,
+                                  const ata_vendor_attr_defs & defs)
+{
+  if (!attr.id)
+    return ATTRSTATE_NON_EXISTING;
 
-  if (!disk || !thre)
-    return 0;
-  
-  // consider only valid attributes, check for failure
-  if (!disk->id || !thre->id || (disk->id != thre->id) || disk->current> thre->threshold)
-    return 0;
-  
-  // We have found a failed attribute.  Return positive or negative? 
-  if (ATTRIBUTE_FLAGS_PREFAILURE(disk->flags))
-    return disk->id;
-  else
-    return -1*(disk->id);
-}
+  // Normalized values (current,worst,threshold) not valid
+  // if specified by '-v' option.
+  // (Some SSD disks uses these bytes to store raw value).
+  if (defs[attr.id].flags & ATTRFLAG_NO_NORMVAL)
+    return ATTRSTATE_NO_NORMVAL;
+
+  // No threshold if thresholds cannot be read.
+  if (!thre.id && !thre.threshold)
+    return ATTRSTATE_NO_THRESHOLD;
+
+  // Bad threshold if id's don't match
+  if (attr.id != thre.id)
+    return ATTRSTATE_BAD_THRESHOLD;
+
+  // Don't report a failed attribute if its threshold is 0.
+  // ATA-3 (X3T13/2008D Revision 7b) declares 0x00 as the "always passing"
+  // threshold (Later ATA versions declare all thresholds as "obsolete").
+  // In practice, threshold value 0 is often used for usage attributes.
+  if (!thre.threshold)
+    return ATTRSTATE_OK;
 
+  // Failed now if current value is below threshold
+  if (attr.current <= thre.threshold)
+    return ATTRSTATE_FAILED_NOW;
+
+  // Failed in the passed if worst value is below threshold
+  if (attr.worst <= thre.threshold)
+    return ATTRSTATE_FAILED_PAST;
+
+  return ATTRSTATE_OK;
+}
 
 // Get default raw value print format
 static ata_attr_raw_format get_default_raw_format(unsigned char id)
@@ -1755,18 +1763,13 @@ static ata_attr_raw_format get_default_raw_format(unsigned char id)
   }
 }
 
-// Format attribute raw value.
-std::string ata_format_attr_raw_value(const ata_smart_attribute & attribute,
-                                      const ata_vendor_attr_defs & defs)
+// Get attribute raw value.
+uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr,
+                                const ata_vendor_attr_defs & defs)
 {
-  // Get print format
-  ata_attr_raw_format format = defs[attribute.id].raw_format;
-  if (format == RAWFMT_DEFAULT)
-    format = get_default_raw_format(attribute.id);
-
   // Get 48 bit raw value
-  const unsigned char * raw = attribute.raw;
-  int64_t rawvalue;
+  const unsigned char * raw = attr.raw;
+  uint64_t rawvalue;
   rawvalue =              raw[0]
              | (          raw[1] <<  8)
              | (          raw[2] << 16)
@@ -1774,12 +1777,37 @@ std::string ata_format_attr_raw_value(const ata_smart_attribute & attribute,
              | ((uint64_t)raw[4] << 32)
              | ((uint64_t)raw[5] << 40);
 
+  if (defs[attr.id].flags & ATTRFLAG_NO_NORMVAL) {
+    // Some SSD vendors use bytes 3-10 from the Attribute
+    // Data Structure to store a 64-bit raw value.
+    rawvalue <<= 8;
+    rawvalue |= attr.worst;
+    rawvalue <<= 8;
+    rawvalue |= attr.current;
+  }
+  return rawvalue;
+}
+
+
+// Format attribute raw value.
+std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
+                                      const ata_vendor_attr_defs & defs)
+{
+  // Get 48 bit or64 bit raw value
+  uint64_t rawvalue = ata_get_attr_raw_value(attr, defs);
+
   // Get 16 bit words
+  const unsigned char * raw = attr.raw;
   unsigned word[3];
   word[0] = raw[0] | (raw[1] << 8);
   word[1] = raw[2] | (raw[3] << 8);
   word[2] = raw[4] | (raw[5] << 8);
 
+  // Get print format
+  ata_attr_raw_format format = defs[attr.id].raw_format;
+  if (format == RAWFMT_DEFAULT)
+    format = get_default_raw_format(attr.id);
+
   // Print
   std::string s;
   switch (format) {
@@ -1801,18 +1829,11 @@ std::string ata_format_attr_raw_value(const ata_smart_attribute & attribute,
     break;
 
   case RAWFMT_RAW64:
+    s = strprintf("%"PRIu64, rawvalue);
+    break;
+
   case RAWFMT_HEX64:
-    // Some SSD vendors use bytes 3-10 from the Attribute
-    // Data Structure to store a 64-bit raw value.
-    // TODO: Do not print VALUE/WORST/THRESH in attribute table.
-    rawvalue <<= 8;
-    rawvalue |= attribute.worst;
-    rawvalue <<= 8;
-    rawvalue |= attribute.current;
-    if (format == RAWFMT_RAW64)
-      s = strprintf("%"PRIu64, rawvalue);
-    else
-      s = strprintf("0x%016"PRIx64, rawvalue);
+    s = strprintf("0x%016"PRIx64, rawvalue);
     break;
 
   case RAWFMT_RAW16_OPT_RAW16:
@@ -2068,38 +2089,15 @@ std::string ata_get_smart_attr_name(unsigned char id, const ata_vendor_attr_defs
     return get_default_attr_name(id);
 }
 
-// Returns raw value of Attribute with ID==id. This will be in the
-// range 0 to 2^48-1 inclusive.  If the Attribute does not exist,
-// return -1.
-int64_t ATAReturnAttributeRawValue(unsigned char id, const ata_smart_values * data)
+// Find attribute index for attribute id, -1 if not found.
+int ata_find_attr_index(unsigned char id, const ata_smart_values & smartval)
 {
-  // valid Attribute IDs are in the range 1 to 255 inclusive.
-  if (!id || !data)
+  if (!id)
     return -1;
-  
-  // loop over Attributes to see if there is one with the desired ID
   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
-    const ata_smart_attribute * ap = data->vendor_attributes + i;
-    if (ap->id == id) {
-      // we've found the desired Attribute.  Return its value
-      int64_t rawvalue=0;
-      int j;
-
-      for (j=0; j<6; j++) {
-	// This looks a bit roundabout, but is necessary.  Don't
-	// succumb to the temptation to use raw[j]<<(8*j) since under
-	// the normal rules this will be promoted to the native type.
-	// On a 32 bit machine this might then overflow.
-	int64_t temp;
-	temp = ap->raw[j];
-	temp <<= 8*j;
-	rawvalue |= temp;
-      } // loop over j
-      return rawvalue;
-    } // found desired Attribute
-  } // loop over Attributes
-  
-  // fall-through: no such Attribute found
+    if (smartval.vendor_attributes[i].id == id)
+      return i;
+  }
   return -1;
 }
 
@@ -2114,9 +2112,10 @@ unsigned char ata_return_temperature_value(const ata_smart_values * data, const
     if (!(   (id == 194 && format == RAWFMT_DEFAULT)
           || format == RAWFMT_TEMPMINMAX || format == RAWFMT_TEMP10X))
       continue;
-    int64_t raw = ATAReturnAttributeRawValue(id, data);
-    if (raw < 0)
+    int idx = ata_find_attr_index(id, *data);
+    if (idx < 0)
       continue;
+    uint64_t raw = ata_get_attr_raw_value(data->vendor_attributes[idx], defs);
     unsigned temp = (unsigned short)raw; // ignore possible min/max values in high words
     if (format == RAWFMT_TEMP10X) // -v N,temp10x
       temp = (temp+5) / 10;
diff --git a/smartmontools/atacmds.h b/smartmontools/atacmds.h
index 2fea4126ca2eb045a2b1b0637735d315f7058ce3..8d5279d35990aa0bfbec86f8c11dcf4dcfb65c9a 100644
--- a/smartmontools/atacmds.h
+++ b/smartmontools/atacmds.h
@@ -798,34 +798,43 @@ int ataSmartTest(ata_device * device, int testtype, const ata_selective_selftest
 
 int TestTime(const ata_smart_values * data, int testtype);
 
+// Attribute state
+enum ata_attr_state
+{
+  ATTRSTATE_NON_EXISTING,   // No such Attribute
+  ATTRSTATE_NO_NORMVAL,     // Normalized value not valid
+  ATTRSTATE_BAD_THRESHOLD,  // Threshold not valid
+  ATTRSTATE_NO_THRESHOLD,   // Unknown or no threshold
+  ATTRSTATE_OK,             // Never failed
+  ATTRSTATE_FAILED_PAST,    // Failed in the past
+  ATTRSTATE_FAILED_NOW      // Failed now
+};
+
+// Get attribute state
+ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
+                                  const ata_smart_threshold_entry & thre,
+                                  const ata_vendor_attr_defs & defs);
+
+// Get attribute raw value.
+uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr,
+                                const ata_vendor_attr_defs & defs);
+
 // Format attribute raw value.
-std::string ata_format_attr_raw_value(const ata_smart_attribute & attribute,
+std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
                                       const ata_vendor_attr_defs & defs);
 
 // Get attribute name
 std::string ata_get_smart_attr_name(unsigned char id,
                                     const ata_vendor_attr_defs & defs);
 
-// This checks the n'th attribute in the attribute list, NOT the
-// attribute with id==n.  If the attribute does not exist, or the
-// attribute is > threshold, then returns zero.  If the attribute is
-// <= threshold (failing) then we the attribute number if it is a
-// prefail attribute.  Else we return minus the attribute number if it
-// is a usage attribute.
-int ataCheckAttribute(const ata_smart_values * data,
-                      const ata_smart_thresholds_pvt * thresholds,
-                      int n);
-
 // External handler function, for when a checksum is not correct.  Can
 // simply return if no action is desired, or can print error messages
 // as needed, or exit.  Is passed a string with the name of the Data
 // Structure with the incorrect checksum.
 void checksumwarning(const char *string);
 
-// Returns raw value of Attribute with ID==id. This will be in the
-// range 0 to 2^48-1 inclusive.  If the Attribute does not exist,
-// return -1.
-int64_t ATAReturnAttributeRawValue(unsigned char id, const ata_smart_values * data);
+// Find attribute index for attribute id, -1 if not found.
+int ata_find_attr_index(unsigned char id, const ata_smart_values & smartval);
 
 // Return Temperature Attribute raw value selected according to possible
 // non-default interpretations. If the Attribute does not exist, return 0
diff --git a/smartmontools/ataprint.cpp b/smartmontools/ataprint.cpp
index 9935206c074dfaac87fa6e73b7ce8318ab61c583..258c11f102a40012efe823b7e21869394b83a18b 100644
--- a/smartmontools/ataprint.cpp
+++ b/smartmontools/ataprint.cpp
@@ -781,22 +781,19 @@ static int find_failed_attr(const ata_smart_values * data,
                             const ata_vendor_attr_defs & defs, int onlyfailed)
 {
   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
-    const ata_smart_attribute * disk = data->vendor_attributes+i;
-    const ata_smart_threshold_entry * thre = thresholds->thres_entries+i;
+    const ata_smart_attribute & attr = data->vendor_attributes[i];
 
-    // consider only valid attributes
-    if (!(disk->id && disk->id == thre->id && thre->threshold
-          && !(defs[disk->id].flags & ATTRFLAG_NO_NORMVAL)   ))
-      continue;
-
-    bool failednow  = (disk->current <= thre->threshold);
-    bool failedever = (disk->worst   <= thre->threshold);
+    ata_attr_state state = ata_get_attr_state(attr,
+                             thresholds->thres_entries[i], defs);
 
-    if (!onlyfailed && failedever)
-      return disk->id;
-
-    if (onlyfailed && failednow && ATTRIBUTE_FLAGS_PREFAILURE(disk->flags))
-      return disk->id;
+    if (!onlyfailed) {
+      if (state >= ATTRSTATE_FAILED_PAST)
+        return attr.id;
+    }
+    else {
+      if (state == ATTRSTATE_FAILED_NOW && ATTRIBUTE_FLAGS_PREFAILURE(attr.flags))
+        return attr.id;
+    }
   }
   return 0;
 }
@@ -809,83 +806,64 @@ static void PrintSmartAttribWithThres(const ata_smart_values * data,
                                       const ata_vendor_attr_defs & defs,
                                       int onlyfailed)
 {
-  int needheader=1;
+  bool needheader = true;
 
   // step through all vendor attributes
   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
-    const ata_smart_attribute * disk = data->vendor_attributes+i;
-    const ata_smart_threshold_entry * thre = thresholds->thres_entries+i;
-    
-    // consider only valid attributes (allowing some screw-ups in the
-    // thresholds page data to slip by)
-    if (disk->id){
-      // Normalized values (current,worth,threshold) valid ?
-      // (Some SSD disks uses these bytes to store raw value).
-      bool norm_values_ok = !(defs[disk->id].flags & ATTRFLAG_NO_NORMVAL);
-
-      // Don't report a failed attribute if its threshold is 0.
-      // ATA-3 (X3T13/2008D Revision 7b) declares 0x00 as the "always passing"
-      // threshold (Later ATA versions declare all thresholds as "obsolete").
-      // In practice, threshold value 0 is often used for usage attributes or
-      // appears if the thresholds cannot be read.
-      bool failednow, failedever;
-      if (norm_values_ok && thre->threshold) {
-        failednow  = (disk->current <= thre->threshold);
-        failedever = (disk->worst   <= thre->threshold);
-      }
-      else
-        failednow = failedever = false;
+    const ata_smart_attribute & attr = data->vendor_attributes[i];
+    const ata_smart_threshold_entry & thre = thresholds->thres_entries[i];
 
-      // These break out of the loop if we are only printing certain entries...
-      if (onlyfailed==1 && (!ATTRIBUTE_FLAGS_PREFAILURE(disk->flags) || !failednow))
-        continue;
-      
-      if (onlyfailed==2 && !failedever)
-        continue;
-      
-      // print header only if needed
-      if (needheader){
-        if (!onlyfailed){
-          pout("SMART Attributes Data Structure revision number: %d\n",(int)data->revnumber);
-          pout("Vendor Specific SMART Attributes with Thresholds:\n");
-        }
-        pout("ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE\n");
-        needheader=0;
-      }
-      
-      // is this Attribute currently failed, or has it ever failed?
-      const char * status;
-      if (failednow)
-        status="FAILING_NOW";
-      else if (failedever)
-        status="In_the_past";
-      else
-        status="    -";
-
-      // printing line for each valid attribute
-      std::string attrname = ata_get_smart_attr_name(disk->id, defs);
-      std::string rawstr = ata_format_attr_raw_value(*disk, defs);
-      const char * type = ATTRIBUTE_FLAGS_PREFAILURE(disk->flags)?"Pre-fail":"Old_age";
-      const char * update = ATTRIBUTE_FLAGS_ONLINE(disk->flags)?"Always":"Offline";
-
-      if (norm_values_ok)
-        pout("%3d %-24s0x%04x   %.3d   %.3d   %.3d    %-10s%-9s%-12s%s\n",
-             disk->id, attrname.c_str(), disk->flags,
-             disk->current, disk->worst, thre->threshold,
-             type, update, status, rawstr.c_str());
-      else
-        pout("%3d %-24s0x%04x   ---   ---   ---    %-10s%-9s%-12s%s\n",
-             disk->id, attrname.c_str(), disk->flags,
-             type, update, status, rawstr.c_str());
-
-      // Print a warning if there is inconsistency here and
-      // threshold info is not empty.
-      if (norm_values_ok && disk->id != thre->id && (thre->id || thre->threshold)) {
-        pout("%3d %-24s<== Data Page      |  WARNING: PREVIOUS ATTRIBUTE HAS TWO\n",
-             disk->id, attrname.c_str());
-        pout("%3d %-24s<== Threshold Page |  INCONSISTENT IDENTITIES IN THE DATA\n",
-             thre->id, attrname.c_str());
+    // Check attribute and threshold
+    ata_attr_state state = ata_get_attr_state(attr, thre, defs);
+    if (state == ATTRSTATE_NON_EXISTING)
+      continue;
+
+    // These break out of the loop if we are only printing certain entries...
+    if (onlyfailed == 1 && !(ATTRIBUTE_FLAGS_PREFAILURE(attr.flags) && state == ATTRSTATE_FAILED_NOW))
+      continue;
+
+    if (onlyfailed == 2 && state < ATTRSTATE_FAILED_PAST)
+      continue;
+
+    // print header only if needed
+    if (needheader) {
+      if (!onlyfailed) {
+        pout("SMART Attributes Data Structure revision number: %d\n",(int)data->revnumber);
+        pout("Vendor Specific SMART Attributes with Thresholds:\n");
       }
+      pout("ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE\n");
+      needheader = false;
+    }
+
+    // Format value, worst, threshold
+    std::string valstr, threstr;
+    if (state > ATTRSTATE_NO_NORMVAL)
+      valstr = strprintf("%.3d   %.3d", attr.current, attr.worst);
+    else
+      valstr = "---   ---";
+    if (state > ATTRSTATE_NO_THRESHOLD)
+      threstr = strprintf("%.3d", thre.threshold);
+    else
+      threstr = "---";
+
+    // Print line for each valid attribute
+    std::string attrname = ata_get_smart_attr_name(attr.id, defs);
+    pout("%3d %-24s0x%04x   %-9s   %-3s    %-10s%-9s%-12s%s\n",
+         attr.id, attrname.c_str(), attr.flags,
+         valstr.c_str(), threstr.c_str(),
+         (ATTRIBUTE_FLAGS_PREFAILURE(attr.flags)? "Pre-fail" : "Old_age"),
+         (ATTRIBUTE_FLAGS_ONLINE(attr.flags)? "Always" : "Offline"),
+         (state == ATTRSTATE_FAILED_NOW  ? "FAILING_NOW" :
+          state == ATTRSTATE_FAILED_PAST ? "In_the_past" :
+                                           "    -"        ),
+         ata_format_attr_raw_value(attr, defs).c_str());
+
+    // Print a warning if there is inconsistency here
+    if (state == ATTRSTATE_BAD_THRESHOLD) {
+      pout("%3d %-24s<== Data Page      |  WARNING: PREVIOUS ATTRIBUTE HAS TWO\n",
+           attr.id, attrname.c_str());
+      pout("%3d %-24s<== Threshold Page |  INCONSISTENT IDENTITIES IN THE DATA\n",
+           thre.id, ata_get_smart_attr_name(thre.id, defs).c_str());
     }
   }
   if (!needheader) pout("\n");
diff --git a/smartmontools/smartd.cpp b/smartmontools/smartd.cpp
index 18d23085fae28e894575648f8fa0902a5c3080f0..c8f2bca622bb97d2c839b4ad64cbdaaaad735490 100644
--- a/smartmontools/smartd.cpp
+++ b/smartmontools/smartd.cpp
@@ -1710,13 +1710,13 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
 
     // see if the necessary Attribute is there to monitor offline or
     // current pending sectors or temperature
-    if (cfg.curr_pending_id && ATAReturnAttributeRawValue(cfg.curr_pending_id, &state.smartval) < 0) {
+    if (cfg.curr_pending_id && ata_find_attr_index(cfg.curr_pending_id, state.smartval) < 0) {
       PrintOut(LOG_INFO,"Device: %s, can't monitor Current Pending Sector count - no Attribute %d\n",
                name, cfg.curr_pending_id);
       cfg.curr_pending_id = 0;
     }
     
-    if (cfg.offl_pending_id && ATAReturnAttributeRawValue(cfg.offl_pending_id, &state.smartval) < 0) {
+    if (cfg.offl_pending_id && ata_find_attr_index(cfg.offl_pending_id, state.smartval) < 0) {
       PrintOut(LOG_INFO,"Device: %s, can't monitor Offline Uncorrectable Sector count - no Attribute %d\n",
                name, cfg.offl_pending_id);
       cfg.offl_pending_id = 0;
@@ -1997,75 +1997,6 @@ static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scs
   return 0;
 }
 
-
-struct changedattribute_t {
-  unsigned char newval;
-  unsigned char oldval;
-  unsigned char id;
-  unsigned char prefail;
-  unsigned char sameraw;
-};
-
-// We compare old and new values of the n'th attribute.  Note that n
-// is NOT the attribute ID number.. If (Normalized & Raw) equal,
-// then return 0, else nonzero.
-static int ATACompareValues(changedattribute_t *delta,
-                            struct ata_smart_values *newv,
-                            struct ata_smart_values *oldv,
-                            struct ata_smart_thresholds_pvt *thresholds,
-                            int n, const char * name)
-{
-  struct ata_smart_attribute *now,*was;
-  struct ata_smart_threshold_entry *thre;
-  unsigned char oldval,newval;
-  int sameraw;
-
-  // check that attribute number in range, and no null pointers
-  if (n<0 || n>=NUMBER_ATA_SMART_ATTRIBUTES || !newv || !oldv || !thresholds)
-    return 0;
-  
-  // pointers to disk's values and vendor's thresholds
-  now=newv->vendor_attributes+n;
-  was=oldv->vendor_attributes+n;
-  thre=thresholds->thres_entries+n;
-
-  // consider only valid attributes
-  if (!now->id || !was->id || !thre->id)
-    return 0;
-  
-  
-  // issue warning if they don't have the same ID in all structures:
-  if ( (now->id != was->id) || (now->id != thre->id) ){
-    PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d = %d\n",
-             name, (int)now->id, (int)was->id, (int)thre->id);
-    return 0;
-  }
-
-  // new and old values of Normalized Attributes
-  newval=now->current;
-  oldval=was->current;
-
-  // See if the RAW values are unchanged (ie, the same)
-  if (memcmp(now->raw, was->raw, 6))
-    sameraw=0;
-  else
-    sameraw=1;
-  
-  // if any values out of the allowed range, or if the values haven't
-  // changed, return 0
-  if (!newval || !oldval || newval>0xfe || oldval>0xfe || (oldval==newval && sameraw))
-    return 0;
-  
-  // values have changed.  Construct output and return
-  delta->newval=newval;
-  delta->oldval=oldval;
-  delta->id=now->id;
-  delta->prefail=ATTRIBUTE_FLAGS_PREFAILURE(now->flags);
-  delta->sameraw=sameraw;
-
-  return 1;
-}
-
 // If the self-test log has got more self-test errors (or more recent
 // self-test errors) recorded, then notify user.
 static void CheckSelfTestLogs(const dev_config & cfg, dev_state & state, int newi)
@@ -2434,13 +2365,18 @@ static void check_pending(const dev_config & cfg, dev_state & state,
                           const ata_smart_values & smartval,
                           int mailtype, const char * msg)
 {
+  // Find attribute index
+  int i = ata_find_attr_index(id, smartval);
+  if (!(i >= 0 && ata_find_attr_index(id, state.smartval) == i))
+    return;
+
   // No report if no sectors pending.
-  int64_t rawval = ATAReturnAttributeRawValue(id, &smartval);
-  if (rawval <= 0)
+  uint64_t rawval = ata_get_attr_raw_value(smartval.vendor_attributes[i], cfg.attribute_defs);
+  if (rawval == 0)
     return;
 
   // If attribute is not reset, report only sector count increases.
-  int64_t prev_rawval = ATAReturnAttributeRawValue(id, &state.smartval);
+  uint64_t prev_rawval = ata_get_attr_raw_value(state.smartval.vendor_attributes[i], cfg.attribute_defs);
   if (!(!increase_only || prev_rawval < rawval))
     return;
 
@@ -2533,6 +2469,103 @@ static void CheckTemperature(const dev_config & cfg, dev_state & state, unsigned
   }
 }
 
+// Check normalized and raw attribute values.
+static void check_attribute(const dev_config & cfg, dev_state & state,
+                            const ata_smart_attribute & attr,
+                            const ata_smart_attribute & prev,
+                            const ata_smart_threshold_entry & thre)
+{
+  // Check attribute and threshold
+  ata_attr_state attrstate = ata_get_attr_state(attr, thre, cfg.attribute_defs);
+  if (attrstate == ATTRSTATE_NON_EXISTING)
+    return;
+
+  // If requested, check for usage attributes that have failed.
+  if (   cfg.usagefailed && attrstate == ATTRSTATE_FAILED_NOW
+      && !cfg.monitor_attr_flags.is_set(attr.id, MONITOR_IGN_FAILUSE)) {
+    std::string attrname = ata_get_smart_attr_name(attr.id, cfg.attribute_defs);
+    PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %d %s.\n", cfg.name.c_str(), attr.id, attrname.c_str());
+    MailWarning(cfg, state, 2, "Device: %s, Failed SMART usage Attribute: %d %s.", cfg.name.c_str(), attr.id, attrname.c_str());
+    state.must_write = true;
+  }
+
+  // Return if we're not tracking this type of attribute
+  bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(attr.flags);
+  if (!(   ( prefail && cfg.prefail)
+        || (!prefail && cfg.usage  )))
+    return;
+
+  // Return if '-I ID' was specified
+  if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_IGNORE))
+    return;
+
+  // Issue warning if they don't have the same ID in all structures.
+  if (attr.id != prev.id || attrstate == ATTRSTATE_BAD_THRESHOLD) {
+    PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d = %d\n",
+             cfg.name.c_str(), attr.id, prev.id, thre.id);
+    return;
+  }
+
+  // Compare normalized values if valid.
+  bool valchanged = false;
+  if (attrstate > ATTRSTATE_NO_NORMVAL) {
+    if (attr.current != prev.current)
+      valchanged = true;
+  }
+
+  // Compare raw values if requested.
+  bool rawchanged = false;
+  if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW)) {
+    if (   ata_get_attr_raw_value(attr, cfg.attribute_defs)
+        != ata_get_attr_raw_value(prev, cfg.attribute_defs))
+      rawchanged = true;
+  }
+
+  // Return if no change
+  if (!(valchanged || rawchanged))
+    return;
+
+  // Format value strings
+  std::string currstr, prevstr;
+  if (attrstate == ATTRSTATE_NO_NORMVAL) {
+    // Print raw values only
+    currstr = strprintf("%s (Raw)",
+      ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str());
+    prevstr = strprintf("%s (Raw)",
+      ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str());
+  }
+  else if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_PRINT)) {
+    // Print normalized and raw values
+    currstr = strprintf("%d [Raw %s]", attr.current,
+      ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str());
+    prevstr = strprintf("%d [Raw %s]", prev.current,
+      ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str());
+  }
+  else {
+    // Print normalized values only
+    currstr = strprintf("%d", attr.current);
+    prevstr = strprintf("%d", prev.current);
+  }
+
+  // Format message
+  std::string msg = strprintf("Device: %s, SMART %s Attribute: %d %s changed from %s to %s",
+                              cfg.name.c_str(), (prefail ? "Prefailure" : "Usage"), attr.id,
+                              ata_get_smart_attr_name(attr.id, cfg.attribute_defs).c_str(),
+                              prevstr.c_str(), currstr.c_str());
+
+  // Report this change as critical ?
+  if (   (valchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_AS_CRIT))
+      || (rawchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_AS_CRIT))) {
+    PrintOut(LOG_CRIT, "%s\n", msg.c_str());
+    MailWarning(cfg, state, 2, "%s", msg.c_str());
+  }
+  else {
+    PrintOut(LOG_INFO, "%s\n", msg.c_str());
+  }
+  state.must_write = true;
+}
+
+
 static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device * atadev, bool allow_selftests)
 {
   const char * name = cfg.name.c_str();
@@ -2643,10 +2676,9 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
   if (   cfg.usagefailed || cfg.prefail || cfg.usage
       || cfg.curr_pending_id || cfg.offl_pending_id
       || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit || cfg.selftest) {
-    struct ata_smart_values     curval;
-    struct ata_smart_thresholds_pvt * thresh = &state.smartthres;
 
-    // Read current attribute values. *drive contains old values and thresholds
+    // Read current attribute values.
+    ata_smart_values curval;
     if (ataReadSmartValues(atadev, &curval)){
       PrintOut(LOG_CRIT, "Device: %s, failed to read SMART Attribute Data\n", name);
       MailWarning(cfg, state, 6, "Device: %s, failed to read SMART Attribute Data", name);
@@ -2670,79 +2702,14 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
 
       if (cfg.usagefailed || cfg.prefail || cfg.usage) {
 
-	// look for failed usage attributes, or track usage or prefail attributes
+        // look for failed usage attributes, or track usage or prefail attributes
         for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
+          check_attribute(cfg, state,
+                          curval.vendor_attributes[i],
+                          state.smartval.vendor_attributes[i],
+                          state.smartthres.thres_entries[i]);
+        }
 
-	  // This block looks for usage attributes that have failed.
-	  // Prefail attributes that have failed are returned with a
-	  // positive sign. No failure returns 0. Usage attributes<0.
-          int att;
-	  if (cfg.usagefailed && ((att=ataCheckAttribute(&curval, thresh, i))<0)){
-	    
-	    // are we ignoring failures of this attribute?
-	    att *= -1;
-            if (!cfg.monitor_attr_flags.is_set(att, MONITOR_IGN_FAILUSE)) {
-	      // warning message
-              std::string attrname = ata_get_smart_attr_name(att, cfg.attribute_defs);
-              PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %d %s.\n", name, att, attrname.c_str());
-              MailWarning(cfg, state, 2, "Device: %s, Failed SMART usage Attribute: %d %s.", name, att, attrname.c_str());
-              state.must_write = true;
-	    }
-	  }
-	  
-	  // This block tracks usage or prefailure attributes to see if
-	  // they are changing.  It also looks for changes in RAW values
-	  // if this has been requested by user.
-          changedattribute_t delta;
-	  if ((cfg.usage || cfg.prefail) && ATACompareValues(&delta, &curval, &state.smartval, thresh, i, name)){
-
-            // Continue if we're not tracking this type of attribute
-            if (!(   ( delta.prefail && cfg.prefail)
-                  || (!delta.prefail && cfg.usage   )))
-              continue;
-
-            // Continue if '-I ID' was specified
-            unsigned char id = delta.id;
-            if (cfg.monitor_attr_flags.is_set(id, MONITOR_IGNORE))
-              continue;
-
-	    // if the only change is the raw value, and we're not
-	    // tracking raw value, then continue loop over attributes
-            if (   !delta.sameraw && delta.newval == delta.oldval
-                && !cfg.monitor_attr_flags.is_set(id, MONITOR_RAW))
-	      continue;
-
-            // get attribute name
-            std::string attrname = ata_get_smart_attr_name(id, cfg.attribute_defs);
-
-            // has the user asked for us to print raw values?
-            std::string newraw, oldraw;
-            if (cfg.monitor_attr_flags.is_set(id, MONITOR_RAW_PRINT)) {
-              // get raw values (as a string) and add to printout
-              newraw = strprintf(" [Raw %s]",
-                ata_format_attr_raw_value(curval.vendor_attributes[i], cfg.attribute_defs).c_str());
-              oldraw = strprintf(" [Raw %s]",
-                ata_format_attr_raw_value(state.smartval.vendor_attributes[i], cfg.attribute_defs).c_str());
-            }
-
-            // Format message
-            std::string msg = strprintf("Device: %s, SMART %s Attribute: %d %s changed from %d%s to %d%s",
-                                        name, (delta.prefail ? "Prefailure" : "Usage"), id, attrname.c_str(),
-                                        delta.oldval, oldraw.c_str(), delta.newval, newraw.c_str());
-
-            // Report this change as critical ?
-            if (   (delta.newval != delta.oldval && cfg.monitor_attr_flags.is_set(id, MONITOR_AS_CRIT))
-                || (!delta.sameraw               && cfg.monitor_attr_flags.is_set(id, MONITOR_RAW_AS_CRIT))) {
-              PrintOut(LOG_CRIT, "%s\n", msg.c_str());
-              MailWarning(cfg, state, 2, "%s", msg.c_str());
-            }
-            else {
-              PrintOut(LOG_INFO, "%s\n", msg.c_str());
-            }
-            state.must_write = true;
-	  } // endof block tracking usage or prefailure
-	} // end of loop over attributes
-	
         if (cfg.selftest) {
           // Log changes of self-test execution status
           if (   curval.self_test_exec_status != state.smartval.self_test_exec_status