* Home page of code is: http://smartmontools.sourceforge.net
*
* Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
- * Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-14 Christian Franke <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
*
* This program is free software; you can redistribute it and/or modify
#include "utility.h"
#include "knowndrives.h"
-const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 3831 2013-07-20 14:25:56Z chrfranke $"
+const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 3982 2014-08-16 21:07:19Z samm2 $"
ATAPRINT_H_CVSID;
lba48 |= lba48_regs->lba_mid_register;
lba48 <<= 8;
lba48 |= lba48_regs->lba_low_register;
- str += strprintf(" at LBA = 0x%08"PRIx64" = %"PRIu64, lba48, lba48);
+ str += strprintf(" at LBA = 0x%08" PRIx64 " = %" PRIu64, lba48, lba48);
}
}
unsigned oui = 0; uint64_t unique_id = 0;
int naa = ata_get_wwn(drive, oui, unique_id);
if (naa >= 0)
- pout("LU WWN Device Id: %x %06x %09"PRIx64"\n", naa, oui, unique_id);
+ pout("LU WWN Device Id: %x %06x %09" PRIx64 "\n", naa, oui, unique_id);
// Additional Product Identifier (OEM Id) string in words 170-173
// (e08130r1, added in ACS-2 Revision 1, December 17, 2008)
pout("Rotation Rate: Unknown (0x%04x)\n", -rpm);
}
+ // Print form factor if reported
+ unsigned short word168 = drive->words088_255[168-88];
+ if (word168) {
+ const char * inches;
+ switch (word168) {
+ case 0x1: inches = "5.25"; break;
+ case 0x2: inches = "3.5"; break;
+ case 0x3: inches = "2.5"; break;
+ case 0x4: inches = "1.8"; break;
+ case 0x5: inches = "< 1.8"; break;
+ default : inches = 0;
+ }
+ if (inches)
+ pout("Form Factor: %s inches\n", inches);
+ else
+ pout("Form Factor: Unknown (0x%04x)\n", word168);
+ }
+
// See if drive is recognized
pout("Device is: %s\n", !dbentry ?
"Not in smartctl database [for details use: -P showall]":
case 0x09: return "Selective self-test log";
case 0x0a: return "Device Statistics Notification"; // ACS-3
case 0x0b: return "Reserved for CFA"; // ACS-3
-
+ case 0x0c: return "Pending Defects log"; // ACS-4
case 0x0d: return "LPS Mis-alignment log"; // ACS-2
case 0x10: return "NCQ Command Error log";
case 0x13: return "SATA NCQ Send and Receive log"; // ACS-3
case 0x14:
case 0x15:
- case 0x16: return "Reserved for Serial ATA";
+ case 0x16:
+ case 0x17: return "Reserved for Serial ATA";
case 0x19: return "LBA Status log"; // ACS-3
static const char * get_log_rw(unsigned logaddr)
{
if ( ( logaddr <= 0x08)
- || (0x0d == logaddr)
+ || (0x0c <= logaddr && logaddr <= 0x0d)
|| (0x10 <= logaddr && logaddr <= 0x13)
|| (0x19 == logaddr)
|| (0x20 <= logaddr && logaddr <= 0x25)
if (!(flags & 0x80))
continue;
+ // Stop if unknown entries contain garbage data due to buggy firmware
+ if (!info && (data[offset+5] || data[offset+6])) {
+ pout("%3d 0x%03x - - [Trailing garbage ignored]\n", page, offset);
+ break;
+ }
+
// Get value size, default to max if unknown
int size = (info ? info[i].size : 7);
for (int j = 0; j < size; j++)
val |= (int64_t)data[offset+j] << (j*8);
}
- snprintf(valstr, sizeof(valstr), "%"PRId64, val);
+ snprintf(valstr, sizeof(valstr), "%" PRId64, val);
}
else {
// Value not known (yet)
}
static bool print_device_statistics(ata_device * device, unsigned nsectors,
- const std::vector<int> & single_pages, bool all_pages, bool ssd_page)
+ const std::vector<int> & single_pages, bool all_pages, bool ssd_page,
+ bool use_gplog)
{
// Read list of supported pages from page 0
unsigned char page_0[512] = {0, };
- if (!ataReadLogExt(device, 0x04, 0, 0, page_0, 1)) {
+ int rc;
+
+ if (use_gplog)
+ rc = ataReadLogExt(device, 0x04, 0, 0, page_0, 1);
+ else
+ rc = ataReadSmartLog(device, 0x04, page_0, 1);
+ if (!rc) {
pout("Read Device Statistics page 0 failed\n\n");
return false;
}
// Print list of supported pages if requested
if (print_page_0) {
- pout("Device Statistics (GP Log 0x04) supported pages\n");
+ pout("Device Statistics (%s Log 0x04) supported pages\n",
+ use_gplog ? "GP" : "SMART");
pout("Page Description\n");
for (i = 0; i < nentries; i++) {
int page = page_0[8+1+i];
// Read & print pages
if (!pages.empty()) {
- pout("Device Statistics (GP Log 0x04)\n");
+ pout("Device Statistics (%s Log 0x04)\n",
+ use_gplog ? "GP" : "SMART");
pout("Page Offset Size Value Description\n");
bool need_trailer = false;
+ int max_page = 0;
+
+ if (!use_gplog)
+ for (i = 0; i < pages.size(); i++) {
+ int page = pages[i];
+ if (max_page < page && page < 0xff)
+ max_page = page;
+ }
+
+ raw_buffer pages_buf((max_page+1) * 512);
+
+ if (!use_gplog && !ataReadSmartLog(device, 0x04, pages_buf.data(), max_page+1)) {
+ pout("Read Device Statistics pages 0-%d failed\n\n", max_page);
+ return false;
+ }
for (i = 0; i < pages.size(); i++) {
int page = pages[i];
- unsigned char page_n[512] = {0, };
- if (!ataReadLogExt(device, 0x04, 0, page, page_n, 1)) {
+ if (use_gplog && !ataReadLogExt(device, 0x04, 0, page, pages_buf.data(), 1)) {
pout("Read Device Statistics page %d failed\n\n", page);
return false;
}
- print_device_statistics_page(page_n, page, need_trailer);
+
+ int offset = (use_gplog ? 0 : page * 512);
+ print_device_statistics_page(pages_buf.data() + offset, page, need_trailer);
}
if (need_trailer)
}
// Counters stop at max value, add '+' in this case
- pout("0x%04x %u %12"PRIu64"%c %s\n", id, size, val,
+ pout("0x%04x %u %12" PRIu64 "%c %s\n", id, size, val,
(val == max_val ? '+' : ' '), name);
}
if (reset)
// we need at least 7 characters wide fields to accomodate the
// labels
- if ((field1=snprintf(tmp,64, "%"PRIu64, maxl))<7)
+ if ((field1=snprintf(tmp,64, "%" PRIu64, maxl))<7)
field1=7;
- if ((field2=snprintf(tmp,64, "%"PRIu64, maxr))<7)
+ if ((field2=snprintf(tmp,64, "%" PRIu64, maxr))<7)
field2=7;
// now print the five test spans
if ((i+1)==(int)log->currentspan)
// this span is currently under test
- pout(" %d %*"PRIu64" %*"PRIu64" %s [%01d0%% left] (%"PRIu64"-%"PRIu64")\n",
+ pout(" %d %*" PRIu64 " %*" PRIu64 " %s [%01d0%% left] (%" PRIu64 "-%" PRIu64 ")\n",
i+1, field1, start, field2, end, msg,
(int)(sv->self_test_exec_status & 0xf), current, currentend);
else
// this span is not currently under test
- pout(" %d %*"PRIu64" %*"PRIu64" Not_testing\n",
+ pout(" %d %*" PRIu64 " %*" PRIu64 " Not_testing\n",
i+1, field1, start, field2, end);
}
// if we are currently read-scanning, print LBAs and the status of
// the read scan
if (log->currentspan>5)
- pout("%5d %*"PRIu64" %*"PRIu64" Read_scanning %s\n",
+ pout("%5d %*" PRIu64 " %*" PRIu64 " Read_scanning %s\n",
(int)log->currentspan, field1, current, field2, currentend,
OfflineDataCollectionStatus(sv->offline_data_collection_status));
);
// SMART and GP log directories needed ?
- bool need_smart_logdir = options.smart_logdir;
+ bool need_smart_logdir = (
+ options.smart_logdir
+ || options.devstat_all_pages // devstat fallback to smartlog if needed
+ || options.devstat_ssd_page
+ || !options.devstat_pages.empty()
+ );
bool need_gp_logdir = (
options.gp_logdir
if (options.get_security)
print_ata_security_status("ATA Security is: ", drive.words088_255[128-88]);
- // Check if SCT commands available
- bool sct_ok = false;
- if (need_sct_support) {
- if (!isSCTCapable(&drive)) {
- failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+ // Print write cache reordering status
+ if (options.sct_wcache_reorder_get) {
+ if (isSCTFeatureControlCapable(&drive)) {
+ int wcache_reorder = ataGetSetSCTWriteCacheReordering(device,
+ false /*enable*/, false /*persistent*/, false /*set*/);
+
+ if (-1 <= wcache_reorder && wcache_reorder <= 2)
+ pout("Wt Cache Reorder: %s\n",
+ (wcache_reorder == -1 ? "Unknown (SCT Feature Control command failed)" :
+ wcache_reorder == 0 ? "Unknown" : // not defined in standard but returned on some drives if not set
+ wcache_reorder == 1 ? "Enabled" : "Disabled"));
+ else
+ pout("Wt Cache Reorder: Unknown (0x%02x)\n", wcache_reorder);
}
else
- sct_ok = true;
- }
-
- // Print write cache reordering status
- if (sct_ok && options.sct_wcache_reorder_get) {
- int wcache_reorder=ataGetSetSCTWriteCacheReordering(device,
- false /* enable */, false /* persistent */, false /*set*/);
- pout("Wt Cache Reorder: ");
- switch(wcache_reorder) {
- case 0: /* not defined in standard but returned on some drives if not set */
- pout("Unknown"); break;
- case 1:
- pout("Enabled"); break;
- case 2:
- pout("Disabled"); break;
- default: /* error? */
- pout("N/A"); break;
- }
- pout("\n");
- }
- if (!sct_ok && options.sct_wcache_reorder_get) {
- pout("Wt Cache Reorder: Unavailable\n");
+ pout("Wt Cache Reorder: Unavailable\n");
}
// Print remaining drive info
}
// Enable/Disable write cache reordering
- if (sct_ok && options.sct_wcache_reorder_set) {
+ if (options.sct_wcache_reorder_set) {
bool enable = (options.sct_wcache_reorder_set > 0);
-
- int wcache_reorder=ataGetSetSCTWriteCacheReordering(device,
- enable, false /* persistent */, true /*set*/);
-
- if (wcache_reorder < 0) {
- pout("Write cache reordering %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg());
- returnval |= FAILSMART;
+ if (!isSCTFeatureControlCapable(&drive))
+ pout("Write cache reordering %sable failed: SCT Feature Control command not supported\n",
+ (enable ? "en" : "dis"));
+ else if (ataGetSetSCTWriteCacheReordering(device,
+ enable, false /*persistent*/, true /*set*/) < 0) {
+ pout("Write cache reordering %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg());
+ returnval |= FAILSMART;
}
else
pout("Write cache reordering %sabled\n", (enable ? "en" : "dis"));
// The ATA SMART RETURN STATUS command provides the result in the ATA output
// registers. Buggy ATA/SATA drivers and SAT Layers often do not properly
// return the registers values.
+ pout("SMART Status %s: %s\n",
+ (device->is_syscall_unsup() ? "not supported" : "command failed"),
+ device->get_errmsg());
failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+
if (!(smart_val_ok && smart_thres_ok)) {
print_on();
pout("SMART overall-health self-assessment test result: UNKNOWN!\n"
print_on();
pout("SMART overall-health self-assessment test result: FAILED!\n"
"Drive failure expected in less than 24 hours. SAVE ALL DATA.\n");
+ pout("Warning: This result is based on an Attribute check.\n");
print_off();
returnval|=FAILATTR;
returnval|=FAILSTATUS;
}
}
+ // Check if SCT commands available
+ bool sct_ok = isSCTCapable(&drive);
if(!sct_ok && (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int
|| options.sct_erc_get || options.sct_erc_set ))
pout("SCT Commands not supported\n\n");
// Print SCT status and temperature history table
if (sct_ok && (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int)) {
for (;;) {
- if (options.sct_temp_sts || options.sct_temp_hist) {
- ata_sct_status_response sts;
- ata_sct_temperature_history_table tmh;
- if (!options.sct_temp_hist) {
- // Read SCT status only
- if (ataReadSCTStatus(device, &sts)) {
- failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
- break;
- }
- }
- else {
- if (!isSCTDataTableCapable(&drive)) {
- pout("SCT Data Table command not supported\n\n");
- failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
- break;
- }
- // Read SCT status and temperature history
- if (ataReadSCTTempHist(device, &tmh, &sts)) {
- pout("Read SCT Temperature History failed\n\n");
- failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
- break;
- }
+ bool sct_temp_hist_ok = isSCTDataTableCapable(&drive);
+ ata_sct_status_response sts;
+
+ if (options.sct_temp_sts || (options.sct_temp_hist && sct_temp_hist_ok)) {
+ // Read SCT status
+ if (ataReadSCTStatus(device, &sts)) {
+ pout("\n");
+ failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+ break;
}
- if (options.sct_temp_sts)
+ if (options.sct_temp_sts) {
ataPrintSCTStatus(&sts);
- if (options.sct_temp_hist)
- ataPrintSCTTempHist(&tmh);
+ pout("\n");
+ }
+ }
+
+ if (!sct_temp_hist_ok && (options.sct_temp_hist || options.sct_temp_int)) {
+ pout("SCT Data Table command not supported\n\n");
+ failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+ break;
+ }
+
+ if (options.sct_temp_hist) {
+ // Read SCT temperature history,
+ // requires initial SCT status from above
+ ata_sct_temperature_history_table tmh;
+ if (ataReadSCTTempHist(device, &tmh, &sts)) {
+ pout("Read SCT Temperature History failed\n\n");
+ failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+ break;
+ }
+ ataPrintSCTTempHist(&tmh);
pout("\n");
}
+
if (options.sct_temp_int) {
// Set new temperature logging interval
if (!isSCTFeatureControlCapable(&drive)) {
// Print Device Statistics
if (options.devstat_all_pages || options.devstat_ssd_page || !options.devstat_pages.empty()) {
- unsigned nsectors = GetNumLogSectors(gplogdir, 0x04, true);
+ bool use_gplog = true;
+ unsigned nsectors = 0;
+ if (gplogdir)
+ nsectors = GetNumLogSectors(gplogdir, 0x04, false);
+ else if (smartlogdir){ // for systems without ATA_READ_LOG_EXT
+ nsectors = GetNumLogSectors(smartlogdir, 0x04, false);
+ use_gplog = false;
+ }
if (!nsectors)
- pout("Device Statistics (GP Log 0x04) not supported\n\n");
+ pout("Device Statistics (GP/SMART Log 0x04) not supported\n\n");
else if (!print_device_statistics(device, nsectors, options.devstat_pages,
- options.devstat_all_pages, options.devstat_ssd_page))
+ options.devstat_all_pages, options.devstat_ssd_page, use_gplog))
failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
}