Use APTD to communicate with ATA devices in Windows.

This commit is contained in:
2021-09-15 23:55:06 +01:00
parent aba2e7fb9f
commit 0847dafd7d
3 changed files with 115 additions and 137 deletions

View File

@@ -136,29 +136,23 @@ namespace Aaru.Devices.Windows
if(buffer == null) if(buffer == null)
return -1; return -1;
uint offsetForBuffer = (uint)(Marshal.SizeOf(typeof(AtaPassThroughEx)) + Marshal.SizeOf(typeof(uint))); var aptd = new AtaPassThroughDirect
var aptdBuf = new AtaPassThroughExBuffer
{ {
aptd = new AtaPassThroughEx TimeOutValue = timeout,
DataBuffer = Marshal.AllocHGlobal(buffer.Length),
Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughDirect)),
DataTransferLength = (uint)buffer.Length,
PreviousTaskFile = new AtaTaskFile(),
CurrentTaskFile = new AtaTaskFile
{ {
TimeOutValue = timeout, Command = registers.Command,
DataBufferOffset = (IntPtr)offsetForBuffer, CylinderHigh = registers.CylinderHigh,
Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughEx)), CylinderLow = registers.CylinderLow,
DataTransferLength = (uint)buffer.Length, DeviceHead = registers.DeviceHead,
PreviousTaskFile = new AtaTaskFile(), Features = registers.Feature,
CurrentTaskFile = new AtaTaskFile SectorCount = registers.SectorCount,
{ SectorNumber = registers.Sector
Command = registers.Command, }
CylinderHigh = registers.CylinderHigh,
CylinderLow = registers.CylinderLow,
DeviceHead = registers.DeviceHead,
Features = registers.Feature,
SectorCount = registers.SectorCount,
SectorNumber = registers.Sector
}
},
dataBuffer = new byte[64 * 512]
}; };
switch(protocol) switch(protocol)
@@ -166,12 +160,12 @@ namespace Aaru.Devices.Windows
case AtaProtocol.PioIn: case AtaProtocol.PioIn:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.Dma: case AtaProtocol.Dma:
aptdBuf.aptd.AtaFlags = AtaFlags.DataIn; aptd.AtaFlags = AtaFlags.DataIn;
break; break;
case AtaProtocol.PioOut: case AtaProtocol.PioOut:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags = AtaFlags.DataOut; aptd.AtaFlags = AtaFlags.DataOut;
break; break;
} }
@@ -183,44 +177,46 @@ namespace Aaru.Devices.Windows
case AtaProtocol.FpDma: case AtaProtocol.FpDma:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags |= AtaFlags.Dma; aptd.AtaFlags |= AtaFlags.Dma;
break; break;
} }
// Unknown if needed // Unknown if needed
aptdBuf.aptd.AtaFlags |= AtaFlags.DrdyRequired; aptd.AtaFlags |= AtaFlags.DrdyRequired;
uint k = 0; uint k = 0;
int error = 0; int error = 0;
Array.Copy(buffer, 0, aptdBuf.dataBuffer, 0, buffer.Length); Marshal.Copy(buffer, 0, aptd.DataBuffer, buffer.Length);
DateTime start = DateTime.Now; DateTime start = DateTime.Now;
sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThrough, ref aptdBuf, sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
(uint)Marshal.SizeOf(aptdBuf), ref aptdBuf, (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
(uint)Marshal.SizeOf(aptdBuf), ref k, IntPtr.Zero); IntPtr.Zero);
DateTime end = DateTime.Now; DateTime end = DateTime.Now;
if(sense) if(sense)
error = Marshal.GetLastWin32Error(); error = Marshal.GetLastWin32Error();
Array.Copy(aptdBuf.dataBuffer, 0, buffer, 0, buffer.Length); Marshal.Copy(aptd.DataBuffer, buffer, 0, buffer.Length);
duration = (end - start).TotalMilliseconds; duration = (end - start).TotalMilliseconds;
errorRegisters.CylinderHigh = aptdBuf.aptd.CurrentTaskFile.CylinderHigh; errorRegisters.CylinderHigh = aptd.CurrentTaskFile.CylinderHigh;
errorRegisters.CylinderLow = aptdBuf.aptd.CurrentTaskFile.CylinderLow; errorRegisters.CylinderLow = aptd.CurrentTaskFile.CylinderLow;
errorRegisters.DeviceHead = aptdBuf.aptd.CurrentTaskFile.DeviceHead; errorRegisters.DeviceHead = aptd.CurrentTaskFile.DeviceHead;
errorRegisters.Error = aptdBuf.aptd.CurrentTaskFile.Error; errorRegisters.Error = aptd.CurrentTaskFile.Error;
errorRegisters.Sector = aptdBuf.aptd.CurrentTaskFile.SectorNumber; errorRegisters.Sector = aptd.CurrentTaskFile.SectorNumber;
errorRegisters.SectorCount = aptdBuf.aptd.CurrentTaskFile.SectorCount; errorRegisters.SectorCount = aptd.CurrentTaskFile.SectorCount;
errorRegisters.Status = aptdBuf.aptd.CurrentTaskFile.Status; errorRegisters.Status = aptd.CurrentTaskFile.Status;
sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0;
Marshal.FreeHGlobal(aptd.DataBuffer);
return error; return error;
} }
@@ -245,29 +241,23 @@ namespace Aaru.Devices.Windows
if(buffer == null) if(buffer == null)
return -1; return -1;
uint offsetForBuffer = (uint)(Marshal.SizeOf(typeof(AtaPassThroughEx)) + Marshal.SizeOf(typeof(uint))); var aptd = new AtaPassThroughDirect
var aptdBuf = new AtaPassThroughExBuffer
{ {
aptd = new AtaPassThroughEx TimeOutValue = timeout,
DataBuffer = Marshal.AllocHGlobal(buffer.Length),
Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughDirect)),
DataTransferLength = (uint)buffer.Length,
PreviousTaskFile = new AtaTaskFile(),
CurrentTaskFile = new AtaTaskFile
{ {
TimeOutValue = timeout, Command = registers.Command,
DataBufferOffset = (IntPtr)offsetForBuffer, CylinderHigh = registers.LbaHigh,
Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughEx)), CylinderLow = registers.LbaMid,
DataTransferLength = (uint)buffer.Length, DeviceHead = registers.DeviceHead,
PreviousTaskFile = new AtaTaskFile(), Features = registers.Feature,
CurrentTaskFile = new AtaTaskFile SectorCount = registers.SectorCount,
{ SectorNumber = registers.LbaLow
Command = registers.Command, }
CylinderHigh = registers.LbaHigh,
CylinderLow = registers.LbaMid,
DeviceHead = registers.DeviceHead,
Features = registers.Feature,
SectorCount = registers.SectorCount,
SectorNumber = registers.LbaLow
}
},
dataBuffer = new byte[64 * 512]
}; };
switch(protocol) switch(protocol)
@@ -275,12 +265,12 @@ namespace Aaru.Devices.Windows
case AtaProtocol.PioIn: case AtaProtocol.PioIn:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.Dma: case AtaProtocol.Dma:
aptdBuf.aptd.AtaFlags = AtaFlags.DataIn; aptd.AtaFlags = AtaFlags.DataIn;
break; break;
case AtaProtocol.PioOut: case AtaProtocol.PioOut:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags = AtaFlags.DataOut; aptd.AtaFlags = AtaFlags.DataOut;
break; break;
} }
@@ -292,44 +282,46 @@ namespace Aaru.Devices.Windows
case AtaProtocol.FpDma: case AtaProtocol.FpDma:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags |= AtaFlags.Dma; aptd.AtaFlags |= AtaFlags.Dma;
break; break;
} }
// Unknown if needed // Unknown if needed
aptdBuf.aptd.AtaFlags |= AtaFlags.DrdyRequired; aptd.AtaFlags |= AtaFlags.DrdyRequired;
uint k = 0; uint k = 0;
int error = 0; int error = 0;
Array.Copy(buffer, 0, aptdBuf.dataBuffer, 0, buffer.Length); Marshal.Copy(buffer, 0, aptd.DataBuffer, buffer.Length);
DateTime start = DateTime.Now; DateTime start = DateTime.Now;
sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThrough, ref aptdBuf, sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
(uint)Marshal.SizeOf(aptdBuf), ref aptdBuf, (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
(uint)Marshal.SizeOf(aptdBuf), ref k, IntPtr.Zero); IntPtr.Zero);
DateTime end = DateTime.Now; DateTime end = DateTime.Now;
if(sense) if(sense)
error = Marshal.GetLastWin32Error(); error = Marshal.GetLastWin32Error();
Array.Copy(aptdBuf.dataBuffer, 0, buffer, 0, buffer.Length); Marshal.Copy(aptd.DataBuffer, buffer, 0, buffer.Length);
duration = (end - start).TotalMilliseconds; duration = (end - start).TotalMilliseconds;
errorRegisters.LbaHigh = aptdBuf.aptd.CurrentTaskFile.CylinderHigh; errorRegisters.LbaHigh = aptd.CurrentTaskFile.CylinderHigh;
errorRegisters.LbaMid = aptdBuf.aptd.CurrentTaskFile.CylinderLow; errorRegisters.LbaMid = aptd.CurrentTaskFile.CylinderLow;
errorRegisters.DeviceHead = aptdBuf.aptd.CurrentTaskFile.DeviceHead; errorRegisters.DeviceHead = aptd.CurrentTaskFile.DeviceHead;
errorRegisters.Error = aptdBuf.aptd.CurrentTaskFile.Error; errorRegisters.Error = aptd.CurrentTaskFile.Error;
errorRegisters.LbaLow = aptdBuf.aptd.CurrentTaskFile.SectorNumber; errorRegisters.LbaLow = aptd.CurrentTaskFile.SectorNumber;
errorRegisters.SectorCount = aptdBuf.aptd.CurrentTaskFile.SectorCount; errorRegisters.SectorCount = aptd.CurrentTaskFile.SectorCount;
errorRegisters.Status = aptdBuf.aptd.CurrentTaskFile.Status; errorRegisters.Status = aptd.CurrentTaskFile.Status;
sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0;
Marshal.FreeHGlobal(aptd.DataBuffer);
return error; return error;
} }
@@ -354,36 +346,30 @@ namespace Aaru.Devices.Windows
if(buffer == null) if(buffer == null)
return -1; return -1;
uint offsetForBuffer = (uint)(Marshal.SizeOf(typeof(AtaPassThroughEx)) + Marshal.SizeOf(typeof(uint))); var aptd = new AtaPassThroughDirect
var aptdBuf = new AtaPassThroughExBuffer
{ {
aptd = new AtaPassThroughEx TimeOutValue = timeout,
DataBuffer = Marshal.AllocHGlobal(buffer.Length),
Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughDirect)),
DataTransferLength = (uint)buffer.Length,
PreviousTaskFile = new AtaTaskFile
{ {
TimeOutValue = timeout, CylinderHigh = registers.LbaHighPrevious,
DataBufferOffset = (IntPtr)offsetForBuffer, CylinderLow = registers.LbaMidPrevious,
Length = (ushort)Marshal.SizeOf(typeof(AtaPassThroughEx)), Features = (byte)((registers.Feature & 0xFF00) >> 8),
DataTransferLength = (uint)buffer.Length, SectorCount = (byte)((registers.SectorCount & 0xFF00) >> 8),
PreviousTaskFile = new AtaTaskFile SectorNumber = registers.LbaLowPrevious
{
CylinderHigh = registers.LbaHighPrevious,
CylinderLow = registers.LbaMidPrevious,
Features = (byte)((registers.Feature & 0xFF00) >> 8),
SectorCount = (byte)((registers.SectorCount & 0xFF00) >> 8),
SectorNumber = registers.LbaLowPrevious
},
CurrentTaskFile = new AtaTaskFile
{
Command = registers.Command,
CylinderHigh = registers.LbaHighCurrent,
CylinderLow = registers.LbaMidCurrent,
DeviceHead = registers.DeviceHead,
Features = (byte)(registers.Feature & 0xFF),
SectorCount = (byte)(registers.SectorCount & 0xFF),
SectorNumber = registers.LbaLowCurrent
}
}, },
dataBuffer = new byte[64 * 512] CurrentTaskFile = new AtaTaskFile
{
Command = registers.Command,
CylinderHigh = registers.LbaHighCurrent,
CylinderLow = registers.LbaMidCurrent,
DeviceHead = registers.DeviceHead,
Features = (byte)(registers.Feature & 0xFF),
SectorCount = (byte)(registers.SectorCount & 0xFF),
SectorNumber = registers.LbaLowCurrent
}
}; };
switch(protocol) switch(protocol)
@@ -391,12 +377,12 @@ namespace Aaru.Devices.Windows
case AtaProtocol.PioIn: case AtaProtocol.PioIn:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.Dma: case AtaProtocol.Dma:
aptdBuf.aptd.AtaFlags = AtaFlags.DataIn; aptd.AtaFlags = AtaFlags.DataIn;
break; break;
case AtaProtocol.PioOut: case AtaProtocol.PioOut:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags = AtaFlags.DataOut; aptd.AtaFlags = AtaFlags.DataOut;
break; break;
} }
@@ -408,51 +394,53 @@ namespace Aaru.Devices.Windows
case AtaProtocol.FpDma: case AtaProtocol.FpDma:
case AtaProtocol.UDmaIn: case AtaProtocol.UDmaIn:
case AtaProtocol.UDmaOut: case AtaProtocol.UDmaOut:
aptdBuf.aptd.AtaFlags |= AtaFlags.Dma; aptd.AtaFlags |= AtaFlags.Dma;
break; break;
} }
aptdBuf.aptd.AtaFlags |= AtaFlags.ExtendedCommand; aptd.AtaFlags |= AtaFlags.ExtendedCommand;
// Unknown if needed // Unknown if needed
aptdBuf.aptd.AtaFlags |= AtaFlags.DrdyRequired; aptd.AtaFlags |= AtaFlags.DrdyRequired;
uint k = 0; uint k = 0;
int error = 0; int error = 0;
Array.Copy(buffer, 0, aptdBuf.dataBuffer, 0, buffer.Length); Marshal.Copy(buffer, 0, aptd.DataBuffer, buffer.Length);
DateTime start = DateTime.Now; DateTime start = DateTime.Now;
sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThrough, ref aptdBuf, sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
(uint)Marshal.SizeOf(aptdBuf), ref aptdBuf, (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
(uint)Marshal.SizeOf(aptdBuf), ref k, IntPtr.Zero); IntPtr.Zero);
DateTime end = DateTime.Now; DateTime end = DateTime.Now;
if(sense) if(sense)
error = Marshal.GetLastWin32Error(); error = Marshal.GetLastWin32Error();
Array.Copy(aptdBuf.dataBuffer, 0, buffer, 0, buffer.Length); Marshal.Copy(aptd.DataBuffer, buffer, 0, buffer.Length);
duration = (end - start).TotalMilliseconds; duration = (end - start).TotalMilliseconds;
errorRegisters.SectorCount = (ushort)((aptdBuf.aptd.PreviousTaskFile.SectorCount << 8) + errorRegisters.SectorCount = (ushort)((aptd.PreviousTaskFile.SectorCount << 8) +
aptdBuf.aptd.CurrentTaskFile.SectorCount); aptd.CurrentTaskFile.SectorCount);
errorRegisters.LbaLowPrevious = aptdBuf.aptd.PreviousTaskFile.SectorNumber; errorRegisters.LbaLowPrevious = aptd.PreviousTaskFile.SectorNumber;
errorRegisters.LbaMidPrevious = aptdBuf.aptd.PreviousTaskFile.CylinderLow; errorRegisters.LbaMidPrevious = aptd.PreviousTaskFile.CylinderLow;
errorRegisters.LbaHighPrevious = aptdBuf.aptd.PreviousTaskFile.CylinderHigh; errorRegisters.LbaHighPrevious = aptd.PreviousTaskFile.CylinderHigh;
errorRegisters.LbaLowCurrent = aptdBuf.aptd.CurrentTaskFile.SectorNumber; errorRegisters.LbaLowCurrent = aptd.CurrentTaskFile.SectorNumber;
errorRegisters.LbaMidCurrent = aptdBuf.aptd.CurrentTaskFile.CylinderLow; errorRegisters.LbaMidCurrent = aptd.CurrentTaskFile.CylinderLow;
errorRegisters.LbaHighCurrent = aptdBuf.aptd.CurrentTaskFile.CylinderHigh; errorRegisters.LbaHighCurrent = aptd.CurrentTaskFile.CylinderHigh;
errorRegisters.DeviceHead = aptdBuf.aptd.CurrentTaskFile.DeviceHead; errorRegisters.DeviceHead = aptd.CurrentTaskFile.DeviceHead;
errorRegisters.Error = aptdBuf.aptd.CurrentTaskFile.Error; errorRegisters.Error = aptd.CurrentTaskFile.Error;
errorRegisters.Status = aptdBuf.aptd.CurrentTaskFile.Status; errorRegisters.Status = aptd.CurrentTaskFile.Status;
sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0; sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0;
Marshal.FreeHGlobal(aptd.DataBuffer);
return error; return error;
} }

View File

@@ -58,8 +58,8 @@ namespace Aaru.Devices.Windows
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]
internal static extern bool DeviceIoControlAta(SafeFileHandle hDevice, WindowsIoctl ioControlCode, internal static extern bool DeviceIoControlAta(SafeFileHandle hDevice, WindowsIoctl ioControlCode,
ref AtaPassThroughExBuffer inBuffer, uint nInBufferSize, ref AtaPassThroughDirect inBuffer, uint nInBufferSize,
ref AtaPassThroughExBuffer outBuffer, uint nOutBufferSize, ref AtaPassThroughDirect outBuffer, uint nOutBufferSize,
ref uint pBytesReturned, IntPtr overlapped); ref uint pBytesReturned, IntPtr overlapped);
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)] [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]

View File

@@ -68,7 +68,7 @@ namespace Aaru.Devices.Windows
} }
[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] [StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
internal struct AtaPassThroughEx internal struct AtaPassThroughDirect
{ {
/// <summary>Length in bytes of this structure</summary> /// <summary>Length in bytes of this structure</summary>
public ushort Length; public ushort Length;
@@ -98,8 +98,8 @@ namespace Aaru.Devices.Windows
/// <summary>Reserved</summary> /// <summary>Reserved</summary>
public uint ReservedAsUlong; public uint ReservedAsUlong;
/// <summary>Pointer to data buffer relative to start of this structure</summary> /// <summary>Pointer to data buffer</summary>
public IntPtr DataBufferOffset; public IntPtr DataBuffer;
/// <summary>Previous ATA registers, for LBA48</summary> /// <summary>Previous ATA registers, for LBA48</summary>
public AtaTaskFile PreviousTaskFile; public AtaTaskFile PreviousTaskFile;
@@ -108,16 +108,6 @@ namespace Aaru.Devices.Windows
public AtaTaskFile CurrentTaskFile; public AtaTaskFile CurrentTaskFile;
} }
[StructLayout(LayoutKind.Sequential), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
internal struct AtaPassThroughExBuffer
{
public AtaPassThroughEx aptd;
public uint filler;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64 * 512)]
public byte[] dataBuffer;
}
[StructLayout(LayoutKind.Explicit), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] [StructLayout(LayoutKind.Explicit), SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
internal struct AtaTaskFile internal struct AtaTaskFile
{ {