On Linux use direct SG_IO.

This commit is contained in:
2018-04-02 23:10:13 +01:00
parent 2201c2b98d
commit 2bde9bf1b8

View File

@@ -56,7 +56,8 @@ namespace DiscImageChef.Devices.Linux
/// <c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer" /> contains SCSI /// <c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer" /> contains SCSI
/// sense /// sense
/// </param> /// </param>
internal static int SendScsiCommand(int fd, byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, internal static int SendScsiCommand(int fd, byte[] cdb, ref byte[] buffer,
out byte[] senseBuffer, uint timeout,
ScsiIoctlDirection direction, out double duration, out bool sense) ScsiIoctlDirection direction, out double duration, out bool sense)
{ {
senseBuffer = null; senseBuffer = null;
@@ -78,6 +79,7 @@ namespace DiscImageChef.Devices.Linux
ioHdr.cmdp = Marshal.AllocHGlobal(cdb.Length); ioHdr.cmdp = Marshal.AllocHGlobal(cdb.Length);
ioHdr.sbp = Marshal.AllocHGlobal(senseBuffer.Length); ioHdr.sbp = Marshal.AllocHGlobal(senseBuffer.Length);
ioHdr.timeout = timeout * 1000; ioHdr.timeout = timeout * 1000;
ioHdr.flags = (uint)SgFlags.DirectIo;
Marshal.Copy(buffer, 0, ioHdr.dxferp, buffer.Length); Marshal.Copy(buffer, 0, ioHdr.dxferp, buffer.Length);
Marshal.Copy(cdb, 0, ioHdr.cmdp, cdb.Length); Marshal.Copy(cdb, 0, ioHdr.cmdp, cdb.Length);
@@ -141,9 +143,11 @@ namespace DiscImageChef.Devices.Linux
/// <param name="protocol">ATA protocol to use</param> /// <param name="protocol">ATA protocol to use</param>
/// <param name="transferRegister">Which register contains the transfer count</param> /// <param name="transferRegister">Which register contains the transfer count</param>
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param> /// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
internal static int SendAtaCommand(int fd, AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters, internal static int SendAtaCommand(int fd, AtaRegistersChs registers,
out AtaErrorRegistersChs errorRegisters,
AtaProtocol protocol, AtaTransferRegister transferRegister, AtaProtocol protocol, AtaTransferRegister transferRegister,
ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, ref byte[] buffer, uint timeout, bool transferBlocks,
out double duration,
out bool sense) out bool sense)
{ {
duration = 0; duration = 0;
@@ -183,7 +187,8 @@ namespace DiscImageChef.Devices.Linux
cdb[13] = registers.DeviceHead; cdb[13] = registers.DeviceHead;
cdb[14] = registers.Command; cdb[14] = registers.Command;
int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout, int error = SendScsiCommand(fd, cdb, ref buffer,
out byte[] senseBuffer, timeout,
AtaProtocolToScsiDirection(protocol), out duration, out sense); AtaProtocolToScsiDirection(protocol), out duration, out sense);
if(senseBuffer.Length < 22 || senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) return error; if(senseBuffer.Length < 22 || senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) return error;
@@ -218,8 +223,10 @@ namespace DiscImageChef.Devices.Linux
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param> /// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
internal static int SendAtaCommand(int fd, AtaRegistersLba28 registers, internal static int SendAtaCommand(int fd, AtaRegistersLba28 registers,
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, AtaTransferRegister transferRegister, ref byte[] buffer,
bool transferBlocks, out double duration, out bool sense) uint timeout,
bool transferBlocks, out double duration,
out bool sense)
{ {
duration = 0; duration = 0;
sense = false; sense = false;
@@ -258,7 +265,8 @@ namespace DiscImageChef.Devices.Linux
cdb[13] = registers.DeviceHead; cdb[13] = registers.DeviceHead;
cdb[14] = registers.Command; cdb[14] = registers.Command;
int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout, int error = SendScsiCommand(fd, cdb, ref buffer,
out byte[] senseBuffer, timeout,
AtaProtocolToScsiDirection(protocol), out duration, out sense); AtaProtocolToScsiDirection(protocol), out duration, out sense);
if(senseBuffer.Length < 22 || senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) return error; if(senseBuffer.Length < 22 || senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) return error;
@@ -293,8 +301,10 @@ namespace DiscImageChef.Devices.Linux
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param> /// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
internal static int SendAtaCommand(int fd, AtaRegistersLba48 registers, internal static int SendAtaCommand(int fd, AtaRegistersLba48 registers,
out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol, out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol,
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, AtaTransferRegister transferRegister, ref byte[] buffer,
bool transferBlocks, out double duration, out bool sense) uint timeout,
bool transferBlocks, out double duration,
out bool sense)
{ {
duration = 0; duration = 0;
sense = false; sense = false;
@@ -339,7 +349,8 @@ namespace DiscImageChef.Devices.Linux
cdb[13] = registers.DeviceHead; cdb[13] = registers.DeviceHead;
cdb[14] = registers.Command; cdb[14] = registers.Command;
int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout, int error = SendScsiCommand(fd, cdb, ref buffer,
out byte[] senseBuffer, timeout,
AtaProtocolToScsiDirection(protocol), out duration, out sense); AtaProtocolToScsiDirection(protocol), out duration, out sense);
if(senseBuffer.Length < 22 || senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) return error; if(senseBuffer.Length < 22 || senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C) return error;
@@ -377,9 +388,12 @@ namespace DiscImageChef.Devices.Linux
/// <param name="argument">Command argument</param> /// <param name="argument">Command argument</param>
/// <param name="response">Response registers</param> /// <param name="response">Response registers</param>
/// <param name="blockSize">Size of block in bytes</param> /// <param name="blockSize">Size of block in bytes</param>
internal static int SendMmcCommand(int fd, MmcCommands command, bool write, bool isApplication, MmcFlags flags, internal static int SendMmcCommand(int fd, MmcCommands command, bool write,
uint argument, uint blockSize, uint blocks, ref byte[] buffer, bool isApplication, MmcFlags flags,
out uint[] response, out double duration, out bool sense, uint timeout = 0) uint argument, uint blockSize, uint blocks,
ref byte[] buffer,
out uint[] response, out double duration, out bool sense,
uint timeout = 0)
{ {
response = null; response = null;
duration = 0; duration = 0;
@@ -403,6 +417,7 @@ namespace DiscImageChef.Devices.Linux
ioCmd.data_timeout_ns = timeout * 1000000000; ioCmd.data_timeout_ns = timeout * 1000000000;
ioCmd.cmd_timeout_ms = timeout * 1000; ioCmd.cmd_timeout_ms = timeout * 1000;
} }
ioCmd.data_ptr = (ulong)bufPtr; ioCmd.data_ptr = (ulong)bufPtr;
Marshal.Copy(buffer, 0, bufPtr, buffer.Length); Marshal.Copy(buffer, 0, bufPtr, buffer.Length);