// $Id: ataprint.cpp,v 1.1 2002/10/09 17:56:58 ballen4705 Exp $ /* * ataprint.c * * Copyright (C) 2002 Bruce Allen <ballen@uwm.edu> * 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. */ #include "ataprint.h" #include "smartctl.h" #include "extern.h" void ataPrintDriveInfo (struct hd_driveid drive) { printf ("Device: %.40s Supports ATA Version %i\n", drive.model, ataVersionInfo ( drive) ); printf("Serial Number: %.20s\n",drive.serial_no); printf("Firmware Version: %.8s\n",drive.fw_rev); printf("ATA minor number (version support) 0x%02x\n",drive.minor_rev_num); } /* void PrintSmartOfflineStatus ( struct ata_smart_values data) prints verbose value Off-line data collection status byte */ void PrintSmartOfflineStatus ( struct ata_smart_values data) { printf ("Off-line data collection status: "); switch (data.offline_data_collection_status) { case 0x0: case 0x80: printf ("(0x%02x)\tOffline data collection activity was\n\t\t\t\t\t", data.offline_data_collection_status); printf("never started\n"); break; case 0x01: case 0x81: printf ("(0x%02x)\tReserved\n", data.offline_data_collection_status); break; case 0x02: case 0x82: printf ("(0x%02x)\tOffline data collection activity \n\t\t\t\t\t", data.offline_data_collection_status); printf ("completed without error\n"); break; case 0x03: case 0x83: printf ("(0x%02x)\tReserved\n", data.offline_data_collection_status); break; case 0x04: case 0x84: printf ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", data.offline_data_collection_status); printf ("suspended by an interrupting command\n"); break; case 0x05: case 0x85: printf ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", data.offline_data_collection_status); printf ("aborted by an interrupting command\n"); break; case 0x06: case 0x86: printf ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", data.offline_data_collection_status); printf ("aborted by the device with 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)) ) { printf ("(0x%02x)\tVendor Specific\n", data.offline_data_collection_status); } else { printf ("(0x%02x)\tReserved\n", data.offline_data_collection_status); } } } void PrintSmartSelfExecStatus ( struct ata_smart_values data) { printf ("Self-test execution status: "); switch (data.self_test_exec_status >> 4) { case 0: printf ("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t", data.self_test_exec_status); printf ("without error or no self-test has ever \n\t\t\t\t\tbeen run\n"); break; case 1: printf ("(%4d)\tThe self-test routine was aborted by\n\t\t\t\t\t", data.self_test_exec_status); printf ("the host\n"); break; case 2: printf ("(%4d)\tThe self-test routine was interrupted\n\t\t\t\t\t", data.self_test_exec_status); printf ("by the host with a hard or soft reset\n"); break; case 3: printf ("(%4d)\tA fatal error or unknown test error\n\t\t\t\t\t", data.self_test_exec_status); printf ("occurred while the device was executing\n\t\t\t\t\t"); printf ("its self-test routine and the device \n\t\t\t\t\t"); printf ("was unable to complete the self-test \n\t\t\t\t\t"); printf ("routine\n"); break; case 4: printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); printf ("a test element that failed and the test\n\t\t\t\t\t"); printf ("element that failed is not known\n"); break; case 5: printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); printf ("the electrical element of the test\n\t\t\t\t\t"); printf ("failed\n"); break; case 6: printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); printf ("the servo (and/or seek) element of the \n\t\t\t\t\t"); printf ("test failed\n"); break; case 7: printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); printf ("the read element of the test failed\n"); break; case 15: printf ("(%4d)\tSelf-test routine in progess\n\t\t\t\t\t", data.self_test_exec_status); printf ("%1d0%% of test remaining\n", data.self_test_exec_status & 0x0f); break; default: printf ("(%4d)\tReserved\n", data.self_test_exec_status); break; } } void PrintSmartTotalTimeCompleteOffline ( struct ata_smart_values data) { printf ("Total time to complete off-line \n"); printf ("data collection: \t\t (%4d) Seconds\n", data.total_time_to_complete_off_line); } void PrintSmartOfflineCollectCap ( struct ata_smart_values data) { printf ("Offline data collection \n"); printf ("Capabilities: \t\t\t (0x%02x)", data.offline_data_collection_capability); if (data.offline_data_collection_capability == 0x00) { printf ("\tOff-line data collection not supported\n"); } else { printf( "%s\n", isSupportExecuteOfflineImmediate(data)? "SMART EXECUTE OFF-LINE IMMEDIATE" : "NO SMART EXECUTE OFF-LINE IMMEDIATE"); printf( "\t\t\t\t\t%s\n", isSupportAutomaticTimer(data)? "Automatic timer ON/OFF support": "NO Automatic timer ON/OFF support"); printf( "\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"); printf( "\t\t\t\t\t%s\n", isSupportOfflineSurfaceScan(data)? "Offline surface scan supported": "NO Offline surface scan supported"); printf( "\t\t\t\t\t%s\n", isSupportSelfTest(data)? "Self-test supported": "NO Self-test supported"); } } void PrintSmartCapability ( struct ata_smart_values data) { printf ("Smart Capablilities: "); printf ("(0x%04x)\t", data.smart_capability); if (data.smart_capability == 0x00) { printf ("automatic saving of SMART data"); printf ("\t\t\t\t\tis not implemented\n"); } else { printf( "%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 ) { printf ("\t\t\t\t\tSupports SMART auto save timer\n"); } } } void PrintSmartErrorLogCapability ( struct ata_smart_values data) { printf ("Error logging capability: "); if ( isSmartErrorLogCapable(data) ) { printf (" (0x%02x)\tError logging supported\n", data.errorlog_capability); } else { printf (" (0x%02x)\tError logging NOT supported\n", data.errorlog_capability); } } void PrintSmartShortSelfTestPollingTime ( struct ata_smart_values data) { if ( isSupportSelfTest(data) ) { printf ("Short self-test routine \n"); printf ("recommended polling time: \t (%4d) Minutes\n", data.short_test_completion_time); } else { printf ("Short self-test routine \n"); printf ("recommended polling time: \t Not Supported\n"); } } void PrintSmartExtendedSelfTestPollingTime ( struct ata_smart_values data) { if ( isSupportSelfTest(data) ) { printf ("Extended self-test routine \n"); printf ("recommended polling time: \t (%4d) Minutes\n", data.extend_test_completion_time); } else { printf ("Extended self-test routine \n"); printf ("recommended polling time: \t Not Supported\n"); } } void PrintSmartAttribWithThres ( struct ata_smart_values data, struct ata_smart_thresholds thresholds) { int i,j; long long rawvalue; printf ("Vendor Specific SMART Attributes with Thresholds:\n"); printf ("Revision Number: %i\n", data.revnumber); printf ("Attribute Flag Value Worst Threshold Raw Value\n"); for ( i = 0 ; i < 30 ; i++ ) { if ( (data.vendor_attributes[i].id !=0) && (thresholds.thres_entries[i].id != 0)) { ataPrintSmartAttribName(data.vendor_attributes[i].id); printf(" 0x%04x %.3i %.3i %.3i ", data.vendor_attributes[i].status.all, data.vendor_attributes[i].current, data.vendor_attributes[i].worst, thresholds.thres_entries[i].threshold); rawvalue = 0; for (j = 0 ; j < 6 ; j++) { rawvalue |= data.vendor_attributes[i].raw[j] << (8*j) ; } /* handle IBM raw format */ if (data.vendor_attributes[i].id!=194 || rawvalue<200) printf ("%llu\n", rawvalue); else printf("First: %u Second: %u Third: %u\n", data.vendor_attributes[i].raw[0], data.vendor_attributes[i].raw[2], data.vendor_attributes[i].raw[4]); } } } void ataPrintGeneralSmartValues ( struct ata_smart_values data) { printf ("\nGeneral Smart Values: \n"); PrintSmartOfflineStatus (data); printf("\n"); if (isSupportSelfTest(data)) { PrintSmartSelfExecStatus (data); printf("\n"); } PrintSmartTotalTimeCompleteOffline (data); printf("\n"); PrintSmartOfflineCollectCap (data); printf("\n"); PrintSmartCapability ( data); printf("\n"); PrintSmartErrorLogCapability (data); printf ("\n"); if (isSupportSelfTest(data)) { PrintSmartShortSelfTestPollingTime (data); printf ("\n"); PrintSmartExtendedSelfTestPollingTime (data); printf ("\n"); } } void ataPrintSmartThresholds (struct ata_smart_thresholds data) { int i; printf ("Smart Thresholds\n"); printf ("Smart Threshold Revision Number: %i\n", data.revnumber); for ( i = 0 ; i < 30 ; i++) { if (data.thres_entries[i].id != 0) printf ("Atrribute %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; printf ("\nSMART Error Log\n"); printf ( "SMART Error Logging Version: %i\n", data.revnumber); // if no errors logged, return if ( ! data.error_log_pointer) { printf ("No Errors Logged\n"); return; } // if log pointer out of range, return if ( data.error_log_pointer>5 ){ printf("Invalid Error log index = %02x (T13/1321D rev 1c" "Section 8.41.6.8.2.2 gives valid range from 1 to 5)\n", data.error_log_pointer); return; } // starting printing error log info if (data.ata_error_count<=5) printf ( "ATA Error Count: %u\n\n", data.ata_error_count); else printf ( "ATA Error Count: %u (note: only most recent five errors are shown below)\n\n", data.ata_error_count); printf( "Acronyms used below:\n"); printf( "DCR = Device Control Register\n"); printf( "FR = Features Register\n"); printf( "SC = Sector Count Register\n"); printf( "SN = Sector Number Register\n"); printf( "CL = Cylinder Low Register\n"); printf( "CH = Cylinder High Register\n"); printf( "D/H = Device/Head Register\n"); printf( "CR = Content written to Command Register\n"); printf( "ER = Error register\n"); printf( "STA = Status register\n\n"); printf( "Timestamp is time (in seconds) since the command that caused an error was accepted,\n"); printf( "measured from the time the disk was powered-on, during the session when the error occured.\n"); printf( "Note: timestamp \"wraps\" after 1193.046 hours = 49.710 days = 2^32 seconds.\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"; } printf("\nError Log Structure %i:\n",5-k); // See table 42 of ATA5 spec printf("Error occured at disk power-on lifetime: %u hours\n", data.errorlog_struct[i].error_struct.timestamp); printf("When the command that caused the error occured, the device was %s.\n",msgstate); printf("After command completion occured, registers were:\n"); printf("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); printf("Sequence of commands leading to the command that caused the error were:\n"); printf("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))) printf ( " %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)); } } } return; } void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data){ int i,j; printf("\nSMART Self-test log, version number %u\n",data.revnumber); if (data.revnumber!=0x01) printf("Warning - structure revision number does not match spec!\n"); if (data.mostrecenttest==0){ printf("No self-test have been logged\n"); return; } // print log printf("\nNum Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n"); 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[16],firstlba[16]; // 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 "; break; case 4:msgstat="Completed: unknown failure "; break; case 5:msgstat="Completed: electrical failure"; break; case 6:msgstat="Completed: servo/seek failure"; break; case 7:msgstat="Completed: read failure "; break; case 15:msgstat="Test in progress "; break; default:msgstat="Unknown test status "; } sprintf(percent,"%1d0%%",(log->selfteststatus)&0xf); if (log->lbafirstfailure==0xffffffff || log->lbafirstfailure==0x00000000) sprintf(firstlba,"%s",""); else sprintf(firstlba,"0x%08x",log->lbafirstfailure); printf("#%2d %s %s %s %8u %s\n", 21-i, msgtest, msgstat, percent, log->timestamp, firstlba); } else return; } return; } void ataPsuedoCheckSmart ( struct ata_smart_values data, struct ata_smart_thresholds thresholds) { int i; int failed = 0; for ( i = 0 ; i < 30 ; i++ ) { if ( (data.vendor_attributes[i].id !=0) && (thresholds.thres_entries[i].id != 0) && ( data.vendor_attributes[i].status.flag.prefailure) && ( data.vendor_attributes[i].current < thresholds.thres_entries[i].threshold) && (thresholds.thres_entries[i].threshold != 0xFE) ) { printf("Attribute ID %i Failed\n", data.vendor_attributes[i].id); failed = 1; } } printf("%s\n", ( failed )? "Please save all data and call drive manufacture immediately.": "Check S.M.A.R.T. Passed."); } void ataPrintSmartAttribName ( unsigned char id ) { switch (id) { case 1: printf("( 1)Raw Read Error Rate "); break; case 2: printf("( 2)Throughput Performance "); break; case 3: printf("( 3)Spin Up Time "); break; case 4: printf("( 4)Start Stop Count "); break; case 5: printf("( 5)Reallocated Sector Ct "); break; case 6: printf("( 6)Read Channel Margin "); break; case 7: printf("( 7)Seek Error Rate "); break; case 8: printf("( 8)Seek Time Preformance "); break; case 9: printf("( 9)Power On Hours "); break; case 10: printf("( 10)Spin Retry Count "); break; case 11: printf("( 11)Calibration Retry Count"); break; case 12: printf("( 12)Power Cycle Count "); break; case 13: printf("( 13)Read Soft Error Rate "); break; case 191: printf("(191)Gsense Error Rate "); break; case 192: printf("(192)Power-Off Retract Count"); break; case 193: printf("(193)Load Cycle Count "); break; case 194: printf("(194)Temperature "); break; case 195: printf("(195)Hardware ECC Recovered "); break; case 196: printf("(196)Reallocated Event Count"); break; case 197: printf("(197)Current Pending Sector "); break; case 198: printf("(198)Offline Uncorrectable "); break; case 199: printf("(199)UDMA CRC Error Count "); break; default: printf("(%3d)Unknown Attribute ", id); break; } } /**** Called by smartctl to access ataprint **/ void ataPrintMain ( int fd ) { struct hd_driveid drive; struct ata_smart_values smartval; struct ata_smart_thresholds smartthres; struct ata_smart_errorlog smarterror; struct ata_smart_selftestlog smartselftest; if ( driveinfo ) { if ( ataReadHDIdentity ( fd, &drive) != 0 ) { printf("Smartctl: Hard Drive Identity Failed\n"); exit(0); } ataPrintDriveInfo(drive); if (ataSmartSupport(drive)) { printf ("Drive supports S.M.A.R.T. and is "); if ( ataSmartStatus(fd) != 0) { printf( "disabled\n"); printf( "Use option -%c to enable\n", SMARTENABLE ); exit(0); } else { printf( "enabled\n"); } } else { printf("Drive does not support S.M.A.R.T.\n"); exit (0); } } if ( smartdisable ) { if ( ataDisableSmart(fd) != 0) { printf( "Smartctl: Smart Enable Failed\n"); exit(-1); } printf("S.M.A.R.T. Disabled\n"); exit (0); } if ( smartenable ) { if ( ataEnableSmart(fd) != 0) { printf( "Smartctl: Smart Enable Failed\n"); exit(-1); } if (ataSmartStatus(fd)==0) printf("S.M.A.R.T. Enabled\n"); else printf( "Smartctl: Smart Enable Failed for unknown reasons\n"); } if ( smartautosavedisable ){ if (ataDisableAutoSave(fd) != 0) { printf( "Smartctl: Smart Disable Atribute Autosave Failed\n"); exit(-1); } printf("S.M.A.R.T. Atribute Autosave Disabled\n"); } if ( smartautosaveenable ){ if (ataEnableAutoSave(fd) != 0) { printf( "Smartctl: Smart Enable Atribute Autosave Failed\n"); exit(-1); } printf("S.M.A.R.T. Atribute Autosave Enabled\n"); } /* for everything else read values and thresholds are needed */ if ( ataReadSmartValues ( fd, &smartval) != 0 ) { printf("Smartctl: Smart Values Read Failed\n"); exit (-1); } if ( ataReadSmartThresholds ( fd, &smartthres) != 0 ) { printf("Smartctl: Smart THresholds Read Failed\n"); exit (-1); } if ( checksmart ) { /* pseudo is used because linux does not support access to Task Fiule registers */ ataPsuedoCheckSmart ( smartval , smartthres); } if ( generalsmartvalues ) { ataPrintGeneralSmartValues( smartval ); } if ( smartvendorattrib ) { PrintSmartAttribWithThres( smartval, smartthres); } if ( smarterrorlog ) { if ( isSmartErrorLogCapable(smartval) == 0) { printf("Device does not support Error Logging\n"); } else { if ( ataReadErrorLog ( fd, &smarterror) != 0 ) { printf("Smartctl: Smart Errorlog Read Failed\n"); } else { ataPrintSmartErrorlog ( smarterror); } } } if ( smartselftestlog ) { if ( isSmartErrorLogCapable(smartval) == 0) { printf("Device does not support Self Test Logging\n"); } else { if ( ataReadSelfTestLog( fd, &smartselftest) != 0 ) { printf("Smartctl: Smart Self Test log Read Failed\n"); } else { ataPrintSmartSelfTestlog (smartselftest); } } } if ( smartautoofflineenable ) { if ( !isSupportAutomaticTimer (smartval)) { printf("Device does not support S.M.A.R.T. Automatic Timers\n"); exit(-1); } if ( ataEnableAutoOffline (fd) != 0) { printf( "Smartctl: Smart Enable Automatic Offline Failed\n"); exit(-1); } printf ("S.M.A.R.T. Automatic Offline Testing Enabled every four hours\n"); } if ( smartautoofflinedisable ) { if ( !isSupportAutomaticTimer (smartval)) { printf("Device does not support S.M.A.R.T. Automatic Timers\n"); exit(-1); } if ( ataDisableAutoOffline (fd) != 0) { printf( "Smartctl: Smart Disable Automatic Offline Failed\n"); exit(-1); } printf ("S.M.A.R.T. Automatic Offline Testing Disabled\n"); } if ( smartexeoffimmediate ) { if ( ataSmartOfflineTest (fd) != 0) { printf( "Smartctl: Smart Offline Failed\n"); exit(-1); } printf ("Drive Command Successful offline test has begun\n"); printf ("Please wait %d seconds for test to complete\n", isOfflineTestTime(smartval) ); printf ("Use smartctl -%c to abort test\n", SMARTSELFTESTABORT); exit (0); } if ( smartshortcapselftest ) { if ( ! isSupportSelfTest(smartval) ) { printf (" ERROR: device does not support Self-Test function\n"); exit(-1); } if ( ataSmartShortCapSelfTest (fd) != 0) { printf( "Smartctl: Smart Short Self Test Failed\n"); exit(-1); } printf ("Drive Command Successful offline test has begun\n"); printf ("Please wait %d minutes for test to complete\n", isShortSelfTestTime (smartval) ); printf ("Use smartctl -%c to abort test\n", SMARTSELFTESTABORT); /* Make sure Offline testing is last thing done */ exit (0); } if ( smartshortselftest ) { if ( ! isSupportSelfTest(smartval) ) { printf (" ERROR: device does not support Self-Test function\n"); exit(-1); } if ( ataSmartShortSelfTest (fd) != 0) { printf( "Smartctl: Smart Short Self Test Failed\n"); exit(-1); } printf ("Drive Command Successful offline test has begun\n"); printf ("Please wait %d minutes for test to complete\n", isShortSelfTestTime (smartval) ); printf ("Use smartctl -%c to abort test\n", SMARTSELFTESTABORT); /* Make sure Offline testing is last thing done */ exit (0); } if ( smartextendselftest ) { if ( ! isSupportSelfTest(smartval) ) { printf (" ERROR: device does not support Self-Test function\n"); exit(-1); } if ( ataSmartExtendSelfTest (fd) != 0) { printf( "S.M.A.R.T. Extendend Self Test Failed\n"); exit(-1); } printf ("Drive Command Successful self test has begun\n"); printf ("Please wait %d minutes for test to complete\n", isExtendedSelfTestTime(smartval) ); printf ("Use smartctl -%c to abort test\n", SMARTSELFTESTABORT); exit (0); } if ( smartextendcapselftest ) { if ( ! isSupportSelfTest(smartval) ) { printf (" ERROR: device does not support self test function\n"); exit(-1); } if ( ataSmartExtendCapSelfTest (fd) != 0) { printf( "S.M.A.R.T. Extendend Self Test Failed\n"); exit(-1); } printf ("Drive Command Successful captive extended self test has begun\n"); printf ("Please wait %d minutes for test to complete\n", isExtendedSelfTestTime(smartval) ); printf ("Use smartctl -%c to abort test\n", SMARTSELFTESTABORT); exit (0); } if ( smartselftestabort ) { if ( ! isSupportSelfTest(smartval) ) { printf (" ERROR: device does not support Self-Test function\n"); exit(-1); } if ( ataSmartSelfTestAbort (fd) != 0) { printf( "S.M.A.R.T. Self Test Abort Failed\n"); exit(-1); } printf ("Drive Command Successful self test aborted\n"); } }