diff --git a/DiscImageChef.Devices/ChangeLog b/DiscImageChef.Devices/ChangeLog index d291e90f1..66950841c 100644 --- a/DiscImageChef.Devices/ChangeLog +++ b/DiscImageChef.Devices/ChangeLog @@ -1,3 +1,18 @@ +2015-10-15 Natalia Portillo + + * Device/AtaCommands.cs: + * Device/ScsiCommands.cs: + * Device/AtapiCommands.cs: + Added duration debug printfs. + + * Enums.cs: + Corrected device<->host direction. + + * Linux/Command.cs: + Corrected device<->host direction. + Changed to workaround how ATA Pass-Through is really + implemented in Linux. + 2015-10-14 Natalia Portillo * Device/Commands.cs: diff --git a/DiscImageChef.Devices/Device/AtaCommands.cs b/DiscImageChef.Devices/Device/AtaCommands.cs index 4a5a26b29..c12817444 100644 --- a/DiscImageChef.Devices/Device/AtaCommands.cs +++ b/DiscImageChef.Devices/Device/AtaCommands.cs @@ -93,10 +93,14 @@ namespace DiscImageChef.Devices registers.command = (byte)Enums.AtaCommands.IdentifyDevice; - lastError = SendAtaCommand(registers, out statusRegisters, Enums.AtaProtocol.PioOut, Enums.AtaTransferRegister.NoTransfer, + lastError = SendAtaCommand(registers, out statusRegisters, Enums.AtaProtocol.PioIn, Enums.AtaTransferRegister.SectorCount, ref buffer, timeout, false, out duration, out sense); error = lastError != 0; + #if DEBUG + Console.WriteLine("ATA IDENTIFY DEVICE took {0} ms.", duration); + #endif + return sense; } } diff --git a/DiscImageChef.Devices/Device/AtapiCommands.cs b/DiscImageChef.Devices/Device/AtapiCommands.cs index dd57328ee..2e98f0820 100644 --- a/DiscImageChef.Devices/Device/AtapiCommands.cs +++ b/DiscImageChef.Devices/Device/AtapiCommands.cs @@ -97,6 +97,10 @@ namespace DiscImageChef.Devices ref buffer, timeout, false, out duration, out sense); error = lastError != 0; + #if DEBUG + Console.WriteLine("ATA IDENTIFY PACKET DEVICE took {0} ms.", duration); + #endif + return sense; } } diff --git a/DiscImageChef.Devices/Device/ScsiCommands.cs b/DiscImageChef.Devices/Device/ScsiCommands.cs index bb24e9d6a..817cf2b99 100644 --- a/DiscImageChef.Devices/Device/ScsiCommands.cs +++ b/DiscImageChef.Devices/Device/ScsiCommands.cs @@ -107,6 +107,10 @@ namespace DiscImageChef.Devices lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, Enums.ScsiDirection.In, out duration, out sense); error = lastError != 0; + #if DEBUG + Console.WriteLine("SCSI INQUIRY took {0} ms.", duration); + #endif + return sense; } @@ -180,6 +184,10 @@ namespace DiscImageChef.Devices lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, Enums.ScsiDirection.In, out duration, out sense); error = lastError != 0; + #if DEBUG + Console.WriteLine("SCSI INQUIRY took {0} ms.", duration); + #endif + return sense; } } diff --git a/DiscImageChef.Devices/Enums.cs b/DiscImageChef.Devices/Enums.cs index 712a794c5..492e81d38 100644 --- a/DiscImageChef.Devices/Enums.cs +++ b/DiscImageChef.Devices/Enums.cs @@ -2414,11 +2414,11 @@ namespace DiscImageChef.Devices /// NonData = 3, /// - /// Requests a host->device transfer using PIO + /// Requests a device->host transfer using PIO /// PioIn = 4, /// - /// Requests a device->host transfer using PIO + /// Requests a host->device transfer using PIO /// PioOut = 5, /// @@ -2438,11 +2438,11 @@ namespace DiscImageChef.Devices /// DeviceReset = 9, /// - /// Requests a host->device transfer using UltraDMA + /// Requests a device->host transfer using UltraDMA /// UDmaIn = 10, /// - /// Requests a device->host transfer using UltraDMA + /// Requests a host->device transfer using UltraDMA /// UDmaOut = 11, /// diff --git a/DiscImageChef.Devices/Linux/Command.cs b/DiscImageChef.Devices/Linux/Command.cs index e06d54a11..3b3aabaaa 100644 --- a/DiscImageChef.Devices/Linux/Command.cs +++ b/DiscImageChef.Devices/Linux/Command.cs @@ -112,10 +112,10 @@ namespace DiscImageChef.Devices.Linux return ScsiIoctlDirection.None; case Enums.AtaProtocol.PioIn: case Enums.AtaProtocol.UDmaIn: - return ScsiIoctlDirection.Out; + return ScsiIoctlDirection.In; case Enums.AtaProtocol.PioOut: case Enums.AtaProtocol.UDmaOut: - return ScsiIoctlDirection.In; + return ScsiIoctlDirection.Out; default: return ScsiIoctlDirection.Unspecified; } @@ -133,8 +133,8 @@ namespace DiscImageChef.Devices.Linux if (buffer == null) return -1; - byte[] cdb = new byte[12]; - cdb[0] = (byte)Enums.ScsiCommands.AtaPassThrough; + byte[] cdb = new byte[16]; + cdb[0] = (byte)Enums.ScsiCommands.AtaPassThrough16; cdb[1] = (byte)(((byte)protocol << 1) & 0x1E); if (transferRegister != Enums.AtaTransferRegister.NoTransfer && protocol != Enums.AtaProtocol.NonData) @@ -156,38 +156,32 @@ namespace DiscImageChef.Devices.Linux cdb[2] |= (byte)((int)transferRegister & 0x03); } - cdb[3] = registers.feature; - cdb[4] = registers.sectorCount; - cdb[5] = registers.sector; - cdb[6] = registers.cylinderHigh; - cdb[7] = registers.cylinderLow; - cdb[8] = registers.deviceHead; - cdb[9] = registers.command; + cdb[2] |= 0x20; + + cdb[4] = registers.feature; + cdb[6] = registers.sectorCount; + cdb[8] = registers.sector; + cdb[10] = registers.cylinderLow; + cdb[12] = registers.cylinderHigh; + cdb[13] = registers.deviceHead; + cdb[14] = registers.command; byte[] senseBuffer; int error = SendScsiCommand(fd, cdb, ref buffer, out senseBuffer, timeout, AtaProtocolToScsiDirection(protocol), out duration, out sense); - // Now get error registers - byte[] returnCdb = new byte[12]; - returnCdb[0] = (byte)Enums.ScsiCommands.AtaPassThrough; - returnCdb[1] = (byte)(((byte)Enums.AtaProtocol.ReturnResponse << 1) & 0x1E); - byte[] returnBuffer = new byte[14]; - bool returnSense; - double returnDuration; - - SendScsiCommand(fd, returnCdb, ref returnBuffer, out senseBuffer, timeout, ScsiIoctlDirection.In, out returnDuration, out returnSense); - if (returnBuffer[0] != 0x09 && returnBuffer[1] != 0x0C) + if (senseBuffer.Length < 22 || (senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C)) return error; - errorRegisters.error = returnBuffer[3]; - errorRegisters.sectorCount = returnBuffer[5]; - errorRegisters.sector = returnBuffer[7]; - errorRegisters.cylinderHigh = returnBuffer[9]; - errorRegisters.cylinderLow = returnBuffer[11]; - errorRegisters.deviceHead = returnBuffer[12]; - errorRegisters.status = returnBuffer[13]; + errorRegisters.error = senseBuffer[11]; - sense |= error != 0; + errorRegisters.sectorCount = senseBuffer[13]; + errorRegisters.sector = senseBuffer[15]; + errorRegisters.cylinderLow = senseBuffer[17]; + errorRegisters.cylinderHigh = senseBuffer[19]; + errorRegisters.deviceHead = senseBuffer[20]; + errorRegisters.status = senseBuffer[21]; + + sense = errorRegisters.error != 0 || (errorRegisters.status & 0xA5) != 0; return error; } @@ -204,8 +198,8 @@ namespace DiscImageChef.Devices.Linux if (buffer == null) return -1; - byte[] cdb = new byte[12]; - cdb[0] = (byte)Enums.ScsiCommands.AtaPassThrough; + byte[] cdb = new byte[16]; + cdb[0] = (byte)Enums.ScsiCommands.AtaPassThrough16; cdb[1] = (byte)(((byte)protocol << 1) & 0x1E); if (transferRegister != Enums.AtaTransferRegister.NoTransfer && protocol != Enums.AtaProtocol.NonData) @@ -227,38 +221,32 @@ namespace DiscImageChef.Devices.Linux cdb[2] |= (byte)((int)transferRegister & 0x03); } - cdb[3] = registers.feature; - cdb[4] = registers.sectorCount; - cdb[5] = registers.lbaLow; - cdb[6] = registers.lbaMid; - cdb[7] = registers.lbaHigh; - cdb[8] = registers.deviceHead; - cdb[9] = registers.command; + cdb[2] |= 0x20; + + cdb[4] = registers.feature; + cdb[6] = registers.sectorCount; + cdb[8] = registers.lbaLow; + cdb[10] = registers.lbaMid; + cdb[12] = registers.lbaHigh; + cdb[13] = registers.deviceHead; + cdb[14] = registers.command; byte[] senseBuffer; int error = SendScsiCommand(fd, cdb, ref buffer, out senseBuffer, timeout, AtaProtocolToScsiDirection(protocol), out duration, out sense); - // Now get error registers - byte[] returnCdb = new byte[12]; - returnCdb[0] = (byte)Enums.ScsiCommands.AtaPassThrough; - returnCdb[1] = (byte)(((byte)Enums.AtaProtocol.ReturnResponse << 1) & 0x1E); - byte[] returnBuffer = new byte[14]; - bool returnSense; - double returnDuration; - - SendScsiCommand(fd, returnCdb, ref returnBuffer, out senseBuffer, timeout, ScsiIoctlDirection.In, out returnDuration, out returnSense); - if (returnBuffer[0] != 0x09 && returnBuffer[1] != 0x0C) + if (senseBuffer.Length < 22 || (senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C)) return error; - errorRegisters.error = returnBuffer[3]; - errorRegisters.sectorCount = returnBuffer[5]; - errorRegisters.lbaLow = returnBuffer[7]; - errorRegisters.lbaMid = returnBuffer[9]; - errorRegisters.lbaHigh = returnBuffer[11]; - errorRegisters.deviceHead = returnBuffer[12]; - errorRegisters.status = returnBuffer[13]; + errorRegisters.error = senseBuffer[11]; - sense |= error != 0; + errorRegisters.sectorCount = senseBuffer[13]; + errorRegisters.lbaLow = senseBuffer[15]; + errorRegisters.lbaMid = senseBuffer[17]; + errorRegisters.lbaHigh = senseBuffer[19]; + errorRegisters.deviceHead = senseBuffer[20]; + errorRegisters.status = senseBuffer[21]; + + sense = errorRegisters.error != 0 || (errorRegisters.status & 0xA5) != 0; return error; } @@ -299,6 +287,8 @@ namespace DiscImageChef.Devices.Linux cdb[2] |= (byte)((int)transferRegister & 0x03); } + cdb[2] |= 0x20; + cdb[3] = (byte)((registers.feature & 0xFF00) >> 8); cdb[4] = (byte)(registers.feature & 0xFF); cdb[5] = (byte)((registers.sectorCount & 0xFF00) >> 8); @@ -315,26 +305,19 @@ namespace DiscImageChef.Devices.Linux byte[] senseBuffer; int error = SendScsiCommand(fd, cdb, ref buffer, out senseBuffer, timeout, AtaProtocolToScsiDirection(protocol), out duration, out sense); - // Now get error registers - byte[] returnCdb = new byte[16]; - returnCdb[0] = (byte)Enums.ScsiCommands.AtaPassThrough16; - returnCdb[1] = (byte)(((byte)Enums.AtaProtocol.ReturnResponse << 1) & 0x1E); - byte[] returnBuffer = new byte[14]; - bool returnSense; - double returnDuration; - - SendScsiCommand(fd, returnCdb, ref returnBuffer, out senseBuffer, timeout, ScsiIoctlDirection.In, out returnDuration, out returnSense); - if (returnBuffer[0] != 0x09 && returnBuffer[1] != 0x0C) + if (senseBuffer.Length < 22 || (senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C)) return error; - errorRegisters.error = returnBuffer[3]; + errorRegisters.error = senseBuffer[11]; - errorRegisters.sectorCount = (ushort)((returnBuffer[4] << 8) + returnBuffer[5]); - errorRegisters.lbaLow = (ushort)((returnBuffer[6] << 8) + returnBuffer[7]); - errorRegisters.lbaMid = (ushort)((returnBuffer[8] << 8) + returnBuffer[9]); - errorRegisters.lbaHigh = (ushort)((returnBuffer[10] << 8) + returnBuffer[11]); - errorRegisters.deviceHead = returnBuffer[12]; - errorRegisters.status = returnBuffer[13]; + errorRegisters.sectorCount = (ushort)((senseBuffer[12] << 8) + senseBuffer[13]); + errorRegisters.lbaLow = (ushort)((senseBuffer[14] << 8) + senseBuffer[15]); + errorRegisters.lbaMid = (ushort)((senseBuffer[16] << 8) + senseBuffer[17]); + errorRegisters.lbaHigh = (ushort)((senseBuffer[18] << 8) + senseBuffer[19]); + errorRegisters.deviceHead = senseBuffer[20]; + errorRegisters.status = senseBuffer[21]; + + sense = errorRegisters.error != 0 || (errorRegisters.status & 0xA5) != 0; sense |= error != 0; diff --git a/DiscImageChef/ChangeLog b/DiscImageChef/ChangeLog index f2c36e320..7ebdf448c 100644 --- a/DiscImageChef/ChangeLog +++ b/DiscImageChef/ChangeLog @@ -1,3 +1,8 @@ +2015-10-15 Natalia Portillo + + * Commands/DeviceInfo.cs: + Added ATA and ATAPI identify commands. + 2015-10-13 Natalia Portillo * Main.cs: diff --git a/DiscImageChef/Commands/DeviceInfo.cs b/DiscImageChef/Commands/DeviceInfo.cs index 67ca46f24..c5982ef0d 100644 --- a/DiscImageChef/Commands/DeviceInfo.cs +++ b/DiscImageChef/Commands/DeviceInfo.cs @@ -84,6 +84,71 @@ namespace DiscImageChef.Commands Console.WriteLine("SCSI OK"); Console.WriteLine("{0}", Decoders.SCSI.PrettifySCSIInquiry(inqBuf)); + + Structs.AtaErrorRegistersCHS errorRegisters; + + byte[] ataBuf; + sense = dev.AtaIdentify(out ataBuf, out errorRegisters); + + FileStream fs; + + if (sense) + { + + if ((errorRegisters.status & 0x01) == 0x01 + && (errorRegisters.error & 0x04) == 0x04 + && errorRegisters.cylinderHigh == 0xEB + && errorRegisters.cylinderLow == 0x14) + { + Console.WriteLine("ATA error, but ATAPI signature detected."); + sense = dev.AtapiIdentify(out ataBuf, out errorRegisters); + + if (sense) + { + Console.WriteLine("ATAPI error"); + + #if DEBUG + Console.WriteLine("STATUS = 0x{0:X2}", errorRegisters.status); + Console.WriteLine("ERROR = 0x{0:X2}", errorRegisters.error); + Console.WriteLine("NSECTOR = 0x{0:X2}", errorRegisters.sectorCount); + Console.WriteLine("SECTOR = 0x{0:X2}", errorRegisters.sector); + Console.WriteLine("CYLHIGH = 0x{0:X2}", errorRegisters.cylinderHigh); + Console.WriteLine("CYLLOW = 0x{0:X2}", errorRegisters.cylinderLow); + Console.WriteLine("DEVICE = 0x{0:X2}", errorRegisters.deviceHead); + Console.WriteLine("COMMAND = 0x{0:X2}", errorRegisters.command); + Console.WriteLine("Error code = {0}", dev.LastError); + #endif + } + else + { + fs = File.Open("atapi_identify.bin", FileMode.OpenOrCreate); + fs.Write(ataBuf, 0, ataBuf.Length); + } + } + else + { + Console.WriteLine("ATA error"); + + #if DEBUG + Console.WriteLine("STATUS = 0x{0:X2}", errorRegisters.status); + Console.WriteLine("ERROR = 0x{0:X2}", errorRegisters.error); + Console.WriteLine("NSECTOR = 0x{0:X2}", errorRegisters.sectorCount); + Console.WriteLine("SECTOR = 0x{0:X2}", errorRegisters.sector); + Console.WriteLine("CYLHIGH = 0x{0:X2}", errorRegisters.cylinderHigh); + Console.WriteLine("CYLLOW = 0x{0:X2}", errorRegisters.cylinderLow); + Console.WriteLine("DEVICE = 0x{0:X2}", errorRegisters.deviceHead); + Console.WriteLine("COMMAND = 0x{0:X2}", errorRegisters.command); + Console.WriteLine("Error code = {0}", dev.LastError); + #endif + } + } + else + { + Console.WriteLine("ATA OK"); + + fs = File.Open("ata_identify.bin", FileMode.OpenOrCreate); + fs.Write(ataBuf, 0, ataBuf.Length); + } } } }