Select Git revision
doxygen_index.h
Forked from
einsteinathome / graphicsframework
Source project has a limited visibility.
-
Oliver Bock authoredOliver Bock authored
ataprint.c 29.90 KiB
/*
* ataprint.c
*
* Home page of code is: http://smartmontools.sourceforge.net
*
* Copyright (C) 2002 Bruce Allen <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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* You should have received a copy of the GNU General Public License
* (for example COPYING); if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This code was originally developed as a Senior Thesis by Michael Cornwell
* at the Concurrent Systems Laboratory (now part of the Storage Systems
* Research Center), Jack Baskin School of Engineering, University of
* California, Santa Cruz. http://ssrc.soe.ucsc.edu/
*
*/
#include <ctype.h>
#include <stdio.h>
#include "ataprint.h"
#include "smartctl.h"
#include "extern.h"
const char *CVSid4="$Id: ataprint.c,v 1.33 2002/10/24 09:54:02 ballen4705 Exp $"
CVSID2 CVSID3 CVSID6;
// Function for printing ASCII byte-swapped strings, skipping white
// space. This is needed on little-endian architectures, eg Intel,
// Alpha. If someone wants to run this on SPARC they'll need to test
// for the Endian-ness and skip the byte swapping if it's big-endian.
void printswap(char *in, unsigned int n){
unsigned int i;
char out[64];
// swap bytes
for (i=0;i<n;i+=2){
unsigned int j=i+1;
out[i]=in[j];
out[j]=in[i];
}
// find the end of the white space
for (i=0;i<n && isspace(out[i]);i++);
// and do the printing starting from first non-white space
if (n-i)
pout("%.*s\n",(int)(n-i),out+i);
else
pout("[No Information Found]\n");
return;
}
void ataPrintDriveInfo (struct hd_driveid drive){
int version;
const char *description;
char unknown[64];
// print out model, serial # and firmware versions (byte-swap ASCI strings)
pout("Device Model: ");
printswap(drive.model,40);
pout("Serial Number: ");
printswap(drive.serial_no,20);
pout("Firmware Version: ");
printswap(drive.fw_rev,8);
// now get ATA version info
version=ataVersionInfo(&description,drive);
// unrecognized minor revision code
if (!description){
sprintf(unknown,"Unrecognized. Minor revision code: 0x%02x",drive.minor_rev_num);
description=unknown;
}
// SMART Support was first added into the ATA/ATAPI-3 Standard with
// Revision 3 of the document, July 25, 1995. Look at the "Document
// Status" revision commands at the beginning of
// http://www.t13.org/project/d2008r6.pdf to see this. So it's not
// enough to check if we are ATA-3. Version=-3 indicates ATA-3
// BEFORE Revision 3.
pout("ATA Version is: %i\n",version>0?version:-1*version);
pout("ATA Standard is: %s\n",description);
if (version>=3)
return;
pout("SMART is only available in ATA Version 3 Revision 3 or greater.\n");
pout("We will try to proceed in spite of this.\n");
return;
}
/* void PrintSmartOfflineStatus ( struct ata_smart_values data)
prints verbose value Off-line data collection status byte */
void PrintSmartOfflineStatus ( struct ata_smart_values data)
{
pout ("Off-line data collection status: ");
switch (data.offline_data_collection_status){
case 0x00:
case 0x80:
pout ("(0x%02x)\tOffline data collection activity was\n\t\t\t\t\t",
data.offline_data_collection_status);
pout("never started.\n");
break;
case 0x01:
case 0x81:
pout ("(0x%02x)\tReserved.\n",
data.offline_data_collection_status);
break;
case 0x02:
case 0x82:
pout ("(0x%02x)\tOffline data collection activity \n\t\t\t\t\t",
data.offline_data_collection_status);
pout ("completed without error.\n");
break;
case 0x03:
case 0x83:
pout ("(0x%02x)\tReserved.\n",
data.offline_data_collection_status);
break;
case 0x04:
case 0x84:
pout ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t",
data.offline_data_collection_status);
pout ("suspended by an interrupting command from host.\n");
break;
case 0x05:
case 0x85:
pout ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t",
data.offline_data_collection_status);
pout ("aborted by an interrupting command from host.\n");
break;
case 0x06:
case 0x86:
pout ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t",
data.offline_data_collection_status);
pout ("aborted by the device with a fatal error.\n");
break;
default:
if ( ((data.offline_data_collection_status >= 0x07) &&
(data.offline_data_collection_status <= 0x3f)) ||
((data.offline_data_collection_status >= 0xc0) &&
(data.offline_data_collection_status <= 0xff)) )
{
pout ("(0x%02x)\tVendor Specific.\n",
data.offline_data_collection_status);
}
else
{
pout ("(0x%02x)\tReserved.\n",
data.offline_data_collection_status);
}
}
}
void PrintSmartSelfExecStatus ( struct ata_smart_values data)
{
pout ("Self-test execution status: ");
switch (data.self_test_exec_status >> 4)
{
case 0:
pout ("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t",
data.self_test_exec_status);
pout ("without error or no self-test has ever \n\t\t\t\t\tbeen run.\n");
break;
case 1:
pout ("(%4d)\tThe self-test routine was aborted by\n\t\t\t\t\t",
data.self_test_exec_status);
pout ("the host.\n");
break;
case 2:
pout ("(%4d)\tThe self-test routine was interrupted\n\t\t\t\t\t",
data.self_test_exec_status);
pout ("by the host with a hard or soft reset.\n");
break;
case 3:
pout ("(%4d)\tA fatal error or unknown test error\n\t\t\t\t\t",
data.self_test_exec_status);
pout ("occurred while the device was executing\n\t\t\t\t\t");
pout ("its self-test routine and the device \n\t\t\t\t\t");
pout ("was unable to complete the self-test \n\t\t\t\t\t");
pout ("routine.\n");
break;
case 4:
pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
data.self_test_exec_status);
pout ("a test element that failed and the test\n\t\t\t\t\t");
pout ("element that failed is not known.\n");
break;
case 5:
pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
data.self_test_exec_status);
pout ("the electrical element of the test\n\t\t\t\t\t");
pout ("failed.\n");
break;
case 6:
pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
data.self_test_exec_status);
pout ("the servo (and/or seek) element of the \n\t\t\t\t\t");
pout ("test failed.\n");
break;
case 7:
pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
data.self_test_exec_status);
pout ("the read element of the test failed.\n");
break;
case 15:
pout ("(%4d)\tSelf-test routine in progress...\n\t\t\t\t\t",
data.self_test_exec_status);
pout ("%1d0%% of test remaining.\n",
data.self_test_exec_status & 0x0f);
break;
default:
pout ("(%4d)\tReserved.\n",
data.self_test_exec_status);
break;
}
}
void PrintSmartTotalTimeCompleteOffline ( struct ata_smart_values data)
{
pout ("Total time to complete off-line \n");
pout ("data collection: \t\t (%4d) seconds.\n",
data.total_time_to_complete_off_line);
}
void PrintSmartOfflineCollectCap ( struct ata_smart_values data)
{
pout ("Offline data collection\n");
pout ("capabilities: \t\t\t (0x%02x) ",
data.offline_data_collection_capability);
if (data.offline_data_collection_capability == 0x00)
{
pout ("\tOff-line data collection not supported.\n");
}
else
{
pout( "%s\n", isSupportExecuteOfflineImmediate(data)?
"SMART execute Offline immediate." :
"No SMART execute Offline immediate.");
pout( "\t\t\t\t\t%s\n", isSupportAutomaticTimer(data)?
"Automatic timer ON/OFF support.":
"No Automatic timer ON/OFF support.");
pout( "\t\t\t\t\t%s\n", isSupportOfflineAbort(data)?
"Abort Offline collection upon new\n\t\t\t\t\tcommand.":
"Suspend Offline collection upon new\n\t\t\t\t\tcommand.");
pout( "\t\t\t\t\t%s\n", isSupportOfflineSurfaceScan(data)?
"Offline surface scan supported.":
"No Offline surface scan supported.");
pout( "\t\t\t\t\t%s\n", isSupportSelfTest(data)?
"Self-test supported.":
"No Self-test supported.");
}
}
void PrintSmartCapability ( struct ata_smart_values data)
{
pout ("SMART capabilities: ");
pout ("(0x%04x)\t", data.smart_capability);
if (data.smart_capability == 0x00)
{
pout ("Automatic saving of SMART data\t\t\t\t\tis not implemented.\n");
}
else
{
pout( "%s\n", (data.smart_capability & 0x01)?
"Saves SMART data before entering\n\t\t\t\t\tpower-saving mode.":
"Does not save SMART data before\n\t\t\t\t\tentering power-saving mode.");
if ( data.smart_capability & 0x02 )
{
pout ("\t\t\t\t\tSupports SMART auto save timer.\n");
}
}
}
void PrintSmartErrorLogCapability ( struct ata_smart_values data)
{
pout ("Error logging capability: ");
if ( isSmartErrorLogCapable(data) )
{
pout (" (0x%02x)\tError logging supported.\n",
data.errorlog_capability);
}
else {
pout (" (0x%02x)\tError logging NOT supported.\n",
data.errorlog_capability);
}
}
void PrintSmartShortSelfTestPollingTime ( struct ata_smart_values data)
{
if ( isSupportSelfTest(data) )
{
pout ("Short self-test routine \n");
pout ("recommended polling time: \t (%4d) minutes.\n",
data.short_test_completion_time);
}
else
{
pout ("Short self-test routine \n");
pout ("recommended polling time: \t Not Supported.\n");
}
}
void PrintSmartExtendedSelfTestPollingTime ( struct ata_smart_values data)
{
if ( isSupportSelfTest(data) )
{
pout ("Extended self-test routine \n");
pout ("recommended polling time: \t (%4d) minutes.\n",
data.extend_test_completion_time);
}
else
{
pout ("Extended self-test routine \n");
pout ("recommended polling time: \t Not Supported.\n");
}
}
// onlyfailed=0 : print all attribute values
// onlyfailed=1: just ones that are currently failed and have prefailure bit set
// onlyfailed=2: ones that are failed, or have failed with or without prefailure bit set
void PrintSmartAttribWithThres (struct ata_smart_values data,
struct ata_smart_thresholds thresholds,
int onlyfailed){
int i,j;
long long rawvalue;
int needheader=1;
// step through all vendor attributes
for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){
char *status;
struct ata_smart_attribute *disk=data.vendor_attributes+i;
struct ata_smart_threshold_entry *thre=thresholds.thres_entries+i;
// consider only valid attributes
if (disk->id && thre->id){
char *type;
int failednow,failedever;
char attributename[64];
failednow =disk->current <= thre->threshold;
failedever=disk->worst <= thre->threshold;
// These break out of the loop if we are only printing certain entries...
if (onlyfailed==1 && (!disk->status.flag.prefailure || !failednow))
continue;
if (onlyfailed==2 && !failedever)
continue;
// print header only if needed
if (needheader){
if (!onlyfailed){
pout ("SMART Attributes Data Structure revision number: %i\n",data.revnumber);
pout ("Vendor Specific SMART Attributes with Thresholds:\n");
}
pout("ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE\n");
needheader=0;
}
// is this currently failed, or has it ever failed?
if (failednow)
status="FAILING_NOW";
else if (failedever)
status="In_the_past";
else
status=" -";
// Print name of attribute
ataPrintSmartAttribName(attributename,disk->id);
pout("%-28s",attributename);
// printing line for each valid attribute
type=disk->status.flag.prefailure?"Pre-fail":"Old_age";
pout("0x%04x %.3i %.3i %.3i %-9s%-12s",
disk->status.all, disk->current, disk->worst,
thre->threshold, type, status);
// convert the six individual bytes to a long long (8 byte) integer
rawvalue = 0;
for (j = 0 ; j < 6 ; j++)
rawvalue |= disk->raw[j] << (8*j) ;
// This switch statement is where we handle Raw attributes
// that are stored in an unusual vendor-specific format,
switch (disk->id){
// Power on time
case 9:
if (smart009minutes)
// minutes
pout ("%llu h + %2llu m\n",rawvalue/60,rawvalue%60);
else
// hours
pout ("%llu\n", rawvalue); //stored in hours
break;
// Temperature
case 194:
pout ("%u", disk->raw[0]);
if (rawvalue==disk->raw[0])
pout("\n");
else
// The other bytes are in use. Try IBM's model
pout(" (Lifetime Min/Max %u/%u)\n",disk->raw[2],
disk->raw[4]);
break;
default:
pout("%llu\n", rawvalue);
}
}
}
if (!needheader) pout("\n");
}
void ataPrintGeneralSmartValues(struct ata_smart_values data){
pout ("General SMART Values:\n");
PrintSmartOfflineStatus(data);
if (isSupportSelfTest(data)){
PrintSmartSelfExecStatus (data);
}
PrintSmartTotalTimeCompleteOffline(data);
PrintSmartOfflineCollectCap(data);
PrintSmartCapability(data);
PrintSmartErrorLogCapability(data);
if (isSupportSelfTest(data)){
PrintSmartShortSelfTestPollingTime (data);
PrintSmartExtendedSelfTestPollingTime (data);
}
pout("\n");
}
// Is not (currently) used in ANY code
void ataPrintSmartThresholds (struct ata_smart_thresholds data)
{
int i;
pout ("SMART Thresholds\n");
pout ("SMART Threshold Revision Number: %i\n", data.revnumber);
for ( i = 0 ; i < NUMBER_ATA_SMART_ATTRIBUTES ; i++) {
if (data.thres_entries[i].id)
pout ("Attribute %3i threshold: %02x (%2i)\n",
data.thres_entries[i].id,
data.thres_entries[i].threshold,
data.thres_entries[i].threshold);
}
}
// Returns nonzero if region of memory contains non-zero entries
int nonempty(unsigned char *testarea,int n){
int i;
for (i=0;i<n;i++)
if (testarea[i])
return 1;
return 0;
}
void ataPrintSmartErrorlog (struct ata_smart_errorlog data){
int i,j,k;
pout ("SMART Error Log Version: %i\n", data.revnumber);
// if no errors logged, return
if (!data.error_log_pointer){
pout ("No Errors Logged\n\n");
return;
}
QUIETON;
// if log pointer out of range, return
if ( data.error_log_pointer>5 ){
pout("Invalid Error Log index = %02x (T13/1321D rev 1c"
"Section 8.41.6.8.2.2 gives valid range from 1 to 5)\n\n",
data.error_log_pointer);
return;
}
// starting printing error log info
if (data.ata_error_count<=5)
pout ( "ATA Error Count: %u\n", data.ata_error_count);
else
pout ( "ATA Error Count: %u (device log contains only the most recent five errors)\n",
data.ata_error_count);
QUIETOFF;
pout("\tDCR = Device Control Register\n");
pout("\tFR = Features Register\n");
pout("\tSC = Sector Count Register\n");
pout("\tSN = Sector Number Register\n");
pout("\tCL = Cylinder Low Register\n");
pout("\tCH = Cylinder High Register\n");
pout("\tD/H = Device/Head Register\n");
pout("\tCR = Content written to Command Register\n");
pout("\tER = Error register\n");
pout("\tSTA = Status register\n");
pout("Timestamp is seconds since the previous disk power-on.\n");
pout("Note: timestamp \"wraps\" after 2^32 msec = 49.710 days.\n\n");
// now step through the five error log data structures (table 39 of spec)
for (k = 4; k >= 0; k-- ) {
// The error log data structure entries are a circular buffer
i=(data.error_log_pointer+k)%5;
// Spec says: unused error log structures shall be zero filled
if (nonempty((unsigned char*)&(data.errorlog_struct[i]),sizeof(data.errorlog_struct[i]))){
char *msgstate;
switch (data.errorlog_struct[i].error_struct.state){
case 0x00: msgstate="in an unknown state";break;
case 0x01: msgstate="sleeping"; break;
case 0x02: msgstate="in standby mode"; break;
case 0x03: msgstate="active or idle"; break;
case 0x04: msgstate="doing SMART off-line or self test"; break;
default: msgstate="in a vendor specific or reserved state";
}
// See table 42 of ATA5 spec
QUIETON;
pout("Error %i occurred at disk power-on lifetime: %u hours\n",
5-k,data.errorlog_struct[i].error_struct.timestamp);
QUIETOFF;
pout("When the command that caused the error occurred, the device was %s.\n",msgstate);
pout("After command completion occurred, registers were:\n");
pout("ER:%02x SC:%02x SN:%02x CL:%02x CH:%02x D/H:%02x ST:%02x\n",
data.errorlog_struct[i].error_struct.error_register,
data.errorlog_struct[i].error_struct.sector_count,
data.errorlog_struct[i].error_struct.sector_number,
data.errorlog_struct[i].error_struct.cylinder_low,
data.errorlog_struct[i].error_struct.cylinder_high,
data.errorlog_struct[i].error_struct.drive_head,
data.errorlog_struct[i].error_struct.status);
pout("Sequence of commands leading to the command that caused the error were:\n");
pout("DCR FR SC SN CL CH D/H CR Timestamp\n");
for ( j = 4; j >= 0; j--){
struct ata_smart_errorlog_command_struct *thiscommand=&(data.errorlog_struct[i].commands[j]);
// Spec says: unused data command structures shall be zero filled
if (nonempty((unsigned char*)thiscommand,sizeof(*thiscommand)))
pout ( " %02x %02x %02x %02x %02x %02x %02x %02x %u.%03u\n",
thiscommand->devicecontrolreg,
thiscommand->featuresreg,
thiscommand->sector_count,
thiscommand->sector_number,
thiscommand->cylinder_low,
thiscommand->cylinder_high,
thiscommand->drive_head,
thiscommand->commandreg,
(unsigned int)(thiscommand->timestamp / 1000),
(unsigned int)(thiscommand->timestamp % 1000));
}
pout("\n");
}
}
QUIETON;
if (quietmode)
pout("\n");
QUIETOFF;
return;
}
// return value is number of entries found where the self-test showed an error
int ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data,int allentries){
int i,j,noheaderprinted=1;
int retval=0;
if (allentries)
pout("SMART Self-test log, version number %u\n",data.revnumber);
if (data.revnumber!=0x01 && allentries)
pout("Warning - structure revision number does not match spec!\n");
if (data.mostrecenttest==0){
if (allentries)
pout("No self-tests have been logged\n\n");
return 0;
}
// print log
for (i=20;i>=0;i--){
struct ata_smart_selftestlog_struct *log;
// log is a circular buffer
j=(i+data.mostrecenttest)%21;
log=data.selftest_struct+j;
if (nonempty((unsigned char*)log,sizeof(*log))){
char *msgtest,*msgstat,percent[64],firstlba[64];
int errorfound=0;
// test name
switch(log->selftestnumber){
case 0: msgtest="Off-line "; break;
case 1: msgtest="Short off-line "; break;
case 2: msgtest="Extended off-line "; break;
case 127: msgtest="Abort off-line test"; break;
case 129: msgtest="Short captive "; break;
case 130: msgtest="Extended captive "; break;
default: msgtest="Unknown test ";
}
// test status
switch((log->selfteststatus)>>4){
case 0:msgstat="Completed "; break;
case 1:msgstat="Aborted by host "; break;
case 2:msgstat="Interrupted (host reset) "; break;
case 3:msgstat="Fatal or unknown error "; errorfound=1; break;
case 4:msgstat="Completed: unknown failure "; errorfound=1; break;
case 5:msgstat="Completed: electrical failure"; errorfound=1; break;
case 6:msgstat="Completed: servo/seek failure"; errorfound=1; break;
case 7:msgstat="Completed: read failure "; errorfound=1; break;
case 15:msgstat="Test in progress "; break;
default:msgstat="Unknown test status ";
}
retval+=errorfound;
sprintf(percent,"%1d0%%",(log->selfteststatus)&0xf);
if (log->lbafirstfailure==0xffffffff || log->lbafirstfailure==0x00000000)
sprintf(firstlba,"%s","");
else
sprintf(firstlba,"0x%08x",log->lbafirstfailure);
if (noheaderprinted && (allentries || errorfound)){
pout("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n");
noheaderprinted=0;
}
if (allentries || errorfound)
pout("#%2d %s %s %s %8u %s\n",21-i,msgtest,msgstat,
percent,log->timestamp,firstlba);
}
}
if (!allentries && retval)
pout("\n");
return retval;
}
void ataPseudoCheckSmart ( struct ata_smart_values data,
struct ata_smart_thresholds thresholds) {
int i;
int failed = 0;
for (i = 0 ; i < NUMBER_ATA_SMART_ATTRIBUTES ; i++) {
if (data.vendor_attributes[i].id &&
thresholds.thres_entries[i].id &&
data.vendor_attributes[i].status.flag.prefailure &&
(data.vendor_attributes[i].current <= thresholds.thres_entries[i].threshold) &&
(thresholds.thres_entries[i].threshold != 0xFE)){
pout("Attribute ID %i Failed\n",data.vendor_attributes[i].id);
failed = 1;
}
}
pout("%s\n", ( failed )?
"SMART overall-health self-assessment test result: FAILED!\n"
"Drive failure expected in less than 24 hours. SAVE ALL DATA":
"SMART overall-health self-assessment test result: PASSED");
}
// Initialize to zero just in case some SMART routines don't work
struct hd_driveid drive;
struct ata_smart_values smartval;
struct ata_smart_thresholds smartthres;
struct ata_smart_errorlog smarterror;
struct ata_smart_selftestlog smartselftest;
int ataPrintMain (int fd){
int timewait,code;
int returnval=0;
// Start by getting Drive ID information. We need this, to know if SMART is supported.
if (ataReadHDIdentity(fd,&drive)){
pout("Smartctl: Hard Drive Read Identity Failed\n\n");
returnval|=FAILID;
}
// Print most drive identity information if requested
if (driveinfo){
pout("=== START OF INFORMATION SECTION ===\n");
ataPrintDriveInfo(drive);
}
// now check if drive supports SMART; otherwise time to exit
if (!ataSmartSupport(drive)){
pout("SMART support is: Unavailable - device lacks SMART capability.\n");
pout(" Checking to be sure by trying SMART ENABLE command.\n");
if (ataEnableSmart(fd)){
pout(" No SMART functionality found. Sorry.\n");
return returnval|FAILSMART;
}
else
pout(" SMART appears to work. Continuing.\n");
if (!driveinfo) pout("\n");
}
// Now print remaining drive info: is SMART enabled?
if (driveinfo){
pout("SMART support is: Available - device has SMART capability.\n");
if (ataDoesSmartWork(fd))
pout("SMART support is: Enabled\n");
else
pout("SMART support is: Disabled\n");
pout("\n");
}
// START OF THE ENABLE/DISABLE SECTION OF THE CODE
if (smartenable || smartdisable ||
smartautosaveenable || smartautosavedisable ||
smartautoofflineenable || smartautoofflinedisable)
pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
// Enable/Disable SMART commands
if (smartenable){
if (ataEnableSmart(fd)) {
pout("Smartctl: SMART Enable Failed.\n\n");
returnval|=FAILSMART;
}
else
pout("SMART Enabled.\n");
}
// From here on, every command requires that SMART be enabled...
if (!ataDoesSmartWork(fd)) {
pout("SMART Disabled. Use option -%c to enable it.\n", SMARTENABLE );
return returnval;
}
// Turn off SMART on device
if (smartdisable){
if (ataDisableSmart(fd)) {
pout( "Smartctl: SMART Disable Failed.\n\n");
returnval|=FAILSMART;
}
pout("SMART Disabled. Use option -%c to enable it.\n",SMARTENABLE);
return returnval;
}
// Let's ALWAYS issue this command to get the SMART status
code=ataSmartStatus2(fd);
if (code==-1)
returnval|=FAILSMART;
// Enable/Disable Auto-save attributes
if (smartautosaveenable){
if (ataEnableAutoSave(fd)){
pout( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n");
returnval|=FAILSMART;
}
else
pout("SMART Attribute Autosave Enabled.\n");
}
if (smartautosavedisable){
if (ataDisableAutoSave(fd)){
pout( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n");
returnval|=FAILSMART;
}
else
pout("SMART Attribute Autosave Disabled.\n");
}
// for everything else read values and thresholds are needed
if (ataReadSmartValues(fd, &smartval)){
pout("Smartctl: SMART Read Values failed.\n\n");
returnval|=FAILSMART;
}
if (ataReadSmartThresholds(fd, &smartthres)){
pout("Smartctl: SMART Read Thresholds failed.\n\n");
returnval|=FAILSMART;
}
// Enable/Disable Off-line testing
if (smartautoofflineenable){
if (!isSupportAutomaticTimer(smartval)){
pout("Warning: device does not support SMART Automatic Timers.\n\n");
}
if (ataEnableAutoOffline(fd)){
pout( "Smartctl: SMART Enable Automatic Offline Failed.\n\n");
returnval|=FAILSMART;
}
else
pout ("SMART Automatic Offline Testing Enabled every four hours.\n");
}
if (smartautoofflinedisable){
if (!isSupportAutomaticTimer(smartval)){
pout("Warning: device does not support SMART Automatic Timers.\n\n");
}
if (ataDisableAutoOffline(fd)){
pout("Smartctl: SMART Disable Automatic Offline Failed.\n\n");
returnval|=FAILSMART;
}
else
pout("SMART Automatic Offline Testing Disabled.\n");
}
// all this for a newline!
if (smartenable || smartdisable ||
smartautosaveenable || smartautosavedisable ||
smartautoofflineenable || smartautoofflinedisable)
pout("\n");
// START OF READ-ONLY OPTIONS APART FROM -V and -i
if (checksmart || generalsmartvalues || smartvendorattrib || smarterrorlog || smartselftestlog)
pout("=== START OF READ SMART DATA SECTION ===\n");
// Check SMART status (use previously returned value)
if (checksmart){
if (code) {
QUIETON;
pout("SMART overall-health self-assessment test result: FAILED!\n"
"Drive failure expected in less than 24 hours. SAVE ALL DATA.\n");
QUIETOFF;
if (ataCheckSmart(smartval, smartthres,1)){
returnval|=FAILATTR;
if (smartvendorattrib)
pout("See vendor-specific Attribute list for failed Attributes.\n\n");
else {
QUIETON;
pout("Failed Attributes:\n");
PrintSmartAttribWithThres(smartval, smartthres,1);
}
}
else
pout("No failed Attributes found.\n\n");
returnval|=FAILSTATUS;
QUIETOFF;
}
else {
pout("SMART overall-health self-assessment test result: PASSED\n");
if (ataCheckSmart(smartval, smartthres,0)){
if (smartvendorattrib)
pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
else {
QUIETON;
pout("Please note the following marginal attributes:\n");
PrintSmartAttribWithThres(smartval, smartthres,2);
}
returnval|=FAILAGE;
}
else
pout("\n");
}
QUIETOFF;
}
// Print general SMART values
if (generalsmartvalues)
ataPrintGeneralSmartValues(smartval);
// Print vendor-specific attributes
if (smartvendorattrib){
QUIETON;
PrintSmartAttribWithThres(smartval, smartthres,quietmode?2:0);
QUIETOFF;
}
// Print SMART error log
if (smarterrorlog){
if (!isSmartErrorLogCapable(smartval))
pout("Warning: device does not support Error Logging\n");
if (ataReadErrorLog(fd, &smarterror)){
pout("Smartctl: SMART Errorlog Read Failed\n");
returnval|=FAILSMART;
}
else {
// turn on quiet mode inside this
ataPrintSmartErrorlog(smarterror);
QUIETOFF;
}
}
// Print SMART self-test log
if (smartselftestlog){
if (!isSmartErrorLogCapable(smartval))
pout("Warning: device does not support Self Test Logging\n");
else {
if(ataReadSelfTestLog(fd, &smartselftest)){
pout("Smartctl: SMART Self Test Log Read Failed\n");
returnval|=FAILSMART;
}
else {
QUIETON;
if (ataPrintSmartSelfTestlog(smartselftest,!quietmode))
returnval|=FAILLOG;
QUIETOFF;
pout("\n");
}
}
}
// START OF THE TESTING SECTION OF THE CODE. IF NO TESTING, RETURN
if (testcase==-1)
return returnval;
pout("=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n");
// if doing a self-test, be sure it's supported by the hardware
if (testcase==OFFLINE_FULL_SCAN && !isSupportExecuteOfflineImmediate(smartval))
pout("Warning: device does not support Execute Off-Line Immediate function.\n\n");
else if (!isSupportSelfTest(smartval))
pout ("Warning: device does not support Self-Test functions.\n\n");
// Now do the test
if (ataSmartTest(fd, testcase))
return returnval|=FAILSMART;
// Tell user how long test will take to complete
if ((timewait=TestTime(smartval,testcase))){
pout ("Please wait %d %s for test to complete.\n",
timewait, testcase==OFFLINE_FULL_SCAN?"seconds":"minutes");
if (testcase!=SHORT_CAPTIVE_SELF_TEST && testcase!=EXTEND_CAPTIVE_SELF_TEST)
pout ("Use smartctl -%c to abort test.\n", SMARTSELFTESTABORT);
}
return returnval;
}