Skip to content
Snippets Groups Projects
Commit c916c4c1 authored by ballen4705's avatar ballen4705
Browse files

Code changes to use simpler control flow through ataPrintMain, and to handle

multiple options more gracefully and logically.


git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@68 4ea69e1a-61f1-4043-bf83-b5c94c648137
parent 630ec855
No related branches found
No related tags found
No related merge requests found
// $Id: atacmds.c,v 1.8 2002/10/15 14:24:26 ballen4705 Exp $
// $Id: atacmds.c,v 1.9 2002/10/20 19:22:02 ballen4705 Exp $
/*
* atacmds.c
*
......@@ -27,11 +27,15 @@
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include "atacmds.h"
// These Drive Identity tables are taken from hdparm 5.2. That's the
// "Gold Standard"
// These Drive Identity tables are taken from hdparm 5.2, and are also
// given in the ATA/ATAPI specs for the IDENTIFY DEVICE command. Note
// that SMART 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.
#define NOVAL_0 0x0000
#define NOVAL_1 0xffff
/* word 81: minor version number */
......@@ -45,10 +49,10 @@ const char *minor_str[] = { /* word 81 value: */
"ATA-2 X3T10 948D prior to revision 2k", /* 0x0005 */
"ATA-3 X3T10 2008D revision 1", /* 0x0006 */
"ATA-2 X3T10 948D revision 2k", /* 0x0007 */
"ATA-3 X3T10 2008D revision 0", /* 0x0008 */
"ATA-3 X3T10 2008D revision 0", /* 0x0008 */ /* SMART NOT INCLUDED */
"ATA-2 X3T10 948D revision 3", /* 0x0009 */
"ATA-3 published, ANSI X3.298-199x", /* 0x000a */
"ATA-3 X3T10 2008D revision 6", /* 0x000b */
"ATA-3 X3T10 2008D revision 6", /* 0x000b */ /* 1st VERSION WITH SMART */
"ATA-3 X3T13 2008D revision 7 and 7a", /* 0x000c */
"ATA/ATAPI-4 X3T13 1153D revision 6", /* 0x000d */
"ATA/ATAPI-4 T13 1153D revision 13", /* 0x000e */
......@@ -71,7 +75,7 @@ const char *minor_str[] = { /* word 81 value: */
"reserved" /* 0x001f-0xfffe*/
};
const char actual_ver[] = {
const int actual_ver[] = {
/* word 81 value: */
0, /* 0x0000 WARNING: */
1, /* 0x0001 WARNING: */
......@@ -81,7 +85,7 @@ const char actual_ver[] = {
2, /* 0x0005 WARNING: corresponds */
3, /* 0x0006 WARNING: *exactly* */
2, /* 0x0007 WARNING: to the ATA/ */
3, /* 0x0008 WARNING: ATAPI version */
-3, /*<== */ /* 0x0008 WARNING: ATAPI version */
2, /* 0x0009 WARNING: listed in */
3, /* 0x000a WARNING: the */
3, /* 0x000b WARNING: minor_str */
......@@ -106,19 +110,72 @@ const char actual_ver[] = {
};
// Used to warn users about invalid checksums. However we will not
// abort on invalid checksums.
void checksumwarning(const char *string){
printf("Warning! %s error: invalid checksum.\n",string);
fprintf(stderr,"Warning! %s error: invalid checksum.\n",string);
syslog(LOG_INFO,"Warning! %s error: invalid checksum.\n",string);
return;
}
int ataReadHDIdentity ( int device, struct hd_driveid *buf)
{
if (ioctl ( device , HDIO_GET_IDENTITY, buf ) != 0)
{
// We no longer use this function, because the IOCTL appears to return
// only the drive identity at the time that the system was booted
// (perhaps from the BIOS. It doesn't correctly reflect the current
// state information, and for example the checksum is usually
// wrong. The replacement function follows afterwards
#if (0)
int ataReadHDIdentity ( int device, struct hd_driveid *buf){
if (ioctl(device, HDIO_GET_IDENTITY, buf )){
perror ("ATA GET HD Failed");
return -1;
}
return 0;
}
#endif
// Reads current Device Identity info (512 bytes) into buf
int ataReadHDIdentity (int device, struct hd_driveid *buf){
unsigned char parms[HDIO_DRIVE_CMD_HDR_SIZE+sizeof(*buf)]=
{WIN_IDENTIFY, 0, 0, 1,};
if (ioctl(device ,HDIO_DRIVE_CMD,parms)){
perror ("ATA GET HD Identity Failed");
return -1;
}
// copy data into driveid structure
memcpy(buf,parms+HDIO_DRIVE_CMD_HDR_SIZE,sizeof(*buf));
// If driveid structure contains a checksum, then compute it, and
// issue a warning message if something is wrong. I prefer this
// rather than simply exiting at this point, though that is another
// option.
// Note -- the declaration that appears in
// /usr/include/linux/hdregs.h: short words160_255[95], is WRONG.
// It should say: short words160_255[96]. I have written to Andre
// Hedrick about this on Oct 17 2002. Please remove this comment
// once the fix has made it into the stock kernel tree.
if ((buf->words160_255[95] & 0x00ff) == 0x00a5){
unsigned char cksum=0;
int i;
for (i=0;i<sizeof(*buf);i++)
cksum+=parms[i+HDIO_DRIVE_CMD_HDR_SIZE];
if (cksum)
checksumwarning("Drive Identity Structure");
}
return 0;
}
// Returns ATA version as an integer, and a pointer to a string
// describing which revision. Note that Revision 0 of ATA-3 does NOT
// support SMART. For this one case we return -3 rather than +3 as
// the version number. See notes above.
int ataVersionInfo (const char** description, struct hd_driveid drive){
unsigned short major,minor;
int i,atavalue=0;
......@@ -157,17 +214,47 @@ int ataVersionInfo (const char** description, struct hd_driveid drive){
return atavalue;
}
// returns 1 if SMART supported, 0 if not supported or can't tell
int ataSmartSupport(struct hd_driveid drive){
unsigned short word82,word83;
// get correct bits of IDENTIFY DEVICE structure
#ifdef __NEW_HD_DRIVE_ID
if (drive.command_set_1 & 0x0001)
word82=drive.command_set_1;
word83=drive.command_set_2;
#else
if (drive.command_sets & 0x0001)
word82=drive.command_sets;
word83=drive.word83;
#endif
return 1; /* drive supports S.M.A.R.T. and is disabled */
return 0;
// Note this does not work for ATA3 < Revision 6, when word82 and word83 were added
// we should check for ATA3 Rev 0 in minor identity code...
return (word83 & 0x0001<<14) && !(word83 & 0x0001<<15) && (word82 & 0x0001);
}
// returns 1 if SMART enabled, 0 if SMART disabled, -1 if can't tell
int ataIsSmartEnabled(struct hd_driveid drive){
unsigned short word85,word87;
// Get correct bits of IDENTIFY DRIVE structure
#ifdef __NEW_HD_DRIVE_ID
word85=drive.cfs_enable_1;
word87=drive.csf_default;
#else
word85=drive.word85;
word87=drive.word87;
#endif
if ((word87 & 0x0001<<14) && !(word87 & 0x0001<<15))
// word85 contains valid information, so
return word85 & 0x0001;
// Since we can't rely word85, we don't know if SMART is enabled.
return -1;
}
// Reads SMART attributes into *data
int ataReadSmartValues(int device, struct ata_smart_values *data){
int i;
unsigned char chksum=0;
......@@ -175,7 +262,7 @@ int ataReadSmartValues (int device, struct ata_smart_values *data){
{WIN_SMART, 0, SMART_READ_VALUES, 1};
if (ioctl(device,HDIO_DRIVE_CMD,buf)){
perror ("Smart Values Read failed");
perror ("SMART Values Read failed");
return -1;
}
......@@ -184,10 +271,8 @@ int ataReadSmartValues (int device, struct ata_smart_values *data){
chksum+=buf[i+HDIO_DRIVE_CMD_HDR_SIZE];
// verify that checksum vanishes
if (chksum){
perror ("Smart Read Failed, Checksum error!");
return -1;
}
if (chksum)
checksumwarning("SMART Data Structure");
// copy data and return
memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE,ATA_SMART_SEC_SIZE);
......@@ -195,91 +280,95 @@ int ataReadSmartValues (int device, struct ata_smart_values *data){
}
int ataReadSelfTestLog (int device, struct ata_smart_selftestlog *data)
{
// Reads the Self Test Log (log #6)
int ataReadSelfTestLog (int device, struct ata_smart_selftestlog *data){
int i;
unsigned char chksum=0;
unsigned char buf[ HDIO_DRIVE_CMD_HDR_SIZE +
ATA_SMART_SEC_SIZE] =
{ WIN_SMART, 0x06, SMART_READ_LOG_SECTOR, 1};
unsigned char buf[HDIO_DRIVE_CMD_HDR_SIZE+ATA_SMART_SEC_SIZE] =
{WIN_SMART, 0x06, SMART_READ_LOG_SECTOR, 1,};
if (ioctl ( device , HDIO_DRIVE_CMD, (unsigned char *) &buf ) != 0)
{
perror ("Smart Error Log Read failed");
// get data from device
if (ioctl(device, HDIO_DRIVE_CMD, buf)){
perror ("SMART Error Log Read failed");
return -1;
}
// compute checksum
// compute its checksum, and issue a warning if needed
for (i=0;i<ATA_SMART_SEC_SIZE;i++)
chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
if (chksum)
checksumwarning("SMART Self-Test Log");
if (chksum){
fprintf(stderr,"Smart Self Test Log Checksum Incorrect!\n");
return -1;
}
memcpy( data, &buf[HDIO_DRIVE_CMD_HDR_SIZE] , ATA_SMART_SEC_SIZE);
// copy data back to the user and return
memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE);
return 0;
}
int ataReadErrorLog (int device, struct ata_smart_errorlog *data)
{
// Reads the Error Log (log #1)
int ataReadErrorLog (int device, struct ata_smart_errorlog *data){
int i;
unsigned char chksum=0;
unsigned char buf[ HDIO_DRIVE_CMD_HDR_SIZE +
ATA_SMART_SEC_SIZE] =
{ WIN_SMART, 0x01, SMART_READ_LOG_SECTOR, 1};
unsigned char buf[HDIO_DRIVE_CMD_HDR_SIZE+ATA_SMART_SEC_SIZE] =
{WIN_SMART, 0x01, SMART_READ_LOG_SECTOR, 1,};
if (ioctl ( device , HDIO_DRIVE_CMD, (unsigned char *) &buf ) != 0)
{
perror ("Smart Error Log Read failed");
// get data from device
if (ioctl(device,HDIO_DRIVE_CMD,&buf)) {
perror ("SMART Error Log Read failed");
return -1;
}
// compute checksum
// compute checksum and issue warning if needed
for (i=0;i<ATA_SMART_SEC_SIZE;i++)
chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
if (chksum)
checksumwarning("SMART Error Log");
if (chksum){
fprintf(stderr,"Smart Error Log Checksum Incorrect!\n");
return -1;
}
memcpy( data, &buf[HDIO_DRIVE_CMD_HDR_SIZE] , ATA_SMART_SEC_SIZE);
//copy data back to user and return
memcpy(data, buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE);
return 0;
}
int ataReadSmartThresholds ( int device, struct ata_smart_thresholds *data)
{
unsigned char buf[ HDIO_DRIVE_CMD_HDR_SIZE +
ATA_SMART_SEC_SIZE] =
{ WIN_SMART, 1, SMART_READ_THRESHOLDS, 1};
// This routine is marked as "Obsolete" in the ATA-5 spec, but it's
// very important for us. Together with the SMART READ DATA command
// above, it's the only way for us to find out if the SMART status is
// good or not. Hopefully this will get fixed -- I will find a way to
// get SMART Status directly.
int ataReadSmartThresholds ( int device, struct ata_smart_thresholds *data){
int i;
unsigned char chksum=0;
unsigned char buf[HDIO_DRIVE_CMD_HDR_SIZE+ATA_SMART_SEC_SIZE] =
{WIN_SMART, 1, SMART_READ_THRESHOLDS, 1,};
if (ioctl ( device , HDIO_DRIVE_CMD, (unsigned char *) &buf ) != 0)
{
perror ("Smart Thresholds Read failed");
// get data from device
if (ioctl(device ,HDIO_DRIVE_CMD, buf)){
perror ("SMART Thresholds Read failed");
return -1;
}
memcpy( data, &buf[HDIO_DRIVE_CMD_HDR_SIZE] , ATA_SMART_SEC_SIZE);
// compute checksum and issue warning if needed
for (i=0;i<ATA_SMART_SEC_SIZE;i++)
chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
if (chksum)
checksumwarning("SMART Attribute Thresholds");
// copy data back to user and return
memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE);
return 0;
}
int ataSetSmartThresholds ( int device, struct ata_smart_thresholds *data)
{
unsigned char buf[ HDIO_DRIVE_CMD_HDR_SIZE +
ATA_SMART_SEC_SIZE] =
{ WIN_SMART, 1, 0xD7, 1};
memcpy( &buf[HDIO_DRIVE_CMD_HDR_SIZE], data , ATA_SMART_SEC_SIZE);
// This routine is not currently in use, and it's been marked as
// "Obsolete" in the ANSI ATA-5 spec. So it should probably be left
// alone and unused.
int ataSetSmartThresholds ( int device, struct ata_smart_thresholds *data){
unsigned char buf[HDIO_DRIVE_CMD_HDR_SIZE+ATA_SMART_SEC_SIZE] =
{WIN_SMART, 1, 0xD7, 1,};
if (ioctl ( device , HDIO_DRIVE_CMD, (unsigned char *) &buf ) != 0)
{
perror ("Smart Thresholds Read failed");
memcpy(buf+HDIO_DRIVE_CMD_HDR_SIZE, data, ATA_SMART_SEC_SIZE);
if (ioctl(device, HDIO_DRIVE_CMD, buf)){
perror ("SMART Thresholds Read failed");
return -1;
}
......@@ -287,14 +376,11 @@ int ataSetSmartThresholds ( int device, struct ata_smart_thresholds *data)
}
int ataEnableSmart (int device )
{
int ataEnableSmart (int device ){
unsigned char parms[4] = {WIN_SMART, 1, SMART_ENABLE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Enable failed");
if (ioctl ( device , HDIO_DRIVE_CMD, &parms )){
perror ("SMART Enable failed");
return -1;
}
......@@ -302,14 +388,11 @@ int ataEnableSmart (int device )
}
int ataDisableSmart (int device )
{
int ataDisableSmart (int device ){
unsigned char parms[4] = {WIN_SMART, 1, SMART_DISABLE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Disable failed");
if (ioctl(device , HDIO_DRIVE_CMD, parms )){
perror ("SMART Disable failed");
return -1;
}
......@@ -319,50 +402,45 @@ int ataDisableSmart (int device )
int ataEnableAutoSave(int device){
unsigned char parms[4] = {WIN_SMART, 241, SMART_AUTOSAVE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Enable Auto-save failed");
if (ioctl(device , HDIO_DRIVE_CMD, parms )){
perror ("SMART Enable Auto-save failed");
return -1;
}
return 0;
};
}
int ataDisableAutoSave(int device){
unsigned char parms[4] = {WIN_SMART, 0, SMART_AUTOSAVE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Disable Auto-save failed");
if (ioctl(device, HDIO_DRIVE_CMD, parms)){
perror ("SMART Disable Auto-save failed");
return -1;
}
return 0;
};
}
int ataEnableAutoOffline (int device )
{
// Note that in the ATA-5 standard this command is marked "OBSOLETE"
int ataEnableAutoOffline (int device ){
/* timer hard coded to 4 hours */
unsigned char parms[4] = {WIN_SMART, 248, SMART_AUTO_OFFLINE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Enable Automatic Offline failed");
if (ioctl(device , HDIO_DRIVE_CMD, parms)){
perror ("SMART Enable Automatic Offline failed");
return -1;
}
return 0;
}
int ataDisableAutoOffline (int device )
{
// Another Obsolete Command!
int ataDisableAutoOffline (int device ){
unsigned char parms[4] = {WIN_SMART, 0, SMART_AUTO_OFFLINE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Disable Automatic Offline failed");
if (ioctl(device , HDIO_DRIVE_CMD, parms)){
perror ("SMART Disable Automatic Offline failed");
return -1;
}
......@@ -371,117 +449,152 @@ int ataDisableAutoOffline (int device )
// Not being used correctly. Must examine the CL and CH registers to
// see what the smart status was. How to fix this? I don't know...
// see what the smart status was. Look at ataSmartStatus2()
int ataSmartStatus (int device ){
unsigned char parms[4] = {WIN_SMART, 0, SMART_STATUS, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms))
if (ioctl(device, HDIO_DRIVE_CMD, parms)){
perror("Return SMART Status failed");
return -1;
}
return 0;
}
// If SMART is enabled, supported, and working, then this call is
// guaranteed to return 1, else zero. Silent inverse of
// ataSmartStatus()
int ataDoesSmartWork(int device){
unsigned char parms[4] = {WIN_SMART, 0, SMART_STATUS, 0};
return !ioctl(device, HDIO_DRIVE_CMD, parms);
}
// This function needs to be properly tested and debugged. I am not
// yet sure if this is right; have asked Andre for help. May need to
// use IDE_DRIVE_TASK. Does CONFIG_IDE_TASKFILE_IO need to be
// configured into the kernel?
int ataSmartStatus2(int device){
unsigned char normal_cyl_lo=0x4f, normal_cyl_hi=0xc2;
unsigned char failed_cyl_lo=0xf4, failed_cyl_hi=0x2c;
unsigned char parms[HDIO_DRIVE_TASK_HDR_SIZE]=
{WIN_SMART, // CMD
SMART_STATUS, // FR
0, // NS
0, // SC
0, // CL
0, // CH
0 // SEL -- Andre, is this right?? Or should it be 1?
};
// load CL and CH values
parms[4]=normal_cyl_lo;
parms[5]=normal_cyl_hi;
int ataSmartTest (int device, int testtype)
{
unsigned char parms[4] = { WIN_SMART, testtype,
SMART_IMMEDIATE_OFFLINE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms) != 0)
{
perror ("Smart Offline failed");
if (ioctl(device,HDIO_DRIVE_TASK,&parms)){
perror ("SMART Status command failed.");
return -1;
}
printf("Completed Off-line command\n");
// Cyl low and Cyl high unchanged means "Good SMART status"
if (parms[4]==normal_cyl_lo && parms[5]==normal_cyl_hi)
return 0;
}
// These values mean "Bad SMART status"
if (parms[4]==failed_cyl_lo && parms[5]==failed_cyl_hi)
return 1;
int ataSmartOfflineTest (int device)
{
return ataSmartTest( device, OFFLINE_FULL_SCAN );
}
int ataSmartShortSelfTest (int device)
{
return ataSmartTest( device, SHORT_SELF_TEST );
}
// We haven't gotten output that makes sense; print out some debugging info
perror("SMART Status returned register values that don't make sense:\n");
printf("CMD=0x%02x\n",parms[0]);
printf("FR =0x%02x\n",parms[1]);
printf("NS =0x%02x\n",parms[2]);
printf("SC =0x%02x\n",parms[3]);
printf("CL =0x%02x\n",parms[4]);
printf("CH =0x%02x\n",parms[5]);
printf("SEL=0x%02x\n",parms[6]);
int ataSmartExtendSelfTest (int device)
{
return ataSmartTest( device, EXTEND_SELF_TEST );
return -1;
}
int ataSmartShortCapSelfTest (int device)
{
return ataSmartTest( device, SHORT_CAPTIVE_SELF_TEST );
// This is the way to execute ALL tests: offline, short self-test,
// extended self test, with and without captive mode, etc.
int ataSmartTest(int device, int testtype){
unsigned char parms[4] = {WIN_SMART, 0, SMART_IMMEDIATE_OFFLINE};
char cmdmsg[128],*type,*captive;
parms[1]=testtype;
// Set up strings that describe the type of test
if (testtype==SHORT_CAPTIVE_SELF_TEST || testtype==EXTEND_CAPTIVE_SELF_TEST)
captive="captive";
else
captive="off-line";
if (testtype==OFFLINE_FULL_SCAN)
type="off-line";
else if (testtype==SHORT_SELF_TEST || testtype==SHORT_CAPTIVE_SELF_TEST)
type="Short self-test";
else
type="Extended self-test";
// Print ouf message that we are sending the command to test
if (testtype==ABORT_SELF_TEST)
sprintf(cmdmsg,"Abort SMART off-line mode self-test routine");
else
sprintf(cmdmsg,"Execute SMART %s routine immediately in %s mode",type,captive);
printf("Sending command: \"%s\".\n",cmdmsg);
// Now send the command to test
if (ioctl(device , HDIO_DRIVE_CMD, parms)){
char errormsg[128];
sprintf(errormsg,"Command \"%s\" failed.\n\n",cmdmsg);
perror (errormsg);
return -1;
}
int ataSmartExtendCapSelfTest (int device)
{
return ataSmartTest( device, EXTEND_CAPTIVE_SELF_TEST );
// Since the command succeeded, tell user
if (testtype==ABORT_SELF_TEST)
printf("Self-testing aborted!\n");
else
printf("Drive command \"%s\" successful.\nTesting has begun.\n",cmdmsg);
return 0;
}
int ataSmartSelfTestAbort (int device)
{
return ataSmartTest( device, 127 );
}
/* Test Time Functions */
int isOfflineTestTime ( struct ata_smart_values data)
{
int TestTime(struct ata_smart_values data,int testtype){
switch (testtype){
case OFFLINE_FULL_SCAN:
return (int) data.total_time_to_complete_off_line;
}
int isShortSelfTestTime ( struct ata_smart_values data)
{
case SHORT_SELF_TEST:
case SHORT_CAPTIVE_SELF_TEST:
return (int) data.short_test_completion_time;
}
int isExtendedSelfTestTime ( struct ata_smart_values data)
{
case EXTEND_SELF_TEST:
case EXTEND_CAPTIVE_SELF_TEST:
return (int) data.extend_test_completion_time;
default:
return 0;
}
}
int isSmartErrorLogCapable ( struct ata_smart_values data)
{
int isSmartErrorLogCapable ( struct ata_smart_values data){
return data.errorlog_capability & 0x01;
}
int isSupportExecuteOfflineImmediate ( struct ata_smart_values data)
{
int isSupportExecuteOfflineImmediate ( struct ata_smart_values data){
return data.offline_data_collection_capability & 0x01;
}
int isSupportAutomaticTimer ( struct ata_smart_values data)
{
int isSupportAutomaticTimer ( struct ata_smart_values data){
return data.offline_data_collection_capability & 0x02;
}
int isSupportOfflineAbort ( struct ata_smart_values data)
{
int isSupportOfflineAbort ( struct ata_smart_values data){
return data.offline_data_collection_capability & 0x04;
}
int isSupportOfflineSurfaceScan ( struct ata_smart_values data)
{
int isSupportOfflineSurfaceScan ( struct ata_smart_values data){
return data.offline_data_collection_capability & 0x08;
}
int isSupportSelfTest (struct ata_smart_values data)
{
int isSupportSelfTest (struct ata_smart_values data){
return data.offline_data_collection_capability & 0x10;
}
......
// $Id: atacmds.cpp,v 1.8 2002/10/15 14:24:26 ballen4705 Exp $
// $Id: atacmds.cpp,v 1.9 2002/10/20 19:22:02 ballen4705 Exp $
/*
* atacmds.c
*
......@@ -27,11 +27,15 @@
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include "atacmds.h"
// These Drive Identity tables are taken from hdparm 5.2. That's the
// "Gold Standard"
// These Drive Identity tables are taken from hdparm 5.2, and are also
// given in the ATA/ATAPI specs for the IDENTIFY DEVICE command. Note
// that SMART 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.
#define NOVAL_0 0x0000
#define NOVAL_1 0xffff
/* word 81: minor version number */
......@@ -45,10 +49,10 @@ const char *minor_str[] = { /* word 81 value: */
"ATA-2 X3T10 948D prior to revision 2k", /* 0x0005 */
"ATA-3 X3T10 2008D revision 1", /* 0x0006 */
"ATA-2 X3T10 948D revision 2k", /* 0x0007 */
"ATA-3 X3T10 2008D revision 0", /* 0x0008 */
"ATA-3 X3T10 2008D revision 0", /* 0x0008 */ /* SMART NOT INCLUDED */
"ATA-2 X3T10 948D revision 3", /* 0x0009 */
"ATA-3 published, ANSI X3.298-199x", /* 0x000a */
"ATA-3 X3T10 2008D revision 6", /* 0x000b */
"ATA-3 X3T10 2008D revision 6", /* 0x000b */ /* 1st VERSION WITH SMART */
"ATA-3 X3T13 2008D revision 7 and 7a", /* 0x000c */
"ATA/ATAPI-4 X3T13 1153D revision 6", /* 0x000d */
"ATA/ATAPI-4 T13 1153D revision 13", /* 0x000e */
......@@ -71,7 +75,7 @@ const char *minor_str[] = { /* word 81 value: */
"reserved" /* 0x001f-0xfffe*/
};
const char actual_ver[] = {
const int actual_ver[] = {
/* word 81 value: */
0, /* 0x0000 WARNING: */
1, /* 0x0001 WARNING: */
......@@ -81,7 +85,7 @@ const char actual_ver[] = {
2, /* 0x0005 WARNING: corresponds */
3, /* 0x0006 WARNING: *exactly* */
2, /* 0x0007 WARNING: to the ATA/ */
3, /* 0x0008 WARNING: ATAPI version */
-3, /*<== */ /* 0x0008 WARNING: ATAPI version */
2, /* 0x0009 WARNING: listed in */
3, /* 0x000a WARNING: the */
3, /* 0x000b WARNING: minor_str */
......@@ -106,19 +110,72 @@ const char actual_ver[] = {
};
// Used to warn users about invalid checksums. However we will not
// abort on invalid checksums.
void checksumwarning(const char *string){
printf("Warning! %s error: invalid checksum.\n",string);
fprintf(stderr,"Warning! %s error: invalid checksum.\n",string);
syslog(LOG_INFO,"Warning! %s error: invalid checksum.\n",string);
return;
}
int ataReadHDIdentity ( int device, struct hd_driveid *buf)
{
if (ioctl ( device , HDIO_GET_IDENTITY, buf ) != 0)
{
// We no longer use this function, because the IOCTL appears to return
// only the drive identity at the time that the system was booted
// (perhaps from the BIOS. It doesn't correctly reflect the current
// state information, and for example the checksum is usually
// wrong. The replacement function follows afterwards
#if (0)
int ataReadHDIdentity ( int device, struct hd_driveid *buf){
if (ioctl(device, HDIO_GET_IDENTITY, buf )){
perror ("ATA GET HD Failed");
return -1;
}
return 0;
}
#endif
// Reads current Device Identity info (512 bytes) into buf
int ataReadHDIdentity (int device, struct hd_driveid *buf){
unsigned char parms[HDIO_DRIVE_CMD_HDR_SIZE+sizeof(*buf)]=
{WIN_IDENTIFY, 0, 0, 1,};
if (ioctl(device ,HDIO_DRIVE_CMD,parms)){
perror ("ATA GET HD Identity Failed");
return -1;
}
// copy data into driveid structure
memcpy(buf,parms+HDIO_DRIVE_CMD_HDR_SIZE,sizeof(*buf));
// If driveid structure contains a checksum, then compute it, and
// issue a warning message if something is wrong. I prefer this
// rather than simply exiting at this point, though that is another
// option.
// Note -- the declaration that appears in
// /usr/include/linux/hdregs.h: short words160_255[95], is WRONG.
// It should say: short words160_255[96]. I have written to Andre
// Hedrick about this on Oct 17 2002. Please remove this comment
// once the fix has made it into the stock kernel tree.
if ((buf->words160_255[95] & 0x00ff) == 0x00a5){
unsigned char cksum=0;
int i;
for (i=0;i<sizeof(*buf);i++)
cksum+=parms[i+HDIO_DRIVE_CMD_HDR_SIZE];
if (cksum)
checksumwarning("Drive Identity Structure");
}
return 0;
}
// Returns ATA version as an integer, and a pointer to a string
// describing which revision. Note that Revision 0 of ATA-3 does NOT
// support SMART. For this one case we return -3 rather than +3 as
// the version number. See notes above.
int ataVersionInfo (const char** description, struct hd_driveid drive){
unsigned short major,minor;
int i,atavalue=0;
......@@ -157,17 +214,47 @@ int ataVersionInfo (const char** description, struct hd_driveid drive){
return atavalue;
}
// returns 1 if SMART supported, 0 if not supported or can't tell
int ataSmartSupport(struct hd_driveid drive){
unsigned short word82,word83;
// get correct bits of IDENTIFY DEVICE structure
#ifdef __NEW_HD_DRIVE_ID
if (drive.command_set_1 & 0x0001)
word82=drive.command_set_1;
word83=drive.command_set_2;
#else
if (drive.command_sets & 0x0001)
word82=drive.command_sets;
word83=drive.word83;
#endif
return 1; /* drive supports S.M.A.R.T. and is disabled */
return 0;
// Note this does not work for ATA3 < Revision 6, when word82 and word83 were added
// we should check for ATA3 Rev 0 in minor identity code...
return (word83 & 0x0001<<14) && !(word83 & 0x0001<<15) && (word82 & 0x0001);
}
// returns 1 if SMART enabled, 0 if SMART disabled, -1 if can't tell
int ataIsSmartEnabled(struct hd_driveid drive){
unsigned short word85,word87;
// Get correct bits of IDENTIFY DRIVE structure
#ifdef __NEW_HD_DRIVE_ID
word85=drive.cfs_enable_1;
word87=drive.csf_default;
#else
word85=drive.word85;
word87=drive.word87;
#endif
if ((word87 & 0x0001<<14) && !(word87 & 0x0001<<15))
// word85 contains valid information, so
return word85 & 0x0001;
// Since we can't rely word85, we don't know if SMART is enabled.
return -1;
}
// Reads SMART attributes into *data
int ataReadSmartValues(int device, struct ata_smart_values *data){
int i;
unsigned char chksum=0;
......@@ -175,7 +262,7 @@ int ataReadSmartValues (int device, struct ata_smart_values *data){
{WIN_SMART, 0, SMART_READ_VALUES, 1};
if (ioctl(device,HDIO_DRIVE_CMD,buf)){
perror ("Smart Values Read failed");
perror ("SMART Values Read failed");
return -1;
}
......@@ -184,10 +271,8 @@ int ataReadSmartValues (int device, struct ata_smart_values *data){
chksum+=buf[i+HDIO_DRIVE_CMD_HDR_SIZE];
// verify that checksum vanishes
if (chksum){
perror ("Smart Read Failed, Checksum error!");
return -1;
}
if (chksum)
checksumwarning("SMART Data Structure");
// copy data and return
memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE,ATA_SMART_SEC_SIZE);
......@@ -195,91 +280,95 @@ int ataReadSmartValues (int device, struct ata_smart_values *data){
}
int ataReadSelfTestLog (int device, struct ata_smart_selftestlog *data)
{
// Reads the Self Test Log (log #6)
int ataReadSelfTestLog (int device, struct ata_smart_selftestlog *data){
int i;
unsigned char chksum=0;
unsigned char buf[ HDIO_DRIVE_CMD_HDR_SIZE +
ATA_SMART_SEC_SIZE] =
{ WIN_SMART, 0x06, SMART_READ_LOG_SECTOR, 1};
unsigned char buf[HDIO_DRIVE_CMD_HDR_SIZE+ATA_SMART_SEC_SIZE] =
{WIN_SMART, 0x06, SMART_READ_LOG_SECTOR, 1,};
if (ioctl ( device , HDIO_DRIVE_CMD, (unsigned char *) &buf ) != 0)
{
perror ("Smart Error Log Read failed");
// get data from device
if (ioctl(device, HDIO_DRIVE_CMD, buf)){
perror ("SMART Error Log Read failed");
return -1;
}
// compute checksum
// compute its checksum, and issue a warning if needed
for (i=0;i<ATA_SMART_SEC_SIZE;i++)
chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
if (chksum)
checksumwarning("SMART Self-Test Log");
if (chksum){
fprintf(stderr,"Smart Self Test Log Checksum Incorrect!\n");
return -1;
}
memcpy( data, &buf[HDIO_DRIVE_CMD_HDR_SIZE] , ATA_SMART_SEC_SIZE);
// copy data back to the user and return
memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE);
return 0;
}
int ataReadErrorLog (int device, struct ata_smart_errorlog *data)
{
// Reads the Error Log (log #1)
int ataReadErrorLog (int device, struct ata_smart_errorlog *data){
int i;
unsigned char chksum=0;
unsigned char buf[ HDIO_DRIVE_CMD_HDR_SIZE +
ATA_SMART_SEC_SIZE] =
{ WIN_SMART, 0x01, SMART_READ_LOG_SECTOR, 1};
unsigned char buf[HDIO_DRIVE_CMD_HDR_SIZE+ATA_SMART_SEC_SIZE] =
{WIN_SMART, 0x01, SMART_READ_LOG_SECTOR, 1,};
if (ioctl ( device , HDIO_DRIVE_CMD, (unsigned char *) &buf ) != 0)
{
perror ("Smart Error Log Read failed");
// get data from device
if (ioctl(device,HDIO_DRIVE_CMD,&buf)) {
perror ("SMART Error Log Read failed");
return -1;
}
// compute checksum
// compute checksum and issue warning if needed
for (i=0;i<ATA_SMART_SEC_SIZE;i++)
chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
if (chksum)
checksumwarning("SMART Error Log");
if (chksum){
fprintf(stderr,"Smart Error Log Checksum Incorrect!\n");
return -1;
}
memcpy( data, &buf[HDIO_DRIVE_CMD_HDR_SIZE] , ATA_SMART_SEC_SIZE);
//copy data back to user and return
memcpy(data, buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE);
return 0;
}
int ataReadSmartThresholds ( int device, struct ata_smart_thresholds *data)
{
unsigned char buf[ HDIO_DRIVE_CMD_HDR_SIZE +
ATA_SMART_SEC_SIZE] =
{ WIN_SMART, 1, SMART_READ_THRESHOLDS, 1};
// This routine is marked as "Obsolete" in the ATA-5 spec, but it's
// very important for us. Together with the SMART READ DATA command
// above, it's the only way for us to find out if the SMART status is
// good or not. Hopefully this will get fixed -- I will find a way to
// get SMART Status directly.
int ataReadSmartThresholds ( int device, struct ata_smart_thresholds *data){
int i;
unsigned char chksum=0;
unsigned char buf[HDIO_DRIVE_CMD_HDR_SIZE+ATA_SMART_SEC_SIZE] =
{WIN_SMART, 1, SMART_READ_THRESHOLDS, 1,};
if (ioctl ( device , HDIO_DRIVE_CMD, (unsigned char *) &buf ) != 0)
{
perror ("Smart Thresholds Read failed");
// get data from device
if (ioctl(device ,HDIO_DRIVE_CMD, buf)){
perror ("SMART Thresholds Read failed");
return -1;
}
memcpy( data, &buf[HDIO_DRIVE_CMD_HDR_SIZE] , ATA_SMART_SEC_SIZE);
// compute checksum and issue warning if needed
for (i=0;i<ATA_SMART_SEC_SIZE;i++)
chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
if (chksum)
checksumwarning("SMART Attribute Thresholds");
// copy data back to user and return
memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE);
return 0;
}
int ataSetSmartThresholds ( int device, struct ata_smart_thresholds *data)
{
unsigned char buf[ HDIO_DRIVE_CMD_HDR_SIZE +
ATA_SMART_SEC_SIZE] =
{ WIN_SMART, 1, 0xD7, 1};
memcpy( &buf[HDIO_DRIVE_CMD_HDR_SIZE], data , ATA_SMART_SEC_SIZE);
// This routine is not currently in use, and it's been marked as
// "Obsolete" in the ANSI ATA-5 spec. So it should probably be left
// alone and unused.
int ataSetSmartThresholds ( int device, struct ata_smart_thresholds *data){
unsigned char buf[HDIO_DRIVE_CMD_HDR_SIZE+ATA_SMART_SEC_SIZE] =
{WIN_SMART, 1, 0xD7, 1,};
if (ioctl ( device , HDIO_DRIVE_CMD, (unsigned char *) &buf ) != 0)
{
perror ("Smart Thresholds Read failed");
memcpy(buf+HDIO_DRIVE_CMD_HDR_SIZE, data, ATA_SMART_SEC_SIZE);
if (ioctl(device, HDIO_DRIVE_CMD, buf)){
perror ("SMART Thresholds Read failed");
return -1;
}
......@@ -287,14 +376,11 @@ int ataSetSmartThresholds ( int device, struct ata_smart_thresholds *data)
}
int ataEnableSmart (int device )
{
int ataEnableSmart (int device ){
unsigned char parms[4] = {WIN_SMART, 1, SMART_ENABLE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Enable failed");
if (ioctl ( device , HDIO_DRIVE_CMD, &parms )){
perror ("SMART Enable failed");
return -1;
}
......@@ -302,14 +388,11 @@ int ataEnableSmart (int device )
}
int ataDisableSmart (int device )
{
int ataDisableSmart (int device ){
unsigned char parms[4] = {WIN_SMART, 1, SMART_DISABLE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Disable failed");
if (ioctl(device , HDIO_DRIVE_CMD, parms )){
perror ("SMART Disable failed");
return -1;
}
......@@ -319,50 +402,45 @@ int ataDisableSmart (int device )
int ataEnableAutoSave(int device){
unsigned char parms[4] = {WIN_SMART, 241, SMART_AUTOSAVE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Enable Auto-save failed");
if (ioctl(device , HDIO_DRIVE_CMD, parms )){
perror ("SMART Enable Auto-save failed");
return -1;
}
return 0;
};
}
int ataDisableAutoSave(int device){
unsigned char parms[4] = {WIN_SMART, 0, SMART_AUTOSAVE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Disable Auto-save failed");
if (ioctl(device, HDIO_DRIVE_CMD, parms)){
perror ("SMART Disable Auto-save failed");
return -1;
}
return 0;
};
}
int ataEnableAutoOffline (int device )
{
// Note that in the ATA-5 standard this command is marked "OBSOLETE"
int ataEnableAutoOffline (int device ){
/* timer hard coded to 4 hours */
unsigned char parms[4] = {WIN_SMART, 248, SMART_AUTO_OFFLINE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Enable Automatic Offline failed");
if (ioctl(device , HDIO_DRIVE_CMD, parms)){
perror ("SMART Enable Automatic Offline failed");
return -1;
}
return 0;
}
int ataDisableAutoOffline (int device )
{
// Another Obsolete Command!
int ataDisableAutoOffline (int device ){
unsigned char parms[4] = {WIN_SMART, 0, SMART_AUTO_OFFLINE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms ) != 0)
{
perror ("Smart Disable Automatic Offline failed");
if (ioctl(device , HDIO_DRIVE_CMD, parms)){
perror ("SMART Disable Automatic Offline failed");
return -1;
}
......@@ -371,117 +449,152 @@ int ataDisableAutoOffline (int device )
// Not being used correctly. Must examine the CL and CH registers to
// see what the smart status was. How to fix this? I don't know...
// see what the smart status was. Look at ataSmartStatus2()
int ataSmartStatus (int device ){
unsigned char parms[4] = {WIN_SMART, 0, SMART_STATUS, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms))
if (ioctl(device, HDIO_DRIVE_CMD, parms)){
perror("Return SMART Status failed");
return -1;
}
return 0;
}
// If SMART is enabled, supported, and working, then this call is
// guaranteed to return 1, else zero. Silent inverse of
// ataSmartStatus()
int ataDoesSmartWork(int device){
unsigned char parms[4] = {WIN_SMART, 0, SMART_STATUS, 0};
return !ioctl(device, HDIO_DRIVE_CMD, parms);
}
// This function needs to be properly tested and debugged. I am not
// yet sure if this is right; have asked Andre for help. May need to
// use IDE_DRIVE_TASK. Does CONFIG_IDE_TASKFILE_IO need to be
// configured into the kernel?
int ataSmartStatus2(int device){
unsigned char normal_cyl_lo=0x4f, normal_cyl_hi=0xc2;
unsigned char failed_cyl_lo=0xf4, failed_cyl_hi=0x2c;
unsigned char parms[HDIO_DRIVE_TASK_HDR_SIZE]=
{WIN_SMART, // CMD
SMART_STATUS, // FR
0, // NS
0, // SC
0, // CL
0, // CH
0 // SEL -- Andre, is this right?? Or should it be 1?
};
// load CL and CH values
parms[4]=normal_cyl_lo;
parms[5]=normal_cyl_hi;
int ataSmartTest (int device, int testtype)
{
unsigned char parms[4] = { WIN_SMART, testtype,
SMART_IMMEDIATE_OFFLINE, 0};
if (ioctl ( device , HDIO_DRIVE_CMD, &parms) != 0)
{
perror ("Smart Offline failed");
if (ioctl(device,HDIO_DRIVE_TASK,&parms)){
perror ("SMART Status command failed.");
return -1;
}
printf("Completed Off-line command\n");
// Cyl low and Cyl high unchanged means "Good SMART status"
if (parms[4]==normal_cyl_lo && parms[5]==normal_cyl_hi)
return 0;
}
// These values mean "Bad SMART status"
if (parms[4]==failed_cyl_lo && parms[5]==failed_cyl_hi)
return 1;
int ataSmartOfflineTest (int device)
{
return ataSmartTest( device, OFFLINE_FULL_SCAN );
}
int ataSmartShortSelfTest (int device)
{
return ataSmartTest( device, SHORT_SELF_TEST );
}
// We haven't gotten output that makes sense; print out some debugging info
perror("SMART Status returned register values that don't make sense:\n");
printf("CMD=0x%02x\n",parms[0]);
printf("FR =0x%02x\n",parms[1]);
printf("NS =0x%02x\n",parms[2]);
printf("SC =0x%02x\n",parms[3]);
printf("CL =0x%02x\n",parms[4]);
printf("CH =0x%02x\n",parms[5]);
printf("SEL=0x%02x\n",parms[6]);
int ataSmartExtendSelfTest (int device)
{
return ataSmartTest( device, EXTEND_SELF_TEST );
return -1;
}
int ataSmartShortCapSelfTest (int device)
{
return ataSmartTest( device, SHORT_CAPTIVE_SELF_TEST );
// This is the way to execute ALL tests: offline, short self-test,
// extended self test, with and without captive mode, etc.
int ataSmartTest(int device, int testtype){
unsigned char parms[4] = {WIN_SMART, 0, SMART_IMMEDIATE_OFFLINE};
char cmdmsg[128],*type,*captive;
parms[1]=testtype;
// Set up strings that describe the type of test
if (testtype==SHORT_CAPTIVE_SELF_TEST || testtype==EXTEND_CAPTIVE_SELF_TEST)
captive="captive";
else
captive="off-line";
if (testtype==OFFLINE_FULL_SCAN)
type="off-line";
else if (testtype==SHORT_SELF_TEST || testtype==SHORT_CAPTIVE_SELF_TEST)
type="Short self-test";
else
type="Extended self-test";
// Print ouf message that we are sending the command to test
if (testtype==ABORT_SELF_TEST)
sprintf(cmdmsg,"Abort SMART off-line mode self-test routine");
else
sprintf(cmdmsg,"Execute SMART %s routine immediately in %s mode",type,captive);
printf("Sending command: \"%s\".\n",cmdmsg);
// Now send the command to test
if (ioctl(device , HDIO_DRIVE_CMD, parms)){
char errormsg[128];
sprintf(errormsg,"Command \"%s\" failed.\n\n",cmdmsg);
perror (errormsg);
return -1;
}
int ataSmartExtendCapSelfTest (int device)
{
return ataSmartTest( device, EXTEND_CAPTIVE_SELF_TEST );
// Since the command succeeded, tell user
if (testtype==ABORT_SELF_TEST)
printf("Self-testing aborted!\n");
else
printf("Drive command \"%s\" successful.\nTesting has begun.\n",cmdmsg);
return 0;
}
int ataSmartSelfTestAbort (int device)
{
return ataSmartTest( device, 127 );
}
/* Test Time Functions */
int isOfflineTestTime ( struct ata_smart_values data)
{
int TestTime(struct ata_smart_values data,int testtype){
switch (testtype){
case OFFLINE_FULL_SCAN:
return (int) data.total_time_to_complete_off_line;
}
int isShortSelfTestTime ( struct ata_smart_values data)
{
case SHORT_SELF_TEST:
case SHORT_CAPTIVE_SELF_TEST:
return (int) data.short_test_completion_time;
}
int isExtendedSelfTestTime ( struct ata_smart_values data)
{
case EXTEND_SELF_TEST:
case EXTEND_CAPTIVE_SELF_TEST:
return (int) data.extend_test_completion_time;
default:
return 0;
}
}
int isSmartErrorLogCapable ( struct ata_smart_values data)
{
int isSmartErrorLogCapable ( struct ata_smart_values data){
return data.errorlog_capability & 0x01;
}
int isSupportExecuteOfflineImmediate ( struct ata_smart_values data)
{
int isSupportExecuteOfflineImmediate ( struct ata_smart_values data){
return data.offline_data_collection_capability & 0x01;
}
int isSupportAutomaticTimer ( struct ata_smart_values data)
{
int isSupportAutomaticTimer ( struct ata_smart_values data){
return data.offline_data_collection_capability & 0x02;
}
int isSupportOfflineAbort ( struct ata_smart_values data)
{
int isSupportOfflineAbort ( struct ata_smart_values data){
return data.offline_data_collection_capability & 0x04;
}
int isSupportOfflineSurfaceScan ( struct ata_smart_values data)
{
int isSupportOfflineSurfaceScan ( struct ata_smart_values data){
return data.offline_data_collection_capability & 0x08;
}
int isSupportSelfTest (struct ata_smart_values data)
{
int isSupportSelfTest (struct ata_smart_values data){
return data.offline_data_collection_capability & 0x10;
}
......
// $Id: atacmds.h,v 1.12 2002/10/15 14:24:26 ballen4705 Exp $
// $Id: atacmds.h,v 1.13 2002/10/20 19:22:02 ballen4705 Exp $
/*
* atacmds.h
*
......@@ -72,6 +72,12 @@
#define SMART_WRITE_LOG_SECTOR 0xd6
#endif
// The following is obsolete -- don't use it!
#ifndef SMART_WRITE_THRESHOLDS
#define SMART_WRITE_THRESHOLDS 0xd7
#endif
#ifndef SMART_ENABLE
#define SMART_ENABLE 0xd8
#endif
......@@ -84,6 +90,7 @@
#define SMART_STATUS 0xda
#endif
// The following is also marked obsolete in ATA-5
#ifndef SMART_AUTO_OFFLINE
#define SMART_AUTO_OFFLINE 0xdb
#endif
......@@ -91,6 +98,7 @@
#define OFFLINE_FULL_SCAN 0
#define SHORT_SELF_TEST 1
#define EXTEND_SELF_TEST 2
#define ABORT_SELF_TEST 127
#define SHORT_CAPTIVE_SELF_TEST 129
#define EXTEND_CAPTIVE_SELF_TEST 130
......@@ -306,22 +314,19 @@ int ataSmartSelfTestAbort (int device);
int ataVersionInfo (const char **description, struct hd_driveid drive);
/* int ataSmartSupport ( int device, struct hd_driveid drive)
* Check if S.M.A.R.T. is supported and enabled in drive
* returns -1:if S.M.A.R.T. capability can not be checked
* returns 0: if drive does not support S.M.A.R.T.
* 1: if drive supports S.M.A.R.T. but not enabled
* 2: if drive supports S.M.A.R.T. and enabled
* 255: if drive supports S.M.A.R.T. but does not
* support ATA-4.
* ATA 3 and lower do not support S.M.A.R.T. enabled bit
* Attempt a Read S.M.A.R.T. attributes to check if enabled
*/
// If SMART supported, this is guaranteed to return 1 if SMART is enabled, else 0.
int ataDoesSmartWork(int device);
// returns 1 if SMART supported, 0 if not supported or can't tell
int ataSmartSupport ( struct hd_driveid drive);
/* Check SMART for Threshold failure */
// Return values:
// 1: SMART enabled
// 0: SMART disabled
// -1: can't tell if SMART is enabled -- try issuing ataDoesSmartWork command to see
int ataIsSmartEnabled(struct hd_driveid drive);
/* Check SMART for Threshold failure */
int ataCheckSmart ( struct ata_smart_values data, struct ata_smart_thresholds thresholds);
/* int isOfflineTestTime ( struct ata_smart_values data)
......@@ -355,6 +360,8 @@ int isSupportOfflineSurfaceScan ( struct ata_smart_values data);
int isSupportSelfTest (struct ata_smart_values data);
int ataSmartTest(int device, int testtype);
int TestTime(struct ata_smart_values data,int testtype);
#endif /* _ATACMDS_H_ */
// $Id: ataprint.c,v 1.12 2002/10/17 04:03:33 ballen4705 Exp $
// $Id: ataprint.c,v 1.13 2002/10/20 19:22:02 ballen4705 Exp $
/*
* ataprint.c
*
......@@ -23,15 +23,56 @@
*
*/
#include <ctype.h>
#include <stdio.h>
#include "ataprint.h"
#include "smartctl.h"
#include "extern.h"
// 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)
printf("%.*s\n",n-i,out+i);
else
printf("[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)
printf("Device Model: ");
printswap(drive.model,40);
printf("Serial Number: ");
printswap(drive.serial_no,20);
printf("Firmware Version: ");
printswap(drive.fw_rev,8);
// now get ATA version info
version=ataVersionInfo(&description,drive);
// unrecognized minor revision code
......@@ -40,17 +81,20 @@ void ataPrintDriveInfo (struct hd_driveid drive){
description=unknown;
}
// print out information for user
printf("Device Model: %.40s\n",drive.model);
printf("Serial Number: %.20s\n",drive.serial_no);
printf("Firmware Version: %.8s\n",drive.fw_rev);
printf("ATA Version is: %i\n",version);
// 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.
printf("ATA Version is: %i\n",version>0?version:-1*version);
printf("ATA Standard is: %s\n",description);
if (version>=3)
return;
printf("SMART is only supported in ATA version 3 or greater\n");
printf("SMART is only available in ATA Version 3 Revision 3 or greater.\n\n");
exit (0);
}
......@@ -62,37 +106,43 @@ void PrintSmartOfflineStatus ( struct ata_smart_values data)
{
printf ("Off-line data collection status: ");
switch (data.offline_data_collection_status)
{
case 0x0: case 0x80:
switch (data.offline_data_collection_status){
case 0x00:
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:
case 0x01:
case 0x81:
printf ("(0x%02x)\tReserved.\n",
data.offline_data_collection_status);
break;
case 0x02: case 0x82:
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:
case 0x03:
case 0x83:
printf ("(0x%02x)\tReserved.\n",
data.offline_data_collection_status);
break;
case 0x04: case 0x84:
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");
printf ("suspended by an interrupting command from host.\n");
break;
case 0x05: case 0x85:
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");
printf ("aborted by an interrupting command from host.\n");
break;
case 0x06: case 0x86:
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 a fatal error.\n");
......@@ -236,8 +286,7 @@ void PrintSmartCapability ( struct ata_smart_values data)
if (data.smart_capability == 0x00)
{
printf ("automatic saving of SMART data");
printf ("\t\t\t\t\tis not implemented.\n");
printf ("Automatic saving of SMART data\t\t\t\t\tis not implemented.\n");
}
else
{
......@@ -451,9 +500,9 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data)
// starting printing error log info
if (data.ata_error_count<=5)
printf ( "ATA Error Count: %u\n\n", data.ata_error_count);
printf ( "ATA Error Count: %u\n", data.ata_error_count);
else
printf ( "ATA Error Count: %u (only the most recent five errors are shown below)\n\n",
printf ( "ATA Error Count: %u (only the most recent five errors are shown below)\n",
data.ata_error_count);
printf( "Acronyms used below:\n");
......@@ -530,7 +579,7 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data)
void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data){
int i,j;
printf("\nSMART Self-test log, version number %u\n",data.revnumber);
printf("SMART Self-test log, version number %u\n",data.revnumber);
if (data.revnumber!=0x01)
printf("Warning - structure revision number does not match spec!\n");
......@@ -540,7 +589,7 @@ void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data){
}
// print log
printf("\nNum Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n");
printf("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n");
for (i=20;i>=0;i--){
struct ata_smart_selftestlog_struct *log;
......@@ -595,7 +644,7 @@ void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data){
return;
}
void ataPsuedoCheckSmart ( struct ata_smart_values data,
void ataPseudoCheckSmart ( struct ata_smart_values data,
struct ata_smart_thresholds thresholds) {
int i;
int failed = 0;
......@@ -605,15 +654,14 @@ void ataPsuedoCheckSmart ( struct ata_smart_values data,
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);
printf("Attribute ID %i Failed\n",data.vendor_attributes[i].id);
failed = 1;
}
}
printf("%s\n", ( failed )?
"SMART overall-health self-assessment test result: FAILED!\n"
"Drive failure expected in less than 24 hours. SAVE ALL DATA\n":
"SMART overall-health self-assessment test result: PASSED\n");
"Drive failure expected in less than 24 hours. SAVE ALL DATA":
"SMART overall-health self-assessment test result: PASSED");
}
void ataPrintSmartAttribName ( unsigned char id ){
......@@ -722,322 +770,195 @@ void ataPrintSmartAttribName ( unsigned char id ){
Called by smartctl to access ataprint
**/
void ataPrintMain ( int fd )
{
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;
int timewait;
if ( driveinfo )
{
if ( ataReadHDIdentity ( fd, &drive) != 0 )
{
printf("Smartctl: Hard Drive Identity Failed\n");
exit(0);
// Start by getting Drive ID information. We need this, to know if SMART is supported.
if (ataReadHDIdentity(fd,&drive)){
printf("Smartctl: Hard Drive Read Identity Failed\n\n");
exit(-1);
}
// Print most drive identity information if requested
if (driveinfo){
printf("\n=== START OF INFORMATION SECTION ===\n");
ataPrintDriveInfo(drive);
if (ataSmartSupport(drive))
{
printf ("SMART support is: ");
if ( ataSmartStatus(fd) != 0)
{
printf( "Disabled\n");
printf( "Use option -%c to enable\n\n", SMARTENABLE );
exit(0);
}
else {
printf( "Enabled\n\n");
}
}
else {
printf("SMART support is: Unavailable. Device lacks SMART capability.\n\n");
// now check if drive supports SMART; otherwise time to exit
if (!ataSmartSupport(drive)){
printf("SMART support is: Unavailable - device lacks SMART capability.\n");
exit (0);
}
// Now print remaining drive info: is SMART enabled?
if (driveinfo){
printf("SMART support is: Available - device has SMART capability.\n");
if (ataDoesSmartWork(fd))
printf("SMART support is: Enabled\n");
else
printf("SMART support is: Disabled\n");
}
if ( smartdisable )
{
// START OF THE ENABLE/DISABLE SECTION OF THE CODE
if (smartenable || smartdisable ||
smartautosaveenable || smartautosavedisable ||
smartautoofflineenable || smartautoofflinedisable)
printf("\n=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
if ( ataDisableSmart(fd) != 0)
{
printf( "Smartctl: SMART Enable Failed\n");
// Enable/Disable SMART commands
if (smartenable){
if (ataEnableSmart(fd)) {
printf("Smartctl: SMART Enable Failed.\n\n");
exit(-1);
}
else
printf("SMART Enabled.\n");
}
printf("SMART Disabled\n");
// From here on, every command requires that SMART be enabled...
if (!ataDoesSmartWork(fd)) {
printf("SMART Disabled. Use option -%c to enable it.\n", SMARTENABLE );
exit(0);
}
if ( smartenable )
{
if ( ataEnableSmart(fd) != 0)
{
printf( "Smartctl: SMART Enable Failed\n");
// Turn off SMART on device
if (smartdisable){
if (ataDisableSmart(fd)) {
printf( "Smartctl: SMART Disable Failed.\n\n");
exit(-1);
}
if (ataSmartStatus(fd)==0)
printf("SMART Enabled\n");
else
printf( "Smartctl: SMART Enable Failed for unknown reasons\n");
printf("SMART Disabled. Use option -%c to enable it.\n",SMARTENABLE);
exit (0);
}
// Enable/Disable Auto-save attributes
if (smartautosaveenable){
if (ataEnableAutoSave(fd)){
printf( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n");
exit(-1);
}
printf("SMART Attribute Autosave Enabled\n");
}
if (smartautosavedisable){
if (ataDisableAutoSave(fd) != 0)
{
printf( "Smartctl: SMART Disable Attribute Autosave Failed\n");
if (ataDisableAutoSave(fd)){
printf( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n");
exit(-1);
}
printf("SMART Attribute Autosave Disabled\n");
}
if ( smartautosaveenable ){
if (ataEnableAutoSave(fd) != 0)
{
printf( "Smartctl: SMART Enable Attribute Autosave Failed\n");
// for everything else read values and thresholds are needed
if (ataReadSmartValues(fd, &smartval)){
printf("Smartctl: SMART Values Read Failed.\n\n");
exit (-1);
}
printf("SMART Attribute Autosave Enabled\n");
if (ataReadSmartThresholds(fd, &smartthres)){
printf("Smartctl: SMART Thresholds Read Failed.\n\n");
exit (-1);
}
/* for everything else read values and thresholds
are needed */
if ( ataReadSmartValues ( fd, &smartval) != 0 )
{
printf("Smartctl: SMART Values Read Failed\n");
// Enable/Disable Off-line testing
if (smartautoofflineenable){
if (!isSupportAutomaticTimer (smartval)){
printf("Device does not support SMART Automatic Timers.\n\n");
exit(-1);
}
if ( ataReadSmartThresholds ( fd, &smartthres) != 0 )
{
printf("Smartctl: SMART Thresholds Read Failed\n");
if (ataEnableAutoOffline (fd)){
printf( "Smartctl: SMART Enable Automatic Offline Failed.\n\n");
exit(-1);
}
printf ("SMART Automatic Offline Testing Enabled every four hours.\n");
}
if (smartautoofflinedisable){
if (!isSupportAutomaticTimer (smartval)){
printf("Device does not support SMART Automatic Timers.\n\n");
exit(-1);
}
if ( ataDisableAutoOffline (fd)){
printf( "Smartctl: SMART Disable Automatic Offline Failed.\n\n");
exit(-1);
}
printf ("SMART Automatic Offline Testing Disabled.\n");
}
if ( checksmart )
{
/* pseudo is used because linux does not support access to
Task File registers */
// I am very confused by this comment. Does anyone get it? Bruce
ataPsuedoCheckSmart ( smartval , smartthres);
// START OF READ-ONLY OPTIONS APART FROM -p and -i
if (checksmart || generalsmartvalues || smartvendorattrib || smarterrorlog || smartselftestlog)
printf("\n=== START OF READ SMART DATA SECTION ===\n");
}
// Check SMART status
if (checksmart)
// Eventually when working use the ataSmartStatus2 function here.
// This will then not require read values & thresholds above, and
// shouldl be moved in the code to just before the read values &
// thresholds statements.
ataPseudoCheckSmart(smartval, smartthres);
// Print general SMART values
if (generalsmartvalues)
{
ataPrintGeneralSmartValues(smartval);
}
// Print vendor-specific attributes
if (smartvendorattrib)
{
PrintSmartAttribWithThres(smartval, smartthres);
}
if ( smarterrorlog )
{
if ( isSmartErrorLogCapable(smartval) == 0)
{
// Print SMART error log
if (smarterrorlog){
if (!isSmartErrorLogCapable(smartval))
printf("Device does not support Error Logging\n");
}
else
{
if ( ataReadErrorLog ( fd, &smarterror) != 0 )
{
else {
if (ataReadErrorLog(fd, &smarterror))
printf("Smartctl: SMART Errorlog Read Failed\n");
}
else
{
ataPrintSmartErrorlog(smarterror);
}
}
}
if ( smartselftestlog )
{
if ( isSmartErrorLogCapable(smartval) == 0)
{
// Print SMART self-test log
if (smartselftestlog){
if (!isSmartErrorLogCapable(smartval))
printf("Device does not support Self Test Logging\n");
}
else
{
if ( ataReadSelfTestLog( fd, &smartselftest) != 0 )
{
else {
if(ataReadSelfTestLog(fd, &smartselftest))
printf("Smartctl: SMART Self Test Log Read Failed\n");
}
else
{
ataPrintSmartSelfTestlog(smartselftest);
}
}
}
if ( smartautoofflineenable )
{
if ( !isSupportAutomaticTimer (smartval))
{
printf("Device does not support SMART Automatic Timers\n");
exit(-1);
}
if ( ataEnableAutoOffline (fd) != 0)
{
printf( "Smartctl: SMART Enable Automatic Offline Failed\n");
exit(-1);
}
printf ("SMART Automatic Offline Testing Enabled every four hours\n");
}
if ( smartautoofflinedisable )
{
if ( !isSupportAutomaticTimer (smartval))
{
printf("Device does not support SMART Automatic Timers\n");
exit(-1);
}
if ( ataDisableAutoOffline (fd) != 0)
{
printf( "Smartctl: SMART Disable Automatic Offline Failed\n");
exit(-1);
}
printf ("SMART 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( "SMART Extended Self Test Failed\n");
exit(-1);
}
// START OF THE TESTING SECTION OF THE CODE. IF NO TESTING, RETURN
if (testcase==-1)
return;
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);
printf("\n=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n");
exit (0);
}
if ( smartextendcapselftest )
{
if ( ! isSupportSelfTest(smartval) )
{
printf ("ERROR: device does not support self test function\n");
// if doing a self-test, be sure it's supported by the hardware
if (testcase==OFFLINE_FULL_SCAN && !isSupportExecuteOfflineImmediate(smartval)){
printf("ERROR: device does not support Execute Off-Line Immediate function.\n\n");
exit(-1);
}
if ( ataSmartExtendCapSelfTest (fd) != 0)
{
printf( "SMART Extended Self Test Failed\n");
else if (!isSupportSelfTest(smartval)){
printf ("ERROR: device does not support Self-Test functions.\n\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");
// Now do the test
if (ataSmartTest(fd, testcase))
exit(-1);
}
if ( ataSmartSelfTestAbort (fd) != 0)
{
printf( "SMART Self Test Abort Failed\n");
exit(-1);
}
// Tell user how long test will take to complete
if ((timewait=TestTime(smartval,testcase))){
printf ("Please wait %d %s for test to complete.\n",
timewait, testcase==OFFLINE_FULL_SCAN?"seconds":"minutes");
printf ("Drive Command Successful self test aborted\n");
if (testcase!=SHORT_CAPTIVE_SELF_TEST && testcase!=EXTEND_CAPTIVE_SELF_TEST)
printf ("Use smartctl -%c to abort test.\n", SMARTSELFTESTABORT);
}
return;
}
// $Id: ataprint.cpp,v 1.12 2002/10/17 04:03:33 ballen4705 Exp $
// $Id: ataprint.cpp,v 1.13 2002/10/20 19:22:02 ballen4705 Exp $
/*
* ataprint.c
*
......@@ -23,15 +23,56 @@
*
*/
#include <ctype.h>
#include <stdio.h>
#include "ataprint.h"
#include "smartctl.h"
#include "extern.h"
// 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)
printf("%.*s\n",n-i,out+i);
else
printf("[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)
printf("Device Model: ");
printswap(drive.model,40);
printf("Serial Number: ");
printswap(drive.serial_no,20);
printf("Firmware Version: ");
printswap(drive.fw_rev,8);
// now get ATA version info
version=ataVersionInfo(&description,drive);
// unrecognized minor revision code
......@@ -40,17 +81,20 @@ void ataPrintDriveInfo (struct hd_driveid drive){
description=unknown;
}
// print out information for user
printf("Device Model: %.40s\n",drive.model);
printf("Serial Number: %.20s\n",drive.serial_no);
printf("Firmware Version: %.8s\n",drive.fw_rev);
printf("ATA Version is: %i\n",version);
// 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.
printf("ATA Version is: %i\n",version>0?version:-1*version);
printf("ATA Standard is: %s\n",description);
if (version>=3)
return;
printf("SMART is only supported in ATA version 3 or greater\n");
printf("SMART is only available in ATA Version 3 Revision 3 or greater.\n\n");
exit (0);
}
......@@ -62,37 +106,43 @@ void PrintSmartOfflineStatus ( struct ata_smart_values data)
{
printf ("Off-line data collection status: ");
switch (data.offline_data_collection_status)
{
case 0x0: case 0x80:
switch (data.offline_data_collection_status){
case 0x00:
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:
case 0x01:
case 0x81:
printf ("(0x%02x)\tReserved.\n",
data.offline_data_collection_status);
break;
case 0x02: case 0x82:
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:
case 0x03:
case 0x83:
printf ("(0x%02x)\tReserved.\n",
data.offline_data_collection_status);
break;
case 0x04: case 0x84:
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");
printf ("suspended by an interrupting command from host.\n");
break;
case 0x05: case 0x85:
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");
printf ("aborted by an interrupting command from host.\n");
break;
case 0x06: case 0x86:
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 a fatal error.\n");
......@@ -236,8 +286,7 @@ void PrintSmartCapability ( struct ata_smart_values data)
if (data.smart_capability == 0x00)
{
printf ("automatic saving of SMART data");
printf ("\t\t\t\t\tis not implemented.\n");
printf ("Automatic saving of SMART data\t\t\t\t\tis not implemented.\n");
}
else
{
......@@ -451,9 +500,9 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data)
// starting printing error log info
if (data.ata_error_count<=5)
printf ( "ATA Error Count: %u\n\n", data.ata_error_count);
printf ( "ATA Error Count: %u\n", data.ata_error_count);
else
printf ( "ATA Error Count: %u (only the most recent five errors are shown below)\n\n",
printf ( "ATA Error Count: %u (only the most recent five errors are shown below)\n",
data.ata_error_count);
printf( "Acronyms used below:\n");
......@@ -530,7 +579,7 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data)
void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data){
int i,j;
printf("\nSMART Self-test log, version number %u\n",data.revnumber);
printf("SMART Self-test log, version number %u\n",data.revnumber);
if (data.revnumber!=0x01)
printf("Warning - structure revision number does not match spec!\n");
......@@ -540,7 +589,7 @@ void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data){
}
// print log
printf("\nNum Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n");
printf("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n");
for (i=20;i>=0;i--){
struct ata_smart_selftestlog_struct *log;
......@@ -595,7 +644,7 @@ void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data){
return;
}
void ataPsuedoCheckSmart ( struct ata_smart_values data,
void ataPseudoCheckSmart ( struct ata_smart_values data,
struct ata_smart_thresholds thresholds) {
int i;
int failed = 0;
......@@ -605,15 +654,14 @@ void ataPsuedoCheckSmart ( struct ata_smart_values data,
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);
printf("Attribute ID %i Failed\n",data.vendor_attributes[i].id);
failed = 1;
}
}
printf("%s\n", ( failed )?
"SMART overall-health self-assessment test result: FAILED!\n"
"Drive failure expected in less than 24 hours. SAVE ALL DATA\n":
"SMART overall-health self-assessment test result: PASSED\n");
"Drive failure expected in less than 24 hours. SAVE ALL DATA":
"SMART overall-health self-assessment test result: PASSED");
}
void ataPrintSmartAttribName ( unsigned char id ){
......@@ -722,322 +770,195 @@ void ataPrintSmartAttribName ( unsigned char id ){
Called by smartctl to access ataprint
**/
void ataPrintMain ( int fd )
{
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;
int timewait;
if ( driveinfo )
{
if ( ataReadHDIdentity ( fd, &drive) != 0 )
{
printf("Smartctl: Hard Drive Identity Failed\n");
exit(0);
// Start by getting Drive ID information. We need this, to know if SMART is supported.
if (ataReadHDIdentity(fd,&drive)){
printf("Smartctl: Hard Drive Read Identity Failed\n\n");
exit(-1);
}
// Print most drive identity information if requested
if (driveinfo){
printf("\n=== START OF INFORMATION SECTION ===\n");
ataPrintDriveInfo(drive);
if (ataSmartSupport(drive))
{
printf ("SMART support is: ");
if ( ataSmartStatus(fd) != 0)
{
printf( "Disabled\n");
printf( "Use option -%c to enable\n\n", SMARTENABLE );
exit(0);
}
else {
printf( "Enabled\n\n");
}
}
else {
printf("SMART support is: Unavailable. Device lacks SMART capability.\n\n");
// now check if drive supports SMART; otherwise time to exit
if (!ataSmartSupport(drive)){
printf("SMART support is: Unavailable - device lacks SMART capability.\n");
exit (0);
}
// Now print remaining drive info: is SMART enabled?
if (driveinfo){
printf("SMART support is: Available - device has SMART capability.\n");
if (ataDoesSmartWork(fd))
printf("SMART support is: Enabled\n");
else
printf("SMART support is: Disabled\n");
}
if ( smartdisable )
{
// START OF THE ENABLE/DISABLE SECTION OF THE CODE
if (smartenable || smartdisable ||
smartautosaveenable || smartautosavedisable ||
smartautoofflineenable || smartautoofflinedisable)
printf("\n=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
if ( ataDisableSmart(fd) != 0)
{
printf( "Smartctl: SMART Enable Failed\n");
// Enable/Disable SMART commands
if (smartenable){
if (ataEnableSmart(fd)) {
printf("Smartctl: SMART Enable Failed.\n\n");
exit(-1);
}
else
printf("SMART Enabled.\n");
}
printf("SMART Disabled\n");
// From here on, every command requires that SMART be enabled...
if (!ataDoesSmartWork(fd)) {
printf("SMART Disabled. Use option -%c to enable it.\n", SMARTENABLE );
exit(0);
}
if ( smartenable )
{
if ( ataEnableSmart(fd) != 0)
{
printf( "Smartctl: SMART Enable Failed\n");
// Turn off SMART on device
if (smartdisable){
if (ataDisableSmart(fd)) {
printf( "Smartctl: SMART Disable Failed.\n\n");
exit(-1);
}
if (ataSmartStatus(fd)==0)
printf("SMART Enabled\n");
else
printf( "Smartctl: SMART Enable Failed for unknown reasons\n");
printf("SMART Disabled. Use option -%c to enable it.\n",SMARTENABLE);
exit (0);
}
// Enable/Disable Auto-save attributes
if (smartautosaveenable){
if (ataEnableAutoSave(fd)){
printf( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n");
exit(-1);
}
printf("SMART Attribute Autosave Enabled\n");
}
if (smartautosavedisable){
if (ataDisableAutoSave(fd) != 0)
{
printf( "Smartctl: SMART Disable Attribute Autosave Failed\n");
if (ataDisableAutoSave(fd)){
printf( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n");
exit(-1);
}
printf("SMART Attribute Autosave Disabled\n");
}
if ( smartautosaveenable ){
if (ataEnableAutoSave(fd) != 0)
{
printf( "Smartctl: SMART Enable Attribute Autosave Failed\n");
// for everything else read values and thresholds are needed
if (ataReadSmartValues(fd, &smartval)){
printf("Smartctl: SMART Values Read Failed.\n\n");
exit (-1);
}
printf("SMART Attribute Autosave Enabled\n");
if (ataReadSmartThresholds(fd, &smartthres)){
printf("Smartctl: SMART Thresholds Read Failed.\n\n");
exit (-1);
}
/* for everything else read values and thresholds
are needed */
if ( ataReadSmartValues ( fd, &smartval) != 0 )
{
printf("Smartctl: SMART Values Read Failed\n");
// Enable/Disable Off-line testing
if (smartautoofflineenable){
if (!isSupportAutomaticTimer (smartval)){
printf("Device does not support SMART Automatic Timers.\n\n");
exit(-1);
}
if ( ataReadSmartThresholds ( fd, &smartthres) != 0 )
{
printf("Smartctl: SMART Thresholds Read Failed\n");
if (ataEnableAutoOffline (fd)){
printf( "Smartctl: SMART Enable Automatic Offline Failed.\n\n");
exit(-1);
}
printf ("SMART Automatic Offline Testing Enabled every four hours.\n");
}
if (smartautoofflinedisable){
if (!isSupportAutomaticTimer (smartval)){
printf("Device does not support SMART Automatic Timers.\n\n");
exit(-1);
}
if ( ataDisableAutoOffline (fd)){
printf( "Smartctl: SMART Disable Automatic Offline Failed.\n\n");
exit(-1);
}
printf ("SMART Automatic Offline Testing Disabled.\n");
}
if ( checksmart )
{
/* pseudo is used because linux does not support access to
Task File registers */
// I am very confused by this comment. Does anyone get it? Bruce
ataPsuedoCheckSmart ( smartval , smartthres);
// START OF READ-ONLY OPTIONS APART FROM -p and -i
if (checksmart || generalsmartvalues || smartvendorattrib || smarterrorlog || smartselftestlog)
printf("\n=== START OF READ SMART DATA SECTION ===\n");
}
// Check SMART status
if (checksmart)
// Eventually when working use the ataSmartStatus2 function here.
// This will then not require read values & thresholds above, and
// shouldl be moved in the code to just before the read values &
// thresholds statements.
ataPseudoCheckSmart(smartval, smartthres);
// Print general SMART values
if (generalsmartvalues)
{
ataPrintGeneralSmartValues(smartval);
}
// Print vendor-specific attributes
if (smartvendorattrib)
{
PrintSmartAttribWithThres(smartval, smartthres);
}
if ( smarterrorlog )
{
if ( isSmartErrorLogCapable(smartval) == 0)
{
// Print SMART error log
if (smarterrorlog){
if (!isSmartErrorLogCapable(smartval))
printf("Device does not support Error Logging\n");
}
else
{
if ( ataReadErrorLog ( fd, &smarterror) != 0 )
{
else {
if (ataReadErrorLog(fd, &smarterror))
printf("Smartctl: SMART Errorlog Read Failed\n");
}
else
{
ataPrintSmartErrorlog(smarterror);
}
}
}
if ( smartselftestlog )
{
if ( isSmartErrorLogCapable(smartval) == 0)
{
// Print SMART self-test log
if (smartselftestlog){
if (!isSmartErrorLogCapable(smartval))
printf("Device does not support Self Test Logging\n");
}
else
{
if ( ataReadSelfTestLog( fd, &smartselftest) != 0 )
{
else {
if(ataReadSelfTestLog(fd, &smartselftest))
printf("Smartctl: SMART Self Test Log Read Failed\n");
}
else
{
ataPrintSmartSelfTestlog(smartselftest);
}
}
}
if ( smartautoofflineenable )
{
if ( !isSupportAutomaticTimer (smartval))
{
printf("Device does not support SMART Automatic Timers\n");
exit(-1);
}
if ( ataEnableAutoOffline (fd) != 0)
{
printf( "Smartctl: SMART Enable Automatic Offline Failed\n");
exit(-1);
}
printf ("SMART Automatic Offline Testing Enabled every four hours\n");
}
if ( smartautoofflinedisable )
{
if ( !isSupportAutomaticTimer (smartval))
{
printf("Device does not support SMART Automatic Timers\n");
exit(-1);
}
if ( ataDisableAutoOffline (fd) != 0)
{
printf( "Smartctl: SMART Disable Automatic Offline Failed\n");
exit(-1);
}
printf ("SMART 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( "SMART Extended Self Test Failed\n");
exit(-1);
}
// START OF THE TESTING SECTION OF THE CODE. IF NO TESTING, RETURN
if (testcase==-1)
return;
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);
printf("\n=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n");
exit (0);
}
if ( smartextendcapselftest )
{
if ( ! isSupportSelfTest(smartval) )
{
printf ("ERROR: device does not support self test function\n");
// if doing a self-test, be sure it's supported by the hardware
if (testcase==OFFLINE_FULL_SCAN && !isSupportExecuteOfflineImmediate(smartval)){
printf("ERROR: device does not support Execute Off-Line Immediate function.\n\n");
exit(-1);
}
if ( ataSmartExtendCapSelfTest (fd) != 0)
{
printf( "SMART Extended Self Test Failed\n");
else if (!isSupportSelfTest(smartval)){
printf ("ERROR: device does not support Self-Test functions.\n\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");
// Now do the test
if (ataSmartTest(fd, testcase))
exit(-1);
}
if ( ataSmartSelfTestAbort (fd) != 0)
{
printf( "SMART Self Test Abort Failed\n");
exit(-1);
}
// Tell user how long test will take to complete
if ((timewait=TestTime(smartval,testcase))){
printf ("Please wait %d %s for test to complete.\n",
timewait, testcase==OFFLINE_FULL_SCAN?"seconds":"minutes");
printf ("Drive Command Successful self test aborted\n");
if (testcase!=SHORT_CAPTIVE_SELF_TEST && testcase!=EXTEND_CAPTIVE_SELF_TEST)
printf ("Use smartctl -%c to abort test.\n", SMARTSELFTESTABORT);
}
return;
}
// $Id: ataprint.h,v 1.5 2002/10/15 14:24:27 ballen4705 Exp $
// $Id: ataprint.h,v 1.6 2002/10/20 19:22:02 ballen4705 Exp $
/*
* ataprint.c
......@@ -32,11 +32,7 @@
#include "atacmds.h"
/* Print Format of Structures for SMART information */
/* Prints ATA Drive Information and S.M.A.R.T. Capability */
void ataPrintDriveInfo (struct hd_driveid);
void ataPrintGeneralSmartValues (struct ata_smart_values);
......@@ -52,12 +48,11 @@ void PrintSmartAttribWithThres (struct ata_smart_values data,
void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data);
void ataPsuedoCheckSmart (struct ata_smart_values ,
void ataPseudoCheckSmart (struct ata_smart_values ,
struct ata_smart_thresholds );
/* Prints Attribute Name for standard SMART attributes */
/* prints 20 character string */
void ataPrintSmartAttribName (unsigned char id);
void ataPrintMain ( int fd );
......
// $Id: extern.h,v 1.5 2002/10/15 14:24:27 ballen4705 Exp $
// $Id: extern.h,v 1.6 2002/10/20 19:22:02 ballen4705 Exp $
/*
* extern.h
*
......@@ -46,5 +46,5 @@ extern unsigned char smartautoofflinedisable;
extern unsigned char smartautosaveenable;
extern unsigned char smartautosavedisable;
extern unsigned char smart009minutes;
extern int testcase;
#endif
// $Id: smartctl.c,v 1.9 2002/10/15 14:24:27 ballen4705 Exp $
// $Id: smartctl.c,v 1.10 2002/10/20 19:22:02 ballen4705 Exp $
/*
* smartctl.c
*
......@@ -58,6 +58,7 @@ unsigned char smartautosaveenable = FALSE;
unsigned char smartautosavedisable = FALSE;
unsigned char printcopyleft = FALSE;
unsigned char smart009minutes = FALSE;
int testcase = -1;
/* void Usage (void)
......@@ -66,7 +67,7 @@ unsigned char smart009minutes = FALSE;
void Usage ( void){
printf( "usage: smartctl -[options] [device]\n");
printf( "Usage: smartctl -[options] [device]\n\n");
printf( "Read Only Options:\n");
printf( "\t\t%c\t\tShow version, copyright and license information\n", PRINTCOPYLEFT);
printf( "\t\t%c\t\tShow all S.M.A.R.T. Information (ATA and SCSI)\n", SMARTVERBOSEALL);
......@@ -94,12 +95,12 @@ void Usage ( void){
printf( "\t\t%c\t\tExecute Short Self Test (Captive Mode) (ATA Only)\n", SMARTSHORTCAPSELFTEST );
printf( "\t\t%c\t\tExecute Extended Self Test (ATA Only)\n", SMARTEXTENDSELFTEST );
printf( "\t\t%c\t\tExecute Extended Self Test (Captive Mode) (ATA Only)\n", SMARTEXTENDCAPSELFTEST );
printf( "\t\t%c\t\tExecute Self Test Abort (ATA Only)\n\n", SMARTSELFTESTABORT );
printf( "\t\t%c\t\tExecute Self Test Abort (ATA Only)\n", SMARTSELFTESTABORT );
printf( "Examples:\n");
printf("\tsmartctl -etf /dev/hda (Enables S.M.A.R.T. on first disk)\n");
printf("\tsmartctl -a /dev/hda (Prints all S.M.A.R.T. information)\n");
printf("\tsmartctl -X /dev/hda (Executes extended disk self-test)\n");
printf("Please see the man pages or the web site for further information.\n");
printf("\tsmartctl -X /dev/hda (Executes extended disk self-test)\n\n");
printf("Please see the man pages or %s for further information.\n",PROJECTHOME);
}
......@@ -131,7 +132,6 @@ void ParseOpts (int argc, char** argv){
driveinfo = TRUE;
break;
case CHECKSMART :
driveinfo = TRUE;
checksmart = TRUE;
break;
case SMARTVERBOSEALL :
......@@ -174,21 +174,27 @@ void ParseOpts (int argc, char** argv){
break;
case SMARTEXEOFFIMMEDIATE:
smartexeoffimmediate = TRUE;
testcase=OFFLINE_FULL_SCAN;
break;
case SMARTSHORTSELFTEST :
smartshortselftest = TRUE;
testcase=SHORT_SELF_TEST;
break;
case SMARTEXTENDSELFTEST :
smartextendselftest = TRUE;
testcase=EXTEND_SELF_TEST;
break;
case SMARTSHORTCAPSELFTEST:
smartshortcapselftest = TRUE;
testcase=SHORT_CAPTIVE_SELF_TEST;
break;
case SMARTEXTENDCAPSELFTEST:
smartextendcapselftest = TRUE;
testcase=EXTEND_CAPTIVE_SELF_TEST;
break;
case SMARTSELFTESTABORT:
smartselftestabort = TRUE;
testcase=ABORT_SELF_TEST;
break;
default:
Usage();
......@@ -197,9 +203,9 @@ void ParseOpts (int argc, char** argv){
if ( (smartexeoffimmediate + smartshortselftest +
smartextendselftest + smartshortcapselftest +
smartextendcapselftest ) > 1){
smartextendcapselftest +smartselftestabort ) > 1){
Usage();
printf ("\n ERROR: smartctl can only run a single test at a time \n");
printf ("\nERROR: smartctl can only run a single test (or abort) at a time.\n\n");
exit(-1);
}
}
......@@ -212,18 +218,19 @@ int main (int argc, char **argv){
char *device;
printf("smartctl version %d.%d-%d Copyright (C) 2002 Bruce Allen\n",RELEASE_MAJOR,RELEASE_MINOR,SMARTMONTOOLS_VERSION);
printf("Home page of smartctl is %s\n\n",PROJECTHOME);
printf("Home page of smartctl is %s\n",PROJECTHOME);
// Part input arguments
ParseOpts (argc,argv);
// Print Copyright/License info if needed
if (printcopyleft){
printf("smartctl comes with ABSOLUTELY NO WARRANTY. This\n");
printf("\nsmartctl comes with ABSOLUTELY NO WARRANTY. This\n");
printf("is free software, and you are welcome to redistribute it\n");
printf("under the terms of the GNU General Public License Version 2.\n");
printf("See http://www.gnu.org for further details.\n\n");
printf("CVS version ID %s\n","$Id: smartctl.c,v 1.9 2002/10/15 14:24:27 ballen4705 Exp $");
printf("CVS version ID %s\n","$Id: smartctl.c,v 1.10 2002/10/20 19:22:02 ballen4705 Exp $");
if (argc==2)
exit(0);
}
......
// $Id: smartctl.cpp,v 1.9 2002/10/15 14:24:27 ballen4705 Exp $
// $Id: smartctl.cpp,v 1.10 2002/10/20 19:22:02 ballen4705 Exp $
/*
* smartctl.c
*
......@@ -58,6 +58,7 @@ unsigned char smartautosaveenable = FALSE;
unsigned char smartautosavedisable = FALSE;
unsigned char printcopyleft = FALSE;
unsigned char smart009minutes = FALSE;
int testcase = -1;
/* void Usage (void)
......@@ -66,7 +67,7 @@ unsigned char smart009minutes = FALSE;
void Usage ( void){
printf( "usage: smartctl -[options] [device]\n");
printf( "Usage: smartctl -[options] [device]\n\n");
printf( "Read Only Options:\n");
printf( "\t\t%c\t\tShow version, copyright and license information\n", PRINTCOPYLEFT);
printf( "\t\t%c\t\tShow all S.M.A.R.T. Information (ATA and SCSI)\n", SMARTVERBOSEALL);
......@@ -94,12 +95,12 @@ void Usage ( void){
printf( "\t\t%c\t\tExecute Short Self Test (Captive Mode) (ATA Only)\n", SMARTSHORTCAPSELFTEST );
printf( "\t\t%c\t\tExecute Extended Self Test (ATA Only)\n", SMARTEXTENDSELFTEST );
printf( "\t\t%c\t\tExecute Extended Self Test (Captive Mode) (ATA Only)\n", SMARTEXTENDCAPSELFTEST );
printf( "\t\t%c\t\tExecute Self Test Abort (ATA Only)\n\n", SMARTSELFTESTABORT );
printf( "\t\t%c\t\tExecute Self Test Abort (ATA Only)\n", SMARTSELFTESTABORT );
printf( "Examples:\n");
printf("\tsmartctl -etf /dev/hda (Enables S.M.A.R.T. on first disk)\n");
printf("\tsmartctl -a /dev/hda (Prints all S.M.A.R.T. information)\n");
printf("\tsmartctl -X /dev/hda (Executes extended disk self-test)\n");
printf("Please see the man pages or the web site for further information.\n");
printf("\tsmartctl -X /dev/hda (Executes extended disk self-test)\n\n");
printf("Please see the man pages or %s for further information.\n",PROJECTHOME);
}
......@@ -131,7 +132,6 @@ void ParseOpts (int argc, char** argv){
driveinfo = TRUE;
break;
case CHECKSMART :
driveinfo = TRUE;
checksmart = TRUE;
break;
case SMARTVERBOSEALL :
......@@ -174,21 +174,27 @@ void ParseOpts (int argc, char** argv){
break;
case SMARTEXEOFFIMMEDIATE:
smartexeoffimmediate = TRUE;
testcase=OFFLINE_FULL_SCAN;
break;
case SMARTSHORTSELFTEST :
smartshortselftest = TRUE;
testcase=SHORT_SELF_TEST;
break;
case SMARTEXTENDSELFTEST :
smartextendselftest = TRUE;
testcase=EXTEND_SELF_TEST;
break;
case SMARTSHORTCAPSELFTEST:
smartshortcapselftest = TRUE;
testcase=SHORT_CAPTIVE_SELF_TEST;
break;
case SMARTEXTENDCAPSELFTEST:
smartextendcapselftest = TRUE;
testcase=EXTEND_CAPTIVE_SELF_TEST;
break;
case SMARTSELFTESTABORT:
smartselftestabort = TRUE;
testcase=ABORT_SELF_TEST;
break;
default:
Usage();
......@@ -197,9 +203,9 @@ void ParseOpts (int argc, char** argv){
if ( (smartexeoffimmediate + smartshortselftest +
smartextendselftest + smartshortcapselftest +
smartextendcapselftest ) > 1){
smartextendcapselftest +smartselftestabort ) > 1){
Usage();
printf ("\n ERROR: smartctl can only run a single test at a time \n");
printf ("\nERROR: smartctl can only run a single test (or abort) at a time.\n\n");
exit(-1);
}
}
......@@ -212,18 +218,19 @@ int main (int argc, char **argv){
char *device;
printf("smartctl version %d.%d-%d Copyright (C) 2002 Bruce Allen\n",RELEASE_MAJOR,RELEASE_MINOR,SMARTMONTOOLS_VERSION);
printf("Home page of smartctl is %s\n\n",PROJECTHOME);
printf("Home page of smartctl is %s\n",PROJECTHOME);
// Part input arguments
ParseOpts (argc,argv);
// Print Copyright/License info if needed
if (printcopyleft){
printf("smartctl comes with ABSOLUTELY NO WARRANTY. This\n");
printf("\nsmartctl comes with ABSOLUTELY NO WARRANTY. This\n");
printf("is free software, and you are welcome to redistribute it\n");
printf("under the terms of the GNU General Public License Version 2.\n");
printf("See http://www.gnu.org for further details.\n\n");
printf("CVS version ID %s\n","$Id: smartctl.cpp,v 1.9 2002/10/15 14:24:27 ballen4705 Exp $");
printf("CVS version ID %s\n","$Id: smartctl.cpp,v 1.10 2002/10/20 19:22:02 ballen4705 Exp $");
if (argc==2)
exit(0);
}
......
// $Id: smartd.c,v 1.9 2002/10/15 14:24:27 ballen4705 Exp $
// $Id: smartd.c,v 1.10 2002/10/20 19:22:02 ballen4705 Exp $
/*
* smartd.c
*
......@@ -117,6 +117,10 @@ void atadevicescan ( atadevices_t *devices){
printout(LOG_INFO,"%s Found and is SMART capable\n",device);
// This makes NO sense. We may want to know if the drive supports
// Offline Surface Scan, for example. But checking if it supports
// self-tests seems useless. In any case, smartd NEVER uses this
// field anywhere...
devices[numatadevices].selftest =
isSupportSelfTest(devices[numatadevices].smartval);
......@@ -213,6 +217,8 @@ int ataCheckDevice( atadevices_t *drive){
if ((failed=ataCheckSmart(tempsmartval,tempsmartthres)))
printout(LOG_CRIT,"Device: %s, Failed attribute: %i\n",drive->devicename,failed);
// WHEN IT WORKS, we should here add a call to ataSmartStatus2()
// see if any values have changed. Second argument is new values
ataCompareSmartValues (drive , tempsmartval);
......@@ -272,7 +278,7 @@ char copyleftstring[]=
"is free software, and you are welcome to redistribute it\n"
"under the terms of the GNU General Public License Version 2.\n"
"See http://www.gnu.org for further details.\n\n"
"CVS Version ID $Id: smartd.c,v 1.9 2002/10/15 14:24:27 ballen4705 Exp $\n";
"CVS Version ID $Id: smartd.c,v 1.10 2002/10/20 19:22:02 ballen4705 Exp $\n";
const char opts[] = { DEBUGMODE, EMAILNOTIFICATION, PRINTCOPYLEFT,'\0' };
......
// $Id: smartd.cpp,v 1.9 2002/10/15 14:24:27 ballen4705 Exp $
// $Id: smartd.cpp,v 1.10 2002/10/20 19:22:02 ballen4705 Exp $
/*
* smartd.c
*
......@@ -117,6 +117,10 @@ void atadevicescan ( atadevices_t *devices){
printout(LOG_INFO,"%s Found and is SMART capable\n",device);
// This makes NO sense. We may want to know if the drive supports
// Offline Surface Scan, for example. But checking if it supports
// self-tests seems useless. In any case, smartd NEVER uses this
// field anywhere...
devices[numatadevices].selftest =
isSupportSelfTest(devices[numatadevices].smartval);
......@@ -213,6 +217,8 @@ int ataCheckDevice( atadevices_t *drive){
if ((failed=ataCheckSmart(tempsmartval,tempsmartthres)))
printout(LOG_CRIT,"Device: %s, Failed attribute: %i\n",drive->devicename,failed);
// WHEN IT WORKS, we should here add a call to ataSmartStatus2()
// see if any values have changed. Second argument is new values
ataCompareSmartValues (drive , tempsmartval);
......@@ -272,7 +278,7 @@ char copyleftstring[]=
"is free software, and you are welcome to redistribute it\n"
"under the terms of the GNU General Public License Version 2.\n"
"See http://www.gnu.org for further details.\n\n"
"CVS Version ID $Id: smartd.cpp,v 1.9 2002/10/15 14:24:27 ballen4705 Exp $\n";
"CVS Version ID $Id: smartd.cpp,v 1.10 2002/10/20 19:22:02 ballen4705 Exp $\n";
const char opts[] = { DEBUGMODE, EMAILNOTIFICATION, PRINTCOPYLEFT,'\0' };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment