📄 atacmds.cpp
字号:
if (smartcommandhandler(device, DISABLE, 0, NULL)){ syserror("Error SMART Disable failed"); return -1; } return 0;}int ataEnableAutoSave(int device){ if (smartcommandhandler(device, AUTOSAVE, 241, NULL)){ syserror("Error SMART Enable Auto-save failed"); return -1; } return 0;}int ataDisableAutoSave(int device){ if (smartcommandhandler(device, AUTOSAVE, 0, NULL)){ syserror("Error SMART Disable Auto-save failed"); return -1; } return 0;}// In *ALL* ATA standards the Enable/Disable AutoOffline command is// marked "OBSOLETE". It is defined in SFF-8035i Revision 2, and most// vendors still support it for backwards compatibility. IBM documents// it for some drives.int ataEnableAutoOffline (int device ){ /* timer hard coded to 4 hours */ if (smartcommandhandler(device, AUTO_OFFLINE, 248, NULL)){ syserror("Error SMART Enable Automatic Offline failed"); return -1; } return 0;}// Another Obsolete Command. See comments directly above, associated// with the corresponding Enable command.int ataDisableAutoOffline (int device ){ if (smartcommandhandler(device, AUTO_OFFLINE, 0, NULL)){ syserror("Error SMART Disable Automatic Offline failed"); return -1; } return 0;}// If SMART is enabled, supported, and working, then this call is// guaranteed to return 1, else zero. Note that it should return 1// regardless of whether the disk's SMART status is 'healthy' or// 'failing'.int ataDoesSmartWork(int device){ int retval=smartcommandhandler(device, STATUS, 0, NULL); if (-1 == retval) return 0; return 1;}// This function uses a different interface (DRIVE_TASK) than the// other commands in this file.int ataSmartStatus2(int device){ return smartcommandhandler(device, STATUS_CHECK, 0, NULL); }// 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, struct ata_smart_values *sv, uint64_t num_sectors){ char cmdmsg[128],*type,*captive; int errornum, cap, retval, select=0; // Boolean, if set, says test is captive cap=testtype & CAPTIVE_MASK; // Set up strings that describe the type of test if (cap) 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 if (testtype==EXTEND_SELF_TEST || testtype==EXTEND_CAPTIVE_SELF_TEST) type="Extended self-test"; else if (testtype==CONVEYANCE_SELF_TEST || testtype==CONVEYANCE_CAPTIVE_SELF_TEST) type="Conveyance self-test"; else if ((select=(testtype==SELECTIVE_SELF_TEST || testtype==SELECTIVE_CAPTIVE_SELF_TEST))) type="Selective self-test"; else type="[Unrecognized] self-test"; // If doing a selective self-test, first use WRITE_LOG to write the // selective self-test log. if (select && (retval=ataWriteSelectiveSelfTestLog(device, sv, num_sectors))) { if (retval==-4) pout("Can't start selective self-test without aborting current test: use '-X' option to smartctl.\n"); return retval; } // 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); pout("Sending command: \"%s\".\n",cmdmsg); if (select) { int i; pout("SPAN STARTING_LBA ENDING_LBA\n"); for (i = 0; i < con->smartselectivenumspans; i++) pout(" %d %20"PRId64" %20"PRId64"\n", i, con->smartselectivespan[i][0], con->smartselectivespan[i][1]); } // Now send the command to test errornum=smartcommandhandler(device, IMMEDIATE_OFFLINE, testtype, NULL); if (errornum && !(cap && errno==EIO)){ char errormsg[128]; sprintf(errormsg,"Command \"%s\" failed",cmdmsg); syserror(errormsg); pout("\n"); return -1; } // Since the command succeeded, tell user if (testtype==ABORT_SELF_TEST) pout("Self-testing aborted!\n"); else pout("Drive command \"%s\" successful.\nTesting has begun.\n",cmdmsg); return 0;}/* Test Time Functions */int TestTime(struct ata_smart_values *data,int testtype){ switch (testtype){ case OFFLINE_FULL_SCAN: return (int) data->total_time_to_complete_off_line; case SHORT_SELF_TEST: case SHORT_CAPTIVE_SELF_TEST: return (int) data->short_test_completion_time; case EXTEND_SELF_TEST: case EXTEND_CAPTIVE_SELF_TEST: return (int) data->extend_test_completion_time; case CONVEYANCE_SELF_TEST: case CONVEYANCE_CAPTIVE_SELF_TEST: return (int) data->conveyance_test_completion_time; default: return 0; }}// This function tells you both about the ATA error log and the// self-test error log capability (introduced in ATA-5). The bit is// poorly documented in the ATA/ATAPI standard. Starting with ATA-6,// SMART error logging is also indicated in bit 0 of DEVICE IDENTIFY// word 84 and 87. Top two bits must match the pattern 01. BEFORE// ATA-6 these top two bits still had to match the pattern 01, but the// remaining bits were reserved (==0).int isSmartErrorLogCapable (struct ata_smart_values *data, struct ata_identify_device *identity){ unsigned short word84=identity->command_set_extension; unsigned short word87=identity->csf_default; int isata6=identity->major_rev_num & (0x01<<6); int isata7=identity->major_rev_num & (0x01<<7); if ((isata6 || isata7) && (word84>>14) == 0x01 && (word84 & 0x01)) return 1; if ((isata6 || isata7) && (word87>>14) == 0x01 && (word87 & 0x01)) return 1; // otherwise we'll use the poorly documented capability bit return data->errorlog_capability & 0x01;}// See previous function. If the error log exists then the self-test// log should (must?) also exist.int isSmartTestLogCapable (struct ata_smart_values *data, struct ata_identify_device *identity){ unsigned short word84=identity->command_set_extension; unsigned short word87=identity->csf_default; int isata6=identity->major_rev_num & (0x01<<6); int isata7=identity->major_rev_num & (0x01<<7); if ((isata6 || isata7) && (word84>>14) == 0x01 && (word84 & 0x02)) return 1; if ((isata6 || isata7) && (word87>>14) == 0x01 && (word87 & 0x02)) return 1; // otherwise we'll use the poorly documented capability bit return data->errorlog_capability & 0x01;}int isGeneralPurposeLoggingCapable(struct ata_identify_device *identity){ unsigned short word84=identity->command_set_extension; unsigned short word87=identity->csf_default; // If bit 14 of word 84 is set to one and bit 15 of word 84 is // cleared to zero, the contents of word 84 contains valid support // information. If not, support information is not valid in this // word. if ((word84>>14) == 0x01) // If bit 5 of word 84 is set to one, the device supports the // General Purpose Logging feature set. return (word84 & (0x01 << 5)); // If bit 14 of word 87 is set to one and bit 15 of word 87 is // cleared to zero, the contents of words (87:85) contain valid // information. If not, information is not valid in these words. if ((word87>>14) == 0x01) // If bit 5 of word 87 is set to one, the device supports // the General Purpose Logging feature set. return (word87 & (0x01 << 5)); // not capable return 0;}// SMART self-test capability is also indicated in bit 1 of DEVICE// IDENTIFY word 87 (if top two bits of word 87 match pattern 01).// However this was only introduced in ATA-6 (but self-test log was in// ATA-5).int isSupportExecuteOfflineImmediate(struct ata_smart_values *data){ return data->offline_data_collection_capability & 0x01;}// Note in the ATA-5 standard, the following bit is listed as "Vendor// Specific". So it may not be reliable. The only use of this that I// have found is in IBM drives, where it is well-documented. See for// example page 170, section 13.32.1.18 of the IBM Travelstar 40GNX// hard disk drive specifications page 164 Revision 1.1 22 Apr 2002.int isSupportAutomaticTimer(struct ata_smart_values *data){ return data->offline_data_collection_capability & 0x02;}int isSupportOfflineAbort(struct ata_smart_values *data){ return data->offline_data_collection_capability & 0x04;}int isSupportOfflineSurfaceScan(struct ata_smart_values *data){ return data->offline_data_collection_capability & 0x08;}int isSupportSelfTest (struct ata_smart_values *data){ return data->offline_data_collection_capability & 0x10;}int isSupportConveyanceSelfTest(struct ata_smart_values *data){ return data->offline_data_collection_capability & 0x20;}int isSupportSelectiveSelfTest(struct ata_smart_values *data){ return data->offline_data_collection_capability & 0x40;}// Loop over all valid attributes. If they are prefailure attributes// and are at or below the threshold value, then return the ID of the// first failing attribute found. Return 0 if all prefailure// attributes are in bounds. The spec says "Bit 0// -Pre-failure/advisory - If the value of this bit equals zero, an// attribute value less than or equal to its corresponding attribute// threshold indicates an advisory condition where the usage or age of// the device has exceeded its intended design life period. If the// value of this bit equals one, an atribute value less than or equal// to its corresponding attribute threshold indicates a pre-failure// condition where imminent loss of data is being predicted."// onlyfailed=0 : are or were any age or prefailure attributes <= threshold// onlyfailed=1: are any prefailure attributes <= threshold nowint ataCheckSmart(struct ata_smart_values *data, struct ata_smart_thresholds_pvt *thresholds, int onlyfailed){ int i; // loop over all attributes for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){ // pointers to disk's values and vendor's thresholds struct ata_smart_attribute *disk=data->vendor_attributes+i; struct ata_smart_threshold_entry *thre=thresholds->thres_entries+i; // consider only valid attributes if (disk->id && thre->id){ int failednow,failedever; failednow =disk->current <= thre->threshold; failedever=disk->worst <= thre->threshold; if (!onlyfailed && failedever) return disk->id; if (onlyfailed && failednow && ATTRIBUTE_FLAGS_PREFAILURE(disk->flags)) return disk->id; } } return 0;}// This checks the n'th attribute in the attribute list, NOT the// attribute with id==n. If the attribute does not exist, or the// attribute is > threshold, then returns zero. If the attribute is// <= threshold (failing) then we the attribute number if it is a// prefail attribute. Else we return minus the attribute number if it// is a usage attribute.int ataCheckAttribute(struct ata_smart_values *data, struct ata_smart_thresholds_pvt *thresholds, int n){ struct ata_smart_attribute *disk; struct ata_smart_threshold_entry *thre; if (n<0 || n>=NUMBER_ATA_SMART_ATTRIBUTES || !data || !thresholds) return 0; // pointers to disk's values and vendor's thresholds disk=data->vendor_attributes+n; thre=thresholds->thres_entries+n; if (!disk || !thre) return 0; // consider only valid attributes, check for failure if (!disk->id || !thre->id || (disk->id != thre->id) || disk->current> thre->threshold) return 0; // We have found a failed attribute. Return positive or negative? if (ATTRIBUTE_FLAGS_PREFAILURE(disk->flags)) return disk->id; else return -1*(disk->id);}// Print temperature value and Min/Max value if presentstatic void ataPrintTemperatureValue(char *out, const unsigned char *raw, const unsigned *word){ out+=sprintf(out, "%u", word[0]); if (!word[1] && !word[2]) return; // No Min/Max unsigned lo = ~0, hi = ~0; if (!raw[3]) { // 00 HH 00 LL 00 TT (IBM) hi = word[2]; lo = word[1]; } else if (!word[2]) { // 00 00 HH LL 00 TT (Maxtor) hi = raw[3]; lo = raw[2]; } if (lo > hi) { unsigned t = lo; lo = hi; hi = t; } if (lo <= word[0] && word[0] <= hi) sprintf(out, " (Lifetime Min/Max %u/%u)", lo, hi); else sprintf(out, " (%u %u %u %u)", raw[5], raw[4], raw[3], raw[2]);}// This routine prints the raw value of an attribute as a text string// into out. It also returns this 48-bit number as a long long. The// array defs[] contains non-zero values if particular attributes have// non-default interpretations.int64_t ataPrintSmartAttribRawValue(char *out, struct ata_smart_attribute *attribute, unsigned char *defs){ int64_t rawvalue; unsigned word[3]; int j; unsigned char select; // convert the six individual bytes to a long long (8 byte) integer. // This is the value that we'll eventually return. rawvalue = 0; for (j=0; j<6; j++) { // This looks a bit roundabout, but is necessary. Don't // succumb to the temptation to use raw[j]<<(8*j) since under // the normal rules this will be promoted to the native type. // On a 32 bit machine this might then overflow. int64_t temp; temp = attribute->raw[j]; temp <<= 8*j; rawvalue |= temp; } // convert quantities to three two-byte words for (j=0; j<3; j++){ word[j] = attribute->raw[2*j+1]; word[j] <<= 8; word[j] |= attribute->raw[2*j]; } // if no data array, Attributes have default interpretations if (defs) select=defs[attribute->id]; else select=0; // Print six one-byte quantities. if (select==253){ for (j=0; j<5; j++) out+=sprintf(out, "%d ", attribute->raw[5-j]); out+=sprintf(out, "%d ", attribute->raw[0]); return rawvalue; } // Print three two-byte quantities if (select==254){ out+=sprintf(out, "%d %d %d", word[2], word[1], word[0]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -