📄 os_win32.cpp
字号:
UCHAR PathId; UCHAR TargetId; UCHAR Lun; UCHAR ReservedAsUchar; ULONG DataTransferLength; ULONG TimeOutValue; ULONG ReservedAsUlong; ULONG/*_PTR*/ DataBufferOffset; UCHAR PreviousTaskFile[8]; UCHAR CurrentTaskFile[8];} ATA_PASS_THROUGH_EX, *PATA_PASS_THROUGH_EX;ASSERT_SIZEOF(ATA_PASS_THROUGH_EX, 40);#define ATA_FLAGS_DRDY_REQUIRED 0x01#define ATA_FLAGS_DATA_IN 0x02#define ATA_FLAGS_DATA_OUT 0x04#define ATA_FLAGS_48BIT_COMMAND 0x08/////////////////////////////////////////////////////////////////////////////static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize){ typedef struct { ATA_PASS_THROUGH_EX apt; ULONG Filler; UCHAR ucDataBuf[512]; } ATA_PASS_THROUGH_EX_WITH_BUFFERS; const unsigned char magic = 0xcf; ATA_PASS_THROUGH_EX_WITH_BUFFERS ab; memset(&ab, 0, sizeof(ab)); ab.apt.Length = sizeof(ATA_PASS_THROUGH_EX); //ab.apt.PathId = 0; //ab.apt.TargetId = 0; //ab.apt.Lun = 0; ab.apt.TimeOutValue = 10; unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf); ab.apt.DataBufferOffset = size; if (datasize > 0) { if (datasize > (int)sizeof(ab.ucDataBuf)) { errno = EINVAL; return -1; } ab.apt.AtaFlags = ATA_FLAGS_DATA_IN; ab.apt.DataTransferLength = datasize; size += datasize; ab.ucDataBuf[0] = magic; } else if (datasize < 0) { if (-datasize > (int)sizeof(ab.ucDataBuf)) { errno = EINVAL; return -1; } ab.apt.AtaFlags = ATA_FLAGS_DATA_OUT; ab.apt.DataTransferLength = -datasize; size += -datasize; memcpy(ab.ucDataBuf, data, -datasize); } else { assert(ab.apt.AtaFlags == 0); assert(ab.apt.DataTransferLength == 0); } assert(sizeof(ab.apt.CurrentTaskFile) == sizeof(IDEREGS)); IDEREGS * ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile; *ctfregs = *regs; DWORD num_out; if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH, &ab, size, &ab, size, &num_out, NULL)) { long err = GetLastError(); if (con->reportataioctl) { pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err); print_ide_regs_io(regs, NULL); } errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); return -1; } // Check ATA status if (ctfregs->bCommandReg/*Status*/ & 0x01) { if (con->reportataioctl) { pout(" IOCTL_ATA_PASS_THROUGH command failed:\n"); print_ide_regs_io(regs, ctfregs); } errno = EIO; return -1; } // Check and copy data if (datasize > 0) { if ( num_out != size || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) { if (con->reportataioctl) { pout(" IOCTL_ATA_PASS_THROUGH output data missing (%lu)\n", num_out); print_ide_regs_io(regs, ctfregs); } errno = EIO; return -1; } memcpy(data, ab.ucDataBuf, datasize); } if (con->reportataioctl > 1) { pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out); print_ide_regs_io(regs, ctfregs); } *regs = *ctfregs; return 0;}/////////////////////////////////////////////////////////////////////////////// ATA PASS THROUGH via SCSI PASS THROUGH (WinNT4 only)#define IOCTL_SCSI_PASS_THROUGH \ CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH, 0x04d004);#define SCSI_IOCTL_DATA_OUT 0#define SCSI_IOCTL_DATA_IN 1#define SCSI_IOCTL_DATA_UNSPECIFIED 2// undocumented SCSI opcode to for ATA passthrough#define SCSIOP_ATA_PASSTHROUGH 0xCCtypedef struct _SCSI_PASS_THROUGH { USHORT Length; UCHAR ScsiStatus; UCHAR PathId; UCHAR TargetId; UCHAR Lun; UCHAR CdbLength; UCHAR SenseInfoLength; UCHAR DataIn; ULONG DataTransferLength; ULONG TimeOutValue; ULONG/*_PTR*/ DataBufferOffset; ULONG SenseInfoOffset; UCHAR Cdb[16];} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;ASSERT_SIZEOF(SCSI_PASS_THROUGH, 44);/////////////////////////////////////////////////////////////////////////////static int ata_via_scsi_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize){ typedef struct { SCSI_PASS_THROUGH spt; ULONG Filler; UCHAR ucSenseBuf[32]; UCHAR ucDataBuf[512]; } SCSI_PASS_THROUGH_WITH_BUFFERS; SCSI_PASS_THROUGH_WITH_BUFFERS sb; IDEREGS * cdbregs; unsigned int size; DWORD num_out; const unsigned char magic = 0xcf; memset(&sb, 0, sizeof(sb)); sb.spt.Length = sizeof(SCSI_PASS_THROUGH); //sb.spt.PathId = 0; sb.spt.TargetId = 1; //sb.spt.Lun = 0; sb.spt.CdbLength = 10; sb.spt.SenseInfoLength = 24; sb.spt.TimeOutValue = 10; sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf); size = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf); sb.spt.DataBufferOffset = size; if (datasize) { if (datasize > sizeof(sb.ucDataBuf)) { errno = EINVAL; return -1; } sb.spt.DataIn = SCSI_IOCTL_DATA_IN; sb.spt.DataTransferLength = datasize; size += datasize; sb.ucDataBuf[0] = magic; } else { sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; //sb.spt.DataTransferLength = 0; } // Use pseudo SCSI command followed by registers sb.spt.Cdb[0] = SCSIOP_ATA_PASSTHROUGH; cdbregs = (IDEREGS *)(sb.spt.Cdb+2); *cdbregs = *regs; if (!DeviceIoControl(hdevice, IOCTL_SCSI_PASS_THROUGH, &sb, size, &sb, size, &num_out, NULL)) { long err = GetLastError(); if (con->reportataioctl) pout(" ATA via IOCTL_SCSI_PASS_THROUGH failed, Error=%ld\n", err); errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); return -1; } // Cannot check ATA status, because command does not return IDEREGS // Check and copy data if (datasize) { if ( num_out != size || (sb.ucDataBuf[0] == magic && !nonempty(sb.ucDataBuf+1, datasize-1))) { if (con->reportataioctl) { pout(" ATA via IOCTL_SCSI_PASS_THROUGH output data missing (%lu)\n", num_out); print_ide_regs_io(regs, NULL); } errno = EIO; return -1; } memcpy(data, sb.ucDataBuf, datasize); } if (con->reportataioctl > 1) { pout(" ATA via IOCTL_SCSI_PASS_THROUGH suceeded, bytes returned: %lu\n", num_out); print_ide_regs_io(regs, NULL); } return 0;}/////////////////////////////////////////////////////////////////////////////// SMART IOCTL via SCSI MINIPORT ioctl// This function is handled by ATAPI port driver (atapi.sys) or by SCSI// miniport driver (via SCSI port driver scsiport.sys).// It can be used to skip the missing or broken handling of some SMART// command codes (e.g. READ_LOG) in the disk class driver (disk.sys)#define IOCTL_SCSI_MINIPORT \ CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)ASSERT_CONST(IOCTL_SCSI_MINIPORT, 0x04d008);typedef struct _SRB_IO_CONTROL { ULONG HeaderLength; UCHAR Signature[8]; ULONG Timeout; ULONG ControlCode; ULONG ReturnCode; ULONG Length;} SRB_IO_CONTROL, *PSRB_IO_CONTROL;ASSERT_SIZEOF(SRB_IO_CONTROL, 28);#define FILE_DEVICE_SCSI 0x001b#define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500)#define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501)#define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502)#define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503)#define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504)#define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505)#define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506)#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)#define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508)#define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509)#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)#define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b)#define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c)/////////////////////////////////////////////////////////////////////////////static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize){ // Select code DWORD code = 0; const char * name = 0; if (regs->bCommandReg == ATA_IDENTIFY_DEVICE) { code = IOCTL_SCSI_MINIPORT_IDENTIFY; name = "IDENTIFY"; } else if (regs->bCommandReg == ATA_SMART_CMD) switch (regs->bFeaturesReg) { case ATA_SMART_READ_VALUES: code = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; name = "READ_SMART_ATTRIBS"; break; case ATA_SMART_READ_THRESHOLDS: code = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; name = "READ_SMART_THRESHOLDS"; break; case ATA_SMART_ENABLE: code = IOCTL_SCSI_MINIPORT_ENABLE_SMART; name = "ENABLE_SMART"; break; case ATA_SMART_DISABLE: code = IOCTL_SCSI_MINIPORT_DISABLE_SMART; name = "DISABLE_SMART"; break; case ATA_SMART_STATUS: code = IOCTL_SCSI_MINIPORT_RETURN_STATUS; name = "RETURN_STATUS"; break; case ATA_SMART_AUTOSAVE: code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; name = "ENABLE_DISABLE_AUTOSAVE"; break; //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break; case ATA_SMART_IMMEDIATE_OFFLINE: code = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; name = "EXECUTE_OFFLINE_DIAGS"; break; case ATA_SMART_AUTO_OFFLINE: code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; name = "ENABLE_DISABLE_AUTO_OFFLINE"; break; case ATA_SMART_READ_LOG_SECTOR: code = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; name = "READ_SMART_LOG"; break; case ATA_SMART_WRITE_LOG_SECTOR: code = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; name = "WRITE_SMART_LOG"; break; } if (!code) { errno = ENOSYS; return -1; } // Set SRB struct { SRB_IO_CONTROL srbc; union { SENDCMDINPARAMS in; SENDCMDOUTPARAMS out; } params; char space[512-1]; } sb; ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512); memset(&sb, 0, sizeof(sb)); unsigned size; if (datasize > 0) { if (datasize > (int)sizeof(sb.space)+1) { errno = EINVAL; return -1; } size = datasize; } else if (datasize < 0) { if (-datasize > (int)sizeof(sb.space)+1) { errno = EINVAL; return -1; } size = -datasize; memcpy(sb.params.in.bBuffer, data, size); } else if (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS) size = sizeof(IDEREGS); else size = 0; sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL); memcpy(sb.srbc.Signature, "SCSIDISK", 8); // atapi.sys sb.srbc.Timeout = 60; // seconds sb.srbc.ControlCode = code; //sb.srbc.ReturnCode = 0; sb.srbc.Length = sizeof(SENDCMDINPARAMS)-1 + size; sb.params.in.irDriveRegs = *regs; sb.params.in.cBufferSize = size; // Call miniport ioctl size += sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)-1; DWORD num_out; if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT, &sb, size, &sb, size, &num_out, NULL)) { long err = GetLastError(); if (con->reportataioctl) { pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err); print_ide_regs_io(regs, NULL); } errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); return -1; } // Check result if (sb.srbc.ReturnCode) { if (con->reportataioctl) { pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08lx\n", name, sb.srbc.ReturnCode); print_ide_regs_io(regs, NULL); } errno = EIO; return -1; } if (sb.params.out.DriverStatus.bDriverError) { if (con->reportataioctl) { pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name, sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError); print_ide_regs_io(regs, NULL); } errno = (!sb.params.out.DriverStatus.bIDEError ? ENOSYS : EIO); return -1; } if (con->reportataioctl > 1) { pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %lu (buffer %lu)\n", name, num_out, sb.params.out.cBufferSize); print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ? (const IDEREGS *)(sb.params.out.bBuffer) : 0)); } if (datasize > 0) memcpy(data, sb.params.out.bBuffer, datasize); else if (datasize == 0 && code == IOCTL_SCSI_MINIPORT_RETURN_STATUS) *regs = *(const IDEREGS *)(sb.params.out.bBuffer); return 0;}/////////////////////////////////////////////////////////////////////////////// ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctlstatic int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize, int port){ struct { SRB_IO_CONTROL srbc; IDEREGS regs; UCHAR buffer[512]; } sb; ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512); if (!(0 <= datasize && datasize <= (int)sizeof(sb.buffer) && port >= 0)) { errno = EINVAL; return -1; } memset(&sb, 0, sizeof(sb)); strcpy((char *)sb.srbc.Signature, "<3ware>"); sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL); sb.srbc.Timeout = 60; // seconds sb.srbc.ControlCode = 0xA0000000; sb.srbc.ReturnCode = 0; sb.srbc.Length = sizeof(IDEREGS) + (datasize > 0 ? datasize : 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -