📄 atacmds.cpp
字号:
}// returns 1 if SMART enabled, 0 if SMART disabled, -1 if can't tellint ataIsSmartEnabled(struct ata_identify_device *drive){ unsigned short word85=drive->cfs_enable_1; unsigned short word87=drive->csf_default; // check if words 85/86/87 contain valid info if ((word87>>14) == 0x01) // return value of SMART enabled bit return word85 & 0x0001; // Since we can't rely word85, we don't know if SMART is enabled. return -1;}// Reads SMART attributes into *dataint ataReadSmartValues(int device, struct ata_smart_values *data){ if (smartcommandhandler(device, READ_VALUES, 0, (char *)data)){ syserror("Error SMART Values Read failed"); return -1; } // compute checksum if (checksum((unsigned char *)data)) checksumwarning("SMART Attribute Data Structure"); // swap endian order if needed if (isbigendian()){ int i; swap2((char *)&(data->revnumber)); swap2((char *)&(data->total_time_to_complete_off_line)); swap2((char *)&(data->smart_capability)); for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){ struct ata_smart_attribute *x=data->vendor_attributes+i; swap2((char *)&(x->flags)); } } return 0;}// This corrects some quantities that are byte reversed in the SMART// SELF TEST LOGvoid fixsamsungselftestlog(struct ata_smart_selftestlog *data){ int i; // bytes 508/509 (numbered from 0) swapped (swap of self-test index // with one byte of reserved. swap2((char *)&(data->mostrecenttest)); // LBA low register (here called 'selftestnumber", containing // information about the TYPE of the self-test) is byte swapped with // Self-test execution status byte. These are bytes N, N+1 in the // entries. for (i=0; i<21; i++) swap2((char *)&(data->selftest_struct[i].selftestnumber)); return;}// Reads the Self Test Log (log #6)int ataReadSelfTestLog (int device, struct ata_smart_selftestlog *data){ // get data from device if (smartcommandhandler(device, READ_LOG, 0x06, (char *)data)){ syserror("Error SMART Error Self-Test Log Read failed"); return -1; } // compute its checksum, and issue a warning if needed if (checksum((unsigned char *)data)) checksumwarning("SMART Self-Test Log Structure"); // fix firmware bugs in self-test log if (con->fixfirmwarebug == FIX_SAMSUNG) fixsamsungselftestlog(data); // swap endian order if needed if (isbigendian()){ int i; swap2((char*)&(data->revnumber)); for (i=0; i<21; i++){ struct ata_smart_selftestlog_struct *x=data->selftest_struct+i; swap2((char *)&(x->timestamp)); swap4((char *)&(x->lbafirstfailure)); } } return 0;}// Reads the Log Directory (log #0). Note: NO CHECKSUM!!int ataReadLogDirectory (int device, struct ata_smart_log_directory *data){ // get data from device if (smartcommandhandler(device, READ_LOG, 0x00, (char *)data)){ return -1; } // swap endian order if needed if (isbigendian()){ swap2((char *)&(data->logversion)); } return 0;}// Reads the selective self-test log (log #9)int ataReadSelectiveSelfTestLog(int device, struct ata_selective_self_test_log *data){ // get data from device if (smartcommandhandler(device, READ_LOG, 0x09, (char *)data)){ syserror("Error SMART Read Selective Self-Test Log failed"); return -1; } // compute its checksum, and issue a warning if needed if (checksum((unsigned char *)data)) checksumwarning("SMART Selective Self-Test Log Structure"); // swap endian order if needed if (isbigendian()){ int i; swap2((char *)&(data->logversion)); for (i=0;i<5;i++){ swap8((char *)&(data->span[i].start)); swap8((char *)&(data->span[i].end)); } swap8((char *)&(data->currentlba)); swap2((char *)&(data->currentspan)); swap2((char *)&(data->flags)); swap2((char *)&(data->pendingtime)); } if (data->logversion != 1) pout("SMART Selective Self-Test Log Data Structure Revision Number (%d) should be 1\n", data->logversion); return 0;}// Writes the selective self-test log (log #9)int ataWriteSelectiveSelfTestLog(int device, struct ata_smart_values *sv, uint64_t num_sectors){ // Disk size must be known if (!num_sectors) { pout("Disk size is unknown, unable to check selective self-test spans\n"); return -1; } // Read log struct ata_selective_self_test_log sstlog, *data=&sstlog; unsigned char *ptr=(unsigned char *)data; if (ataReadSelectiveSelfTestLog(device, data)) { pout("Since Read failed, will not attempt to WRITE Selective Self-test Log\n"); return -1; } // Fix logversion if needed if (data->logversion !=1) { if (!con->permissive) { pout("Error SMART Selective Self-Test Log Data Structure Revision not recognized\n" "Revision number should be 1 but is %d. To be safe, aborting WRITE LOG.\n" "To fix revision number, add one '-T permissive' option.\n", data->logversion); return -2; } con->permissive--; pout("SMART Selective Self-Test Log Data Structure Revision should be 1 but is %d\n" "'-T permissive' specified, now trying to fix it by WRITE LOG.\n", data->logversion); data->logversion = 1; } // Host is NOT allowed to write selective self-test log if a selective // self-test is in progress. if (0<data->currentspan && data->currentspan<6 && ((sv->self_test_exec_status)>>4)==15) { pout("Error SMART Selective or other Self-Test in progress.\n"); return -4; } // Set start/end values based on old spans for special -t select,... options int i; for (i=0; i<con->smartselectivenumspans; i++) { char mode = con->smartselectivemode[i]; uint64_t start = con->smartselectivespan[i][0]; uint64_t end = con->smartselectivespan[i][1]; if (mode == SEL_CONT) {// redo or next dependig on last test status switch (sv->self_test_exec_status >> 4) { case 1: case 2: // Aborted/Interrupted by host pout("Continue Selective Self-Test: Redo last span\n"); mode = SEL_REDO; break; default: // All others pout("Continue Selective Self-Test: Start next span\n"); mode = SEL_NEXT; break; } } switch (mode) { case SEL_RANGE: // -t select,START-END break; case SEL_REDO: // -t select,redo... => Redo current start = data->span[i].start; if (end > 0) { // -t select,redo+SIZE end--; end += start; // [oldstart, oldstart+SIZE) } else // -t select,redo end = data->span[i].end; // [oldstart, oldend] break; case SEL_NEXT: // -t select,next... => Do next if (data->span[i].end == 0) { start = end = 0; break; // skip empty spans } start = data->span[i].end + 1; if (start >= num_sectors) start = 0; // wrap around if (end > 0) { // -t select,next+SIZE end--; end += start; // (oldend, oldend+SIZE] } else { // -t select,next uint64_t oldsize = data->span[i].end - data->span[i].start + 1; end = start + oldsize - 1; // (oldend, oldend+oldsize] if (end >= num_sectors) { // Adjust size to allow round-robin testing without future size decrease uint64_t spans = (num_sectors + oldsize-1) / oldsize; uint64_t newsize = (num_sectors + spans-1) / spans; uint64_t newstart = num_sectors - newsize, newend = num_sectors - 1; pout("Span %d changed from %"PRIu64"-%"PRIu64" (%"PRIu64" sectors)\n" " to %"PRIu64"-%"PRIu64" (%"PRIu64" sectors) (%"PRIu64" spans)\n", i, start, end, oldsize, newstart, newend, newsize, spans); start = newstart; end = newend; } } break; default: pout("ataWriteSelectiveSelfTestLog: Invalid mode %d\n", mode); return -1; } // Range check if (start < num_sectors && num_sectors <= end) { if (end != ~(uint64_t)0) // -t select,N-max pout("Size of self-test span %d decreased according to disk size\n", i); end = num_sectors - 1; } if (!(start <= end && end < num_sectors)) { pout("Invalid selective self-test span %d: %"PRIu64"-%"PRIu64" (%"PRIu64" sectors)\n", i, start, end, num_sectors); return -1; } // Write back to allow ataSmartTest() to print the actual values con->smartselectivespan[i][0] = start; con->smartselectivespan[i][1] = end; } // Clear spans for (i=0; i<5; i++) memset(data->span+i, 0, sizeof(struct test_span)); // Set spans for testing for (i=0; i<con->smartselectivenumspans; i++){ data->span[i].start = con->smartselectivespan[i][0]; data->span[i].end = con->smartselectivespan[i][1]; } // host must initialize to zero before initiating selective self-test data->currentlba=0; data->currentspan=0; // Perform off-line scan after selective test? if (1 == con->scanafterselect) // NO data->flags &= ~SELECTIVE_FLAG_DOSCAN; else if (2 == con->scanafterselect) // YES data->flags |= SELECTIVE_FLAG_DOSCAN; // Must clear active and pending flags before writing data->flags &= ~(SELECTIVE_FLAG_ACTIVE); data->flags &= ~(SELECTIVE_FLAG_PENDING); // modify pending time? if (con->pendingtime) data->pendingtime=(unsigned short)(con->pendingtime-1); // Set checksum to zero, then compute checksum data->checksum=0; unsigned char cksum=0; for (i=0; i<512; i++) cksum+=ptr[i]; cksum=~cksum; cksum+=1; data->checksum=cksum; // swap endian order if needed if (isbigendian()){ swap2((char *)&(data->logversion)); for (int i=0;i<5;i++){ swap8((char *)&(data->span[i].start)); swap8((char *)&(data->span[i].end)); } swap8((char *)&(data->currentlba)); swap2((char *)&(data->currentspan)); swap2((char *)&(data->flags)); swap2((char *)&(data->pendingtime)); } // write new selective self-test log if (smartcommandhandler(device, WRITE_LOG, 0x09, (char *)data)){ syserror("Error Write Selective Self-Test Log failed"); return -3; } return 0;}// This corrects some quantities that are byte reversed in the SMART// ATA ERROR LOG.void fixsamsungerrorlog(struct ata_smart_errorlog *data){ int i,j; // FIXED IN SAMSUNG -25 FIRMWARE??? // Device error count in bytes 452-3 swap2((char *)&(data->ata_error_count)); // FIXED IN SAMSUNG -22a FIRMWARE // step through 5 error log data structures for (i=0; i<5; i++){ // step through 5 command data structures for (j=0; j<5; j++) // Command data structure 4-byte millisec timestamp. These are // bytes (N+8, N+9, N+10, N+11). swap4((char *)&(data->errorlog_struct[i].commands[j].timestamp)); // Error data structure two-byte hour life timestamp. These are // bytes (N+28, N+29). swap2((char *)&(data->errorlog_struct[i].error_struct.timestamp)); } return;}// NEEDED ONLY FOR SAMSUNG -22 (some) -23 AND -24?? FIRMWAREvoid fixsamsungerrorlog2(struct ata_smart_errorlog *data){ // Device error count in bytes 452-3 swap2((char *)&(data->ata_error_count)); return;}// Reads the Summary SMART Error Log (log #1). The Comprehensive SMART// Error Log is #2, and the Extended Comprehensive SMART Error log is// #3int ataReadErrorLog (int device, struct ata_smart_errorlog *data){ // get data from device if (smartcommandhandler(device, READ_LOG, 0x01, (char *)data)){ syserror("Error SMART Error Log Read failed"); return -1; } // compute its checksum, and issue a warning if needed if (checksum((unsigned char *)data)) checksumwarning("SMART ATA Error Log Structure"); // Some disks have the byte order reversed in some SMART Summary // Error log entries if (con->fixfirmwarebug == FIX_SAMSUNG) fixsamsungerrorlog(data); else if (con->fixfirmwarebug == FIX_SAMSUNG2) fixsamsungerrorlog2(data); // swap endian order if needed if (isbigendian()){ int i,j; // Device error count in bytes 452-3 swap2((char *)&(data->ata_error_count)); // step through 5 error log data structures for (i=0; i<5; i++){ // step through 5 command data structures for (j=0; j<5; j++) // Command data structure 4-byte millisec timestamp swap4((char *)&(data->errorlog_struct[i].commands[j].timestamp)); // Error data structure life timestamp swap2((char *)&(data->errorlog_struct[i].error_struct.timestamp)); } } return 0;}int ataReadSmartThresholds (int device, struct ata_smart_thresholds_pvt *data){ // get data from device if (smartcommandhandler(device, READ_THRESHOLDS, 0, (char *)data)){ syserror("Error SMART Thresholds Read failed"); return -1; } // compute its checksum, and issue a warning if needed if (checksum((unsigned char *)data)) checksumwarning("SMART Attribute Thresholds Structure"); // swap endian order if needed if (isbigendian()) swap2((char *)&(data->revnumber)); return 0;}int ataEnableSmart (int device ){ if (smartcommandhandler(device, ENABLE, 0, NULL)){ syserror("Error SMART Enable failed"); return -1; } return 0;}int ataDisableSmart (int device ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -