📄 os_win32.cpp
字号:
" smartctl -a /dev/hda (Prints all SMART information)\n\n"#ifdef HAVE_GETOPT_LONG " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n" " (Enables SMART on first disk)\n\n" " smartctl -t long /dev/hda (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n" " (Prints Self-Test & Attribute errors)\n"#else " smartctl -s on -o on -S on /dev/hda (Enables SMART on first disk)\n" " smartctl -t long /dev/hda (Executes extended disk self-test)\n" " smartctl -A -l selftest -q errorsonly /dev/hda\n" " (Prints Self-Test & Attribute errors)\n"#endif " smartctl -a /dev/scsi21\n" " (Prints all information for SCSI disk on ASPI adapter 2, ID 1)\n" " smartctl -a /dev/sda\n" " (Prints all information for SCSI disk on PhysicalDrive 0)\n" " smartctl -a /dev/pd3\n" " (Prints all information for SCSI disk on PhysicalDrive 3)\n" " smartctl -a /dev/tape1\n" " (Prints all information for SCSI tape on Tape 1)\n" " smartctl -A /dev/hdb,3\n" " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n" " smartctl -A /dev/tw_cli/c0/p1\n" " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n" "\n" " ATA SMART access methods and ordering may be specified by modifiers\n" " following the device name: /dev/hdX:[saicm], where\n" " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n" " 'i': IOCTL_IDE_PASS_THROUGH, 'c': ATA via IOCTL_SCSI_PASS_THROUGH,\n" " 'f': IOCTL_STORAGE_*, 'm': IOCTL_SCSI_MINIPORT_*.\n" " The default on this system is /dev/sdX:%s\n", ata_get_def_options() );}/////////////////////////////////////////////////////////////////////////////// ATA Interface/////////////////////////////////////////////////////////////////////////////// SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection)#define FILE_READ_ACCESS 0x0001#define FILE_WRITE_ACCESS 0x0002#define METHOD_BUFFERED 0#define CTL_CODE(DeviceType, Function, Method, Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))#define FILE_DEVICE_DISK 7#define IOCTL_DISK_BASE FILE_DEVICE_DISK#define SMART_GET_VERSION \ CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS)#define SMART_SEND_DRIVE_COMMAND \ CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)#define SMART_RCV_DRIVE_DATA \ CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)ASSERT_CONST(SMART_GET_VERSION , 0x074080);ASSERT_CONST(SMART_SEND_DRIVE_COMMAND, 0x07c084);ASSERT_CONST(SMART_RCV_DRIVE_DATA , 0x07c088);#define SMART_CYL_LOW 0x4F#define SMART_CYL_HI 0xC2#pragma pack(1)typedef struct _GETVERSIONOUTPARAMS { UCHAR bVersion; UCHAR bRevision; UCHAR bReserved; UCHAR bIDEDeviceMap; ULONG fCapabilities; ULONG dwReserved[4];} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;ASSERT_SIZEOF(GETVERSIONOUTPARAMS, 24);#define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameterstypedef struct _GETVERSIONINPARAMS_EX { BYTE bVersion; BYTE bRevision; BYTE bReserved; BYTE bIDEDeviceMap; DWORD fCapabilities; DWORD dwDeviceMapEx; // 3ware specific: RAID drive bit map WORD wIdentifier; // Vendor specific identifier WORD wControllerId; // 3ware specific: Controller ID (0,1,...) ULONG dwReserved[2];} GETVERSIONINPARAMS_EX, *PGETVERSIONINPARAMS_EX, *LPGETVERSIONINPARAMS_EX;ASSERT_SIZEOF(GETVERSIONINPARAMS_EX, sizeof(GETVERSIONOUTPARAMS));typedef struct _IDEREGS { UCHAR bFeaturesReg; UCHAR bSectorCountReg; UCHAR bSectorNumberReg; UCHAR bCylLowReg; UCHAR bCylHighReg; UCHAR bDriveHeadReg; UCHAR bCommandReg; UCHAR bReserved;} IDEREGS, *PIDEREGS, *LPIDEREGS;typedef struct _SENDCMDINPARAMS { ULONG cBufferSize; IDEREGS irDriveRegs; UCHAR bDriveNumber; UCHAR bReserved[3]; ULONG dwReserved[4]; UCHAR bBuffer[1];} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;ASSERT_SIZEOF(SENDCMDINPARAMS, 32+1);typedef struct _SENDCMDINPARAMS_EX { DWORD cBufferSize; IDEREGS irDriveRegs; BYTE bDriveNumber; BYTE bPortNumber; // 3ware specific: port number WORD wIdentifier; // Vendor specific identifier DWORD dwReserved[4]; BYTE bBuffer[1];} SENDCMDINPARAMS_EX, *PSENDCMDINPARAMS_EX, *LPSENDCMDINPARAMS_EX;ASSERT_SIZEOF(SENDCMDINPARAMS_EX, sizeof(SENDCMDINPARAMS));/* DRIVERSTATUS.bDriverError constants (just for info, not used)#define SMART_NO_ERROR 0#define SMART_IDE_ERROR 1#define SMART_INVALID_FLAG 2#define SMART_INVALID_COMMAND 3#define SMART_INVALID_BUFFER 4#define SMART_INVALID_DRIVE 5#define SMART_INVALID_IOCTL 6#define SMART_ERROR_NO_MEM 7#define SMART_INVALID_REGISTER 8#define SMART_NOT_SUPPORTED 9#define SMART_NO_IDE_DEVICE 10*/typedef struct _DRIVERSTATUS { UCHAR bDriverError; UCHAR bIDEError; UCHAR bReserved[2]; ULONG dwReserved[2];} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;typedef struct _SENDCMDOUTPARAMS { ULONG cBufferSize; DRIVERSTATUS DriverStatus; UCHAR bBuffer[1];} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1);#pragma pack()/////////////////////////////////////////////////////////////////////////////static void print_ide_regs(const IDEREGS * r, int out){ pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n", (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg, r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg);}static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro){ pout(" Input : "); print_ide_regs(ri, 0); if (ro) { pout(" Output: "); print_ide_regs(ro, 1); }}/////////////////////////////////////////////////////////////////////////////// call SMART_GET_VERSION, return device map or -1 on errorstatic int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version_ex = 0){ GETVERSIONOUTPARAMS vers; memset(&vers, 0, sizeof(vers)); const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers; DWORD num_out; if (!DeviceIoControl(hdevice, SMART_GET_VERSION, NULL, 0, &vers, sizeof(vers), &num_out, NULL)) { if (con->reportataioctl) pout(" SMART_GET_VERSION failed, Error=%ld\n", GetLastError()); errno = ENOSYS; return -1; } assert(num_out == sizeof(GETVERSIONOUTPARAMS)); if (con->reportataioctl > 1) { pout(" SMART_GET_VERSION suceeded, bytes returned: %lu\n" " Vers = %d.%d, Caps = 0x%lx, DeviceMap = 0x%02x\n", num_out, vers.bVersion, vers.bRevision, vers.fCapabilities, vers.bIDEDeviceMap); if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08lx\n", vers_ex.wIdentifier, vers_ex.wControllerId, vers_ex.dwDeviceMapEx); } if (ata_version_ex) *ata_version_ex = vers_ex; // TODO: Check vers.fCapabilities here? return vers.bIDEDeviceMap;}// call SMART_* ioctlstatic int smart_ioctl(HANDLE hdevice, int drive, IDEREGS * regs, char * data, unsigned datasize, int port){ SENDCMDINPARAMS inpar; SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar; unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512]; const SENDCMDOUTPARAMS * outpar; DWORD code, num_out; unsigned int size_out; const char * name; memset(&inpar, 0, sizeof(inpar)); inpar.irDriveRegs = *regs; // drive is set to 0-3 on Win9x only inpar.irDriveRegs.bDriveHeadReg = 0xA0 | ((drive & 1) << 4); inpar.bDriveNumber = drive; if (port >= 0) { // Set RAID port inpar_ex.wIdentifier = SMART_VENDOR_3WARE; inpar_ex.bPortNumber = port; } assert(datasize == 0 || datasize == 512); if (datasize) { code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA"; inpar.cBufferSize = size_out = 512; } else { code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND"; if (regs->bFeaturesReg == ATA_SMART_STATUS) size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data // Note: cBufferSize must be 0 on Win9x else size_out = 0; } memset(&outbuf, 0, sizeof(outbuf)); if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1, outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) { // CAUTION: DO NOT change "regs" Parameter in this case, see ata_command_interface() long err = GetLastError(); if (con->reportataioctl && (err != ERROR_INVALID_PARAMETER || con->reportataioctl > 1)) { pout(" %s failed, Error=%ld\n", name, err); print_ide_regs_io(regs, NULL); } errno = ( err == ERROR_INVALID_FUNCTION/*9x*/ || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/ || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); return -1; } // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs outpar = (const SENDCMDOUTPARAMS *)outbuf; if (outpar->DriverStatus.bDriverError) { if (con->reportataioctl) { pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name, outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError); print_ide_regs_io(regs, NULL); } errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO); return -1; } if (con->reportataioctl > 1) { pout(" %s suceeded, bytes returned: %lu (buffer %lu)\n", name, num_out, outpar->cBufferSize); print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ? (const IDEREGS *)(outpar->bBuffer) : NULL)); } if (datasize) memcpy(data, outpar->bBuffer, 512); else if (regs->bFeaturesReg == ATA_SMART_STATUS) { if (nonempty(const_cast<unsigned char *>(outpar->bBuffer), sizeof(IDEREGS))) *regs = *(const IDEREGS *)(outpar->bBuffer); else { // Workaround for driver not returning regs if (con->reportataioctl) pout(" WARNING: driver does not return ATA registers in output buffer!\n"); *regs = inpar.irDriveRegs; } } return 0;}/////////////////////////////////////////////////////////////////////////////// IDE PASS THROUGH (2000, XP, undocumented)//// Based on WinATA.cpp, 2002 c't/Matthias Withopf// ftp://ftp.heise.de/pub/ct/listings/0207-218.zip#define FILE_DEVICE_CONTROLLER 4#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER#define IOCTL_IDE_PASS_THROUGH \ CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)ASSERT_CONST(IOCTL_IDE_PASS_THROUGH, 0x04d028);#pragma pack(1)typedef struct { IDEREGS IdeReg; ULONG DataBufferSize; UCHAR DataBuffer[1];} ATA_PASS_THROUGH;ASSERT_SIZEOF(ATA_PASS_THROUGH, 12+1);#pragma pack()/////////////////////////////////////////////////////////////////////////////static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize){ if (datasize > 512) { errno = EINVAL; return -1; } unsigned int size = sizeof(ATA_PASS_THROUGH)-1 + datasize; ATA_PASS_THROUGH * buf = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); DWORD num_out; const unsigned char magic = 0xcf; if (!buf) { errno = ENOMEM; return -1; } buf->IdeReg = *regs; buf->DataBufferSize = datasize; if (datasize) buf->DataBuffer[0] = magic; if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH, buf, size, buf, size, &num_out, NULL)) { long err = GetLastError(); if (con->reportataioctl) { pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err); print_ide_regs_io(regs, NULL); } VirtualFree(buf, 0, MEM_RELEASE); errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); return -1; } // Check ATA status if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) { if (con->reportataioctl) { pout(" IOCTL_IDE_PASS_THROUGH command failed:\n"); print_ide_regs_io(regs, &buf->IdeReg); } VirtualFree(buf, 0, MEM_RELEASE); errno = EIO; return -1; } // Check and copy data if (datasize) { if ( num_out != size || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) { if (con->reportataioctl) { pout(" IOCTL_IDE_PASS_THROUGH output data missing (%lu, %lu)\n", num_out, buf->DataBufferSize); print_ide_regs_io(regs, &buf->IdeReg); } VirtualFree(buf, 0, MEM_RELEASE); errno = EIO; return -1; } memcpy(data, buf->DataBuffer, datasize); } if (con->reportataioctl > 1) { pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %lu (buffer %lu)\n", num_out, buf->DataBufferSize); print_ide_regs_io(regs, &buf->IdeReg); } *regs = buf->IdeReg; // Caution: VirtualFree() fails if parameter "dwSize" is nonzero VirtualFree(buf, 0, MEM_RELEASE); return 0;}/////////////////////////////////////////////////////////////////////////////// ATA PASS THROUGH (Win2003, XP SP2)#define IOCTL_ATA_PASS_THROUGH \ CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)ASSERT_CONST(IOCTL_ATA_PASS_THROUGH, 0x04d02c);typedef struct _ATA_PASS_THROUGH_EX { USHORT Length; USHORT AtaFlags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -