📄 atacmds.cpp
字号:
// Construct the sorted list of strings. if (!(sorted_list = (const char **)malloc(sizeof vendorattributeargs))) goto END; for (ps = sorted_list, pp = pairs, i = 0; i < count; ps++, pp++, i++) *ps = pp->vaa; *ps = NULL;END: if (pairs) { for (i = 0; i < count; i++) if (pairs[i].padded_vaa) free((void *)pairs[i].padded_vaa); free((void *)pairs); } // If there was a problem creating the list then sorted_list should now // contain NULL. return sorted_list;}// Function to return a multiline string containing a list of the arguments in // vendorattributeargs[]. The strings are preceeded by tabs and followed// (except for the last) by newlines.// This function allocates the required memory for the string and the caller// must use free() to free it. It returns NULL if the required memory can't// be allocated.char *create_vendor_attribute_arg_list(void){ const char **ps, **sorted; char *s; int len; // Get a sorted list of vendor attribute arguments. If the sort fails // (which should only happen if the system is really low on memory) then just // use the unordered list. if (!(sorted = (const char **) sort_vendorattributeargs())) sorted = vendorattributeargs; // Calculate the required number of characters len = 1; // At least one char ('\0') for (ps = sorted; *ps != NULL; ps++) { len += 1; // For the tab len += strlen(*ps); // For the actual argument string if (*(ps+1)) len++; // For the newline if required } // Attempt to allocate memory for the string if (!(s = (char *)malloc(len))) return NULL; // Construct the string *s = '\0'; for (ps = sorted; *ps != NULL; ps++) { strcat(s, "\t"); strcat(s, *ps); if (*(ps+1)) strcat(s, "\n"); } free((char **)sorted); // Return a pointer to the string return s;}// swap two bytes. Point to low addressvoid swap2(char *location){ char tmp=*location; *location=*(location+1); *(location+1)=tmp; return;}// swap four bytes. Point to low addressvoid swap4(char *location){ char tmp=*location; *location=*(location+3); *(location+3)=tmp; swap2(location+1); return;}// swap eight bytes. Points to low addressvoid swap8(char *location){ char tmp=*location; *location=*(location+7); *(location+7)=tmp; tmp=*(location+1); *(location+1)=*(location+6); *(location+6)=tmp; swap4(location+2); return;}// Invalidate serial number and adjust checksum in IDENTIFY datastatic void invalidate_serno(ata_identify_device * id){ unsigned char sum = 0; for (unsigned i = 0; i < sizeof(id->serial_no); i++) { sum += id->serial_no[i]; sum -= id->serial_no[i] = 'X'; }#ifndef __NetBSD__ bool must_swap = !!isbigendian(); if (must_swap) swapx(id->words088_255+255-88);#endif if ((id->words088_255[255-88] & 0x00ff) == 0x00a5) id->words088_255[255-88] += sum << 8;#ifndef __NetBSD__ if (must_swap) swapx(id->words088_255+255-88);#endif}static char *commandstrings[]={ "SMART ENABLE", "SMART DISABLE", "SMART AUTOMATIC ATTRIBUTE SAVE", "SMART IMMEDIATE OFFLINE", "SMART AUTO OFFLINE", "SMART STATUS", "SMART STATUS CHECK", "SMART READ ATTRIBUTE VALUES", "SMART READ ATTRIBUTE THRESHOLDS", "SMART READ LOG", "IDENTIFY DEVICE", "IDENTIFY PACKET DEVICE", "CHECK POWER MODE", "SMART WRITE LOG", "WARNING (UNDEFINED COMMAND -- CONTACT DEVELOPERS AT " PACKAGE_BUGREPORT ")\n"};static void prettyprint(const unsigned char *p, const char *name){ pout("\n===== [%s] DATA START (BASE-16) =====\n", name); for (int i=0; i<512; i+=16, p+=16) // print complete line to avoid slow tty output and extra lines in syslog. pout("%03d-%03d: %02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n", i, i+16-1, p[ 0], p[ 1], p[ 2], p[ 3], p[ 4], p[ 5], p[ 6], p[ 7], p[ 8], p[ 9], p[10], p[11], p[12], p[13], p[14], p[15]); pout("===== [%s] DATA END (512 Bytes) =====\n\n", name);}static int parsedev_command_interface(int fd, smart_command_set command, int select, char * data);// This function provides the pretty-print reporting for SMART// commands: it implements the various -r "reporting" options for ATA// ioctls.int smartcommandhandler(int device, smart_command_set command, int select, char *data){ int retval; // This conditional is true for commands that return data int getsdata=(command==PIDENTIFY || command==IDENTIFY || command==READ_LOG || command==READ_THRESHOLDS || command==READ_VALUES || command==CHECK_POWER_MODE); int sendsdata=(command==WRITE_LOG); // If reporting is enabled, say what the command will be before it's executed if (con->reportataioctl){ // conditional is true for commands that use parameters int usesparam=(command==READ_LOG || command==AUTO_OFFLINE || command==AUTOSAVE || command==IMMEDIATE_OFFLINE || command==WRITE_LOG); pout("\nREPORT-IOCTL: DeviceFD=%d Command=%s", device, commandstrings[command]); if (usesparam) pout(" InputParameter=%d\n", select); else pout("\n"); } if ((getsdata || sendsdata) && !data){ pout("REPORT-IOCTL: Unable to execute command %s : data destination address is NULL\n", commandstrings[command]); return -1; } // The reporting is cleaner, and we will find coding bugs faster, if // the commands that failed clearly return empty (zeroed) data // structures if (getsdata) { if (command==CHECK_POWER_MODE) data[0]=0; else memset(data, '\0', 512); } // if requested, pretty-print the input data structure if (con->reportataioctl>1 && sendsdata) prettyprint((unsigned char *)data, commandstrings[command]); // In case the command produces an error, we'll want to know what it is: errno=0; // now execute the command switch (con->controller_type) { case CONTROLLER_3WARE_678K: case CONTROLLER_3WARE_678K_CHAR: case CONTROLLER_3WARE_9000_CHAR: retval=escalade_command_interface(device, con->controller_port-1, con->controller_type, command, select, data); if (retval && con->controller_port<=0) pout("WARNING: apparently missing '-d 3ware,N' disk specification\n"); break; case CONTROLLER_MARVELL_SATA: retval=marvell_command_interface(device, command, select, data); break; case CONTROLLER_SAT: retval=sat_command_interface(device, command, select, data); break; case CONTROLLER_HPT: retval=highpoint_command_interface(device, command, select, data); break; case CONTROLLER_PARSEDEV: retval=parsedev_command_interface(device, command, select, data); break; default: retval=ata_command_interface(device, command, select, data); } // If requested, invalidate serial number before any printing is done if ((command == IDENTIFY || command == PIDENTIFY) && !retval && con->dont_print_serial) invalidate_serno((ata_identify_device *)data); // If reporting is enabled, say what output was produced by the command if (con->reportataioctl){ if (errno) pout("REPORT-IOCTL: DeviceFD=%d Command=%s returned %d errno=%d [%s]\n", device, commandstrings[command], retval, errno, strerror(errno)); else pout("REPORT-IOCTL: DeviceFD=%d Command=%s returned %d\n", device, commandstrings[command], retval); // if requested, pretty-print the output data structure if (con->reportataioctl>1 && getsdata) { if (command==CHECK_POWER_MODE) pout("Sector Count Register (BASE-16): %02x\n", (unsigned char)(*data)); else prettyprint((unsigned char *)data, commandstrings[command]); } } return retval;}// This function computes the checksum of a single disk sector (512// bytes). Returns zero if checksum is OK, nonzero if the checksum is// incorrect. The size (512) is correct for all SMART structures.unsigned char checksum(unsigned char *buffer){ unsigned char sum=0; int i; for (i=0; i<512; i++) sum+=buffer[i]; return sum;}// returns -1 if command fails or the device is in Sleep mode, else// value of Sector Count register. Sector Count result values:// 00h device is in Standby mode. // 80h device is in Idle mode.// FFh device is in Active mode or Idle mode.int ataCheckPowerMode(int device) { unsigned char result; if ((smartcommandhandler(device, CHECK_POWER_MODE, 0, (char *)&result))) return -1; if (result!=0 && result!=0x80 && result!=0xff) pout("ataCheckPowerMode(): ATA CHECK POWER MODE returned unknown Sector Count Register value %02x\n", result); return (int)result;}// Reads current Device Identity info (512 bytes) into buf. Returns 0// if all OK. Returns -1 if no ATA Device identity can be// established. Returns >0 if Device is ATA Packet Device (not SMART// capable). The value of the integer helps identify the type of// Packet device, which is useful so that the user can connect the// formal device number with whatever object is inside their computer.int ataReadHDIdentity (int device, struct ata_identify_device *buf){ unsigned short *rawshort=(unsigned short *)buf; unsigned char *rawbyte =(unsigned char *)buf; // See if device responds either to IDENTIFY DEVICE or IDENTIFY // PACKET DEVICE if ((smartcommandhandler(device, IDENTIFY, 0, (char *)buf))){ if (smartcommandhandler(device, PIDENTIFY, 0, (char *)buf)){ return -1; } }#ifndef __NetBSD__ // if machine is big-endian, swap byte order as needed // NetBSD kernel delivers IDENTIFY data in host byte order if (isbigendian()){ int i; // swap various capability words that are needed for (i=0; i<33; i++) swap2((char *)(buf->words047_079+i)); for (i=80; i<=87; i++) swap2((char *)(rawshort+i)); for (i=0; i<168; i++) swap2((char *)(buf->words088_255+i)); }#endif // If there is a checksum there, validate it if ((rawshort[255] & 0x00ff) == 0x00a5 && checksum(rawbyte)) checksumwarning("Drive Identity Structure"); // If this is a PACKET DEVICE, return device type if (rawbyte[1] & 0x80) return 1+(rawbyte[1] & 0x1f); // Not a PACKET DEVICE 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 ata_identify_device *drive, unsigned short *minor){ unsigned short major; int i; // check that arrays at the top of this file are defined // consistently if (sizeof(minor_str) != sizeof(char *)*(1+MINOR_MAX)){ pout("Internal error in ataVersionInfo(). minor_str[] size %d\n" "is not consistent with value of MINOR_MAX+1 = %d\n", (int)(sizeof(minor_str)/sizeof(char *)), MINOR_MAX+1); fflush(NULL); abort(); } if (sizeof(actual_ver) != sizeof(int)*(1+MINOR_MAX)){ pout("Internal error in ataVersionInfo(). actual_ver[] size %d\n" "is not consistent with value of MINOR_MAX = %d\n", (int)(sizeof(actual_ver)/sizeof(int)), MINOR_MAX+1); fflush(NULL); abort(); } // get major and minor ATA revision numbers major=drive->major_rev_num; *minor=drive->minor_rev_num; // First check if device has ANY ATA version information in it if (major==NOVAL_0 || major==NOVAL_1) { *description=NULL; return -1; } // The minor revision number has more information - try there first if (*minor && (*minor<=MINOR_MAX)){ int std = actual_ver[*minor]; if (std) { *description=minor_str[*minor]; return std; } } // Try new ATA-8 minor revision numbers (Table 32 of T13/1699-D Revision 4c) // (not in actual_ver/minor_str to avoid large sparse tables) const char *desc; switch (*minor) { case 0x0027: desc = "ATA-8-ACS revision 3c"; break; case 0x0029: desc = "ATA-8-ACS revision 4"; break; case 0x0033: desc = "ATA-8-ACS revision 3e"; break; case 0x0039: desc = "ATA-8-ACS revision 4c"; break; case 0x0042: desc = "ATA-8-ACS revision 3f"; break; case 0x0052: desc = "ATA-8-ACS revision 3b"; break; case 0x0107: desc = "ATA-8-ACS revision 2d"; break; default: desc = 0; break; } if (desc) { *description = desc; return 8; } // HDPARM has a very complicated algorithm from here on. Since SMART only // exists on ATA-3 and later standards, let's punt on this. If you don't // like it, please fix it. The code's in CVS. for (i=15; i>0; i--) if (major & (0x1<<i)) break; *description=NULL; if (i==0) return 1; else return i;}// returns 1 if SMART supported, 0 if SMART unsupported, -1 if can't tellint ataSmartSupport(struct ata_identify_device *drive){ unsigned short word82=drive->command_set_1; unsigned short word83=drive->command_set_2; // check if words 82/83 contain valid info if ((word83>>14) == 0x01) // return value of SMART support bit return word82 & 0x0001; // since we can're rely on word 82, we don't know if SMART supported return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -