diff --git a/DiscImageChef.Devices/ChangeLog b/DiscImageChef.Devices/ChangeLog index b71da7a55..f0189ceb2 100644 --- a/DiscImageChef.Devices/ChangeLog +++ b/DiscImageChef.Devices/ChangeLog @@ -1,3 +1,9 @@ +2015-10-24 Natalia Portillo + + * Enums.cs: + * Device/ScsiCommands.cs: + Added SCSI MODE SENSE(6) and MODE SENSE(10) commands. + 2015-10-24 Natalia Portillo * Device/ScsiCommands.cs: diff --git a/DiscImageChef.Devices/Device/ScsiCommands.cs b/DiscImageChef.Devices/Device/ScsiCommands.cs index b1062959e..a6c906b05 100644 --- a/DiscImageChef.Devices/Device/ScsiCommands.cs +++ b/DiscImageChef.Devices/Device/ScsiCommands.cs @@ -209,6 +209,167 @@ namespace DiscImageChef.Devices return sense; } + + /// + /// Sends the SCSI MODE SENSE(6) command to the device as introduced in SCSI-1 + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ModeSense(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ModeSense6(out buffer, out senseBuffer, false, ScsiModeSensePageControl.Current, 0, 0, timeout, out duration); + } + + /// + /// Sends the SCSI MODE SENSE(6) command to the device as introduced in SCSI-2 + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// If set to true device MUST not return any block descriptor. + /// Page control. + /// Page code. + public bool ModeSense6(out byte[] buffer, out byte[] senseBuffer, bool DBD, ScsiModeSensePageControl pageControl, byte pageCode, uint timeout, out double duration) + { + return ModeSense6(out buffer, out senseBuffer, DBD, pageControl, pageCode, 0, timeout, out duration); + } + + /// + /// Sends the SCSI MODE SENSE(6) command to the device as introduced in SCSI-3 SPC-3 + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// If set to true device MUST not return any block descriptor. + /// Page control. + /// Page code. + /// Sub-page code. + public bool ModeSense6(out byte[] buffer, out byte[] senseBuffer, bool DBD, ScsiModeSensePageControl pageControl, byte pageCode, byte subPageCode, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[6]; + buffer = new byte[4]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ModeSense; + if (DBD) + cdb[1] = 0x08; + cdb[2] |= (byte)pageControl; + cdb[2] |= (byte)(pageCode & 0x3F); + cdb[3] = subPageCode; + cdb[4] = (byte)buffer.Length; + cdb[5] = 0; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + if (sense) + return true; + + byte modeLength = (byte)(buffer[0] + 1); + buffer = new byte[modeLength]; + cdb[4] = (byte)buffer.Length; + senseBuffer = new byte[32]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "MODE SENSE(6) took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SCSI MODE SENSE(10) command to the device as introduced in SCSI-2 + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// If set to true device MUST not return any block descriptor. + /// Page control. + /// Page code. + public bool ModeSense10(out byte[] buffer, out byte[] senseBuffer, bool DBD, ScsiModeSensePageControl pageControl, byte pageCode, uint timeout, out double duration) + { + return ModeSense10(out buffer, out senseBuffer, false, DBD, pageControl, pageCode, 0, timeout, out duration); + } + + /// + /// Sends the SCSI MODE SENSE(10) command to the device as introduced in SCSI-3 SPC-2 + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// If set to true device MUST not return any block descriptor. + /// Page control. + /// Page code. + /// If set means 64-bit LBAs are accepted by the caller. + public bool ModeSense10(out byte[] buffer, out byte[] senseBuffer, bool LLBAA, bool DBD, ScsiModeSensePageControl pageControl, byte pageCode, uint timeout, out double duration) + { + return ModeSense10(out buffer, out senseBuffer, LLBAA, DBD, pageControl, pageCode, 0, timeout, out duration); + } + + /// + /// Sends the SCSI MODE SENSE(10) command to the device as introduced in SCSI-3 SPC-3 + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// If set to true device MUST not return any block descriptor. + /// Page control. + /// Page code. + /// Sub-page code. + /// If set means 64-bit LBAs are accepted by the caller. + public bool ModeSense10(out byte[] buffer, out byte[] senseBuffer, bool LLBAA, bool DBD, ScsiModeSensePageControl pageControl, byte pageCode, byte subPageCode, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + buffer = new byte[4]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ModeSense10; + if (LLBAA) + cdb[1] |= 0x10; + if (DBD) + cdb[1] |= 0x08; + cdb[2] |= (byte)pageControl; + cdb[2] |= (byte)(pageCode & 0x3F); + cdb[3] = subPageCode; + cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(buffer.Length & 0xFF); + cdb[9] = 0; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + if (sense) + return true; + + ushort modeLength = (ushort)(((int)buffer[0] << 8) + buffer[1]); + buffer = new byte[modeLength]; + cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(buffer.Length & 0xFF); + senseBuffer = new byte[32]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "MODE SENSE(10) took {0} ms.", duration); + + return sense; + } } } diff --git a/DiscImageChef.Devices/Enums.cs b/DiscImageChef.Devices/Enums.cs index 882c29606..bd55ca516 100644 --- a/DiscImageChef.Devices/Enums.cs +++ b/DiscImageChef.Devices/Enums.cs @@ -2698,5 +2698,28 @@ namespace DiscImageChef.Devices /// ResetWritePointer = 0x04 } + + /// + /// MODE SENSE page control, mask 0xC0 + /// + public enum ScsiModeSensePageControl : byte + { + /// + /// Current values + /// + Current = 0x00, + /// + /// Changeable values + /// + Changeable = 0x40, + /// + /// Default values + /// + Default = 0x80, + /// + /// Saved values + /// + Saved = 0xC0 + } }