From 361b8977b049a60fb5ca4bd7e346bad6c3faceae Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Thu, 5 Nov 2015 06:50:02 +0000 Subject: [PATCH] * DiscImageChef.Decoders/SCSI/Modes.cs: Check for vendor pages not following page format (even if they must). * DiscImageChef.Devices/Device/Constructor.cs: Some devices (at least smsc usb-floppy) crash and reset when receiving ata over the ATA PASS-THROUGH scsi command. This will check for SCSI compliance first giving devices time to reset. * DiscImageChef.Devices/Device/ScsiCommands.cs: Some devices (smsc usb floppies) return the real command result size disregarding allocation length and generating a buffer overflow. * DiscImageChef.Devices/Enums.cs: Added some vendor commands for Plextor and HL-DT-ST devices. * DiscImageChef/Commands/DeviceInfo.cs: Mode sense should be written even if it can't be decoded. --- DiscImageChef.Decoders/ChangeLog | 6 ++ DiscImageChef.Decoders/SCSI/Modes.cs | 8 +++ DiscImageChef.Devices/ChangeLog | 16 +++++ DiscImageChef.Devices/Device/Constructor.cs | 75 ++++++++++---------- DiscImageChef.Devices/Device/ScsiCommands.cs | 14 ++-- DiscImageChef.Devices/Enums.cs | 24 ++++++- DiscImageChef/ChangeLog | 5 ++ DiscImageChef/Commands/DeviceInfo.cs | 11 +-- 8 files changed, 110 insertions(+), 49 deletions(-) diff --git a/DiscImageChef.Decoders/ChangeLog b/DiscImageChef.Decoders/ChangeLog index 7480ddad..3bd67145 100644 --- a/DiscImageChef.Decoders/ChangeLog +++ b/DiscImageChef.Decoders/ChangeLog @@ -1,3 +1,9 @@ +2015-11-05 Natalia Portillo + + * SCSI/Modes.cs: + Check for vendor pages not following page format (even if + they must). + 2015-11-02 Natalia Portillo * DiscImageChef.Decoders.csproj: diff --git a/DiscImageChef.Decoders/SCSI/Modes.cs b/DiscImageChef.Decoders/SCSI/Modes.cs index f4583162..9548f240 100644 --- a/DiscImageChef.Decoders/SCSI/Modes.cs +++ b/DiscImageChef.Decoders/SCSI/Modes.cs @@ -5904,6 +5904,10 @@ namespace DiscImageChef.Decoders.SCSI if (isSubpage) { pg.PageResponse = new byte[(modeResponse[offset + 2] << 8) + modeResponse[offset + 3] + 4]; + + if((pg.PageResponse.Length + offset) > modeResponse.Length) + return decoded; + Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length); pg.Page = (byte)(modeResponse[offset] & 0x3F); pg.Subpage = modeResponse[offset + 1]; @@ -5912,6 +5916,10 @@ namespace DiscImageChef.Decoders.SCSI else { pg.PageResponse = new byte[modeResponse[offset + 1] + 2]; + + if((pg.PageResponse.Length + offset) > modeResponse.Length) + return decoded; + Array.Copy(modeResponse, offset, pg.PageResponse, 0, pg.PageResponse.Length); pg.Page = (byte)(modeResponse[offset] & 0x3F); pg.Subpage = 0; diff --git a/DiscImageChef.Devices/ChangeLog b/DiscImageChef.Devices/ChangeLog index 7c6de823..2c1e0f06 100644 --- a/DiscImageChef.Devices/ChangeLog +++ b/DiscImageChef.Devices/ChangeLog @@ -1,3 +1,19 @@ +2015-11-05 Natalia Portillo + + * Device/Constructor.cs: + Some devices (at least smsc usb-floppy) crash and reset when + receiving ata over the ATA PASS-THROUGH scsi command. This + will check for SCSI compliance first giving devices time to + reset. + + * Device/ScsiCommands.cs: + Some devices (smsc usb floppies) return the real command + result size disregarding allocation length and generating a + buffer overflow. + + * Enums.cs: + Added some vendor commands for Plextor and HL-DT-ST devices. + 2015-11-02 Natalia Portillo * Enums.cs: diff --git a/DiscImageChef.Devices/Device/Constructor.cs b/DiscImageChef.Devices/Device/Constructor.cs index 0f7efd24..7f153e2f 100644 --- a/DiscImageChef.Devices/Device/Constructor.cs +++ b/DiscImageChef.Devices/Device/Constructor.cs @@ -95,33 +95,29 @@ namespace DiscImageChef.Devices AtaErrorRegistersCHS errorRegisters; byte[] ataBuf; - bool sense = AtaIdentify(out ataBuf, out errorRegisters); + byte[] senseBuf; + byte[] inqBuf; - if (!sense) + bool scsiSense = ScsiInquiry(out inqBuf, out senseBuf); + + if (!scsiSense) { - type = DeviceType.ATA; - Decoders.ATA.Identify.IdentifyDevice? ATAID = Decoders.ATA.Identify.Decode(ataBuf); + Decoders.SCSI.Inquiry.SCSIInquiry? Inquiry = Decoders.SCSI.Inquiry.Decode(inqBuf); - if (ATAID.HasValue) + type = DeviceType.SCSI; + bool sense = ScsiInquiry(out inqBuf, out senseBuf, 0x80); + if (!sense) + serial = Decoders.SCSI.EVPD.DecodePage80(inqBuf); + + if (Inquiry.HasValue) { - string[] separated = ATAID.Value.Model.Split(' '); + revision = StringHandlers.SpacePaddedToString(Inquiry.Value.ProductRevisionLevel); + model = StringHandlers.SpacePaddedToString(Inquiry.Value.ProductIdentification); + manufacturer = StringHandlers.SpacePaddedToString(Inquiry.Value.VendorIdentification); - if (separated.Length == 1) - model = separated[0]; - else - { - manufacturer = separated[0]; - model = separated[separated.Length - 1]; - } - - revision = ATAID.Value.FirmwareRevision; - serial = ATAID.Value.SerialNumber; - - scsiType = Decoders.SCSI.PeripheralDeviceTypes.DirectAccess; + scsiType = (Decoders.SCSI.PeripheralDeviceTypes)Inquiry.Value.PeripheralDeviceType; } - } - else - { + sense = AtapiIdentify(out ataBuf, out errorRegisters); if (!sense) @@ -132,31 +128,32 @@ namespace DiscImageChef.Devices if (ATAID.HasValue) serial = ATAID.Value.SerialNumber; } + } - byte[] senseBuf; - byte[] inqBuf; - - sense = ScsiInquiry(out inqBuf, out senseBuf); - + if (scsiSense || manufacturer == "ATA") + { + bool sense = AtaIdentify(out ataBuf, out errorRegisters); if (!sense) { - Decoders.SCSI.Inquiry.SCSIInquiry? Inquiry = Decoders.SCSI.Inquiry.Decode(inqBuf); + type = DeviceType.ATA; + Decoders.ATA.Identify.IdentifyDevice? ATAID = Decoders.ATA.Identify.Decode(ataBuf); - if (type != DeviceType.ATAPI) + if (ATAID.HasValue) { - type = DeviceType.SCSI; - sense = ScsiInquiry(out inqBuf, out senseBuf, 0x80); - if (!sense) - serial = Decoders.SCSI.EVPD.DecodePage80(inqBuf); - } + string[] separated = ATAID.Value.Model.Split(' '); - if (Inquiry.HasValue) - { - revision = StringHandlers.SpacePaddedToString(Inquiry.Value.ProductRevisionLevel); - model = StringHandlers.SpacePaddedToString(Inquiry.Value.ProductIdentification); - manufacturer = StringHandlers.SpacePaddedToString(Inquiry.Value.VendorIdentification); + if (separated.Length == 1) + model = separated[0]; + else + { + manufacturer = separated[0]; + model = separated[separated.Length - 1]; + } - scsiType = (Decoders.SCSI.PeripheralDeviceTypes)Inquiry.Value.PeripheralDeviceType; + revision = ATAID.Value.FirmwareRevision; + serial = ATAID.Value.SerialNumber; + + scsiType = Decoders.SCSI.PeripheralDeviceTypes.DirectAccess; } } } diff --git a/DiscImageChef.Devices/Device/ScsiCommands.cs b/DiscImageChef.Devices/Device/ScsiCommands.cs index a810702b..fdb01576 100644 --- a/DiscImageChef.Devices/Device/ScsiCommands.cs +++ b/DiscImageChef.Devices/Device/ScsiCommands.cs @@ -88,9 +88,9 @@ namespace DiscImageChef.Devices /// Duration in milliseconds it took for the device to execute the command. public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) { - buffer = new byte[5]; + buffer = new byte[36]; senseBuffer = new byte[32]; - byte[] cdb = { (byte)ScsiCommands.Inquiry, 0, 0, 0, 5, 0 }; + byte[] cdb = { (byte)ScsiCommands.Inquiry, 0, 0, 0, 36, 0 }; bool sense; lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); @@ -163,9 +163,9 @@ namespace DiscImageChef.Devices /// The Extended Vital Product Data public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, byte page, uint timeout, out double duration) { - buffer = new byte[5]; + buffer = new byte[36]; senseBuffer = new byte[32]; - byte[] cdb = { (byte)ScsiCommands.Inquiry, 1, page, 0, 5, 0 }; + byte[] cdb = { (byte)ScsiCommands.Inquiry, 1, page, 0, 36, 0 }; bool sense; lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); @@ -174,6 +174,10 @@ namespace DiscImageChef.Devices if (sense) return true; + // This is because INQ was returned instead of EVPD + if (buffer[1] != page) + return true; + byte pagesLength = (byte)(buffer[3] + 4); cdb = new byte[] { (byte)ScsiCommands.Inquiry, 1, page, 0, pagesLength, 0 }; @@ -336,7 +340,7 @@ namespace DiscImageChef.Devices { senseBuffer = new byte[32]; byte[] cdb = new byte[10]; - buffer = new byte[4]; + buffer = new byte[4096]; bool sense; cdb[0] = (byte)ScsiCommands.ModeSense10; diff --git a/DiscImageChef.Devices/Enums.cs b/DiscImageChef.Devices/Enums.cs index 3bd83990..264b92d3 100644 --- a/DiscImageChef.Devices/Enums.cs +++ b/DiscImageChef.Devices/Enums.cs @@ -2559,7 +2559,29 @@ namespace DiscImageChef.Devices /// Variable sized Command Description Block /// SPC-4 rev. 16 /// - VariableSizedCDB = 0x7F + VariableSizedCDB = 0x7F, + + #region Plextor vendor commands + /// + /// Sends extended commands (like SpeedRead) to Plextor drives + /// + Plextor_Extend = 0xE9, + /// + /// Resets Plextor drives + /// + Plextor_Reset = 0xEE, + /// + /// Reads drive statistics from Plextor drives EEPROM + /// + Plextor_ReadEeprom = 0xF1, + #endregion Plextor vendor commands + + #region HL-DT-ST vendor commands + /// + /// Sends debugging commands to HL-DT-ST DVD drives + /// + HlDtSt_Vendor = 0xE7 + #endregion HL-DT-ST vendor commands } #endregion SCSI Commands diff --git a/DiscImageChef/ChangeLog b/DiscImageChef/ChangeLog index f2524789..bb53d767 100644 --- a/DiscImageChef/ChangeLog +++ b/DiscImageChef/ChangeLog @@ -1,3 +1,8 @@ +2015-11-05 Natalia Portillo + + * Commands/DeviceInfo.cs: + Mode sense should be written even if it can't be decoded. + 2015-11-02 Natalia Portillo * Options.cs: diff --git a/DiscImageChef/Commands/DeviceInfo.cs b/DiscImageChef/Commands/DeviceInfo.cs index c4f9a485..1d7ea929 100644 --- a/DiscImageChef/Commands/DeviceInfo.cs +++ b/DiscImageChef/Commands/DeviceInfo.cs @@ -349,16 +349,16 @@ namespace DiscImageChef.Commands decMode = Decoders.SCSI.Modes.DecodeMode6(modeBuf, devType); } - if (decMode.HasValue) + if (!sense) { - if(!string.IsNullOrEmpty(options.OutputPrefix)) + if (!string.IsNullOrEmpty(options.OutputPrefix)) { if (!File.Exists(options.OutputPrefix + "_scsi_modesense.bin")) { try { DicConsole.DebugWriteLine("Device-Info command", "Writing SCSI MODE SENSE to {0}{1}", options.OutputPrefix, "_scsi_modesense.bin"); - outputFs = new FileStream(options.OutputPrefix +"_scsi_modesense.bin", FileMode.CreateNew); + outputFs = new FileStream(options.OutputPrefix + "_scsi_modesense.bin", FileMode.CreateNew); outputFs.Write(modeBuf, 0, modeBuf.Length); outputFs.Close(); } @@ -370,7 +370,10 @@ namespace DiscImageChef.Commands else DicConsole.ErrorWriteLine("Not overwriting file {0}{1}", options.OutputPrefix, "_scsi_modesense.bin"); } + } + if (decMode.HasValue) + { DicConsole.WriteLine(Decoders.SCSI.Modes.PrettifyModeHeader(decMode.Value.Header, devType)); if (decMode.Value.Pages != null) @@ -608,7 +611,7 @@ namespace DiscImageChef.Commands { try { - DicConsole.DebugWriteLine("Device-Info command", "Writing SCSI MODE SENSE to {0}{1}", options.OutputPrefix, "_mmc_getconfiguration.bin"); + DicConsole.DebugWriteLine("Device-Info command", "Writing MMC GET CONFIGURATION to {0}{1}", options.OutputPrefix, "_mmc_getconfiguration.bin"); outputFs = new FileStream(options.OutputPrefix +"_mmc_getconfiguration.bin", FileMode.CreateNew); outputFs.Write(confBuf, 0, confBuf.Length); outputFs.Close();