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

View File

@@ -58,8 +58,8 @@ namespace Aaru.Devices.Windows
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]
internal static extern bool DeviceIoControlAta(SafeFileHandle hDevice, WindowsIoctl ioControlCode,
ref AtaPassThroughExBuffer inBuffer, uint nInBufferSize,
ref AtaPassThroughExBuffer outBuffer, uint nOutBufferSize,
ref AtaPassThroughDirect inBuffer, uint nInBufferSize,
ref AtaPassThroughDirect outBuffer, uint nOutBufferSize,
ref uint pBytesReturned, IntPtr overlapped);
[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")]
internal struct AtaPassThroughEx
internal struct AtaPassThroughDirect
{
/// <summary>Length in bytes of this structure</summary>
public ushort Length;
@@ -98,8 +98,8 @@ namespace Aaru.Devices.Windows
/// <summary>Reserved</summary>
public uint ReservedAsUlong;
/// <summary>Pointer to data buffer relative to start of this structure</summary>
public IntPtr DataBufferOffset;
/// <summary>Pointer to data buffer</summary>
public IntPtr DataBuffer;
/// <summary>Previous ATA registers, for LBA48</summary>
public AtaTaskFile PreviousTaskFile;
@@ -108,16 +108,6 @@ namespace Aaru.Devices.Windows
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")]
internal struct AtaTaskFile
{