diff --git a/DiscImageChef.Devices/ChangeLog b/DiscImageChef.Devices/ChangeLog index 1abe020c..8f882b09 100644 --- a/DiscImageChef.Devices/ChangeLog +++ b/DiscImageChef.Devices/ChangeLog @@ -1,3 +1,16 @@ +2016-01-11 Natalia Portillo + + * Device/ScsiCommands.cs: + * Device/ScsiCommands/MMC.cs: + * Device/ScsiCommands/NEC.cs: + * Device/ScsiCommands/SPC.cs: + * Device/ScsiCommands/SBC.cs: + * DiscImageChef.Devices.csproj: + * Device/ScsiCommands/Plextor.cs: + * Device/ScsiCommands/Pioneer.cs: + * Device/ScsiCommands/HL-DT-ST.cs: + Separated SCSI commands by category/vendor. + 2016-01-11 Natalia Portillo * Enums.cs: diff --git a/DiscImageChef.Devices/Device/ScsiCommands.cs b/DiscImageChef.Devices/Device/ScsiCommands.cs deleted file mode 100644 index b122277c..00000000 --- a/DiscImageChef.Devices/Device/ScsiCommands.cs +++ /dev/null @@ -1,2023 +0,0 @@ -// /*************************************************************************** -// The Disc Image Chef -// ---------------------------------------------------------------------------- -// -// Filename : ScsiCommands.cs -// Version : 1.0 -// Author(s) : Natalia Portillo -// -// Component : Direct device access -// -// Revision : $Revision$ -// Last change by : $Author$ -// Date : $Date$ -// -// --[ Description ] ---------------------------------------------------------- -// -// Contains SCSI commands -// -// --[ License ] -------------------------------------------------------------- -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// ---------------------------------------------------------------------------- -// Copyright (C) 2011-2015 Claunia.com -// ****************************************************************************/ -// //$Id$ -using System; -using DiscImageChef.Console; - -namespace DiscImageChef.Devices -{ - public partial class Device - { - /// - /// Sends the SCSI INQUIRY command to the device using default device timeout. - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI INQUIRY response will be stored - /// Sense buffer. - public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer) - { - return ScsiInquiry(out buffer, out senseBuffer, Timeout); - } - - /// - /// Sends the SCSI INQUIRY command to the device using default device timeout. - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI INQUIRY response will be stored - /// Sense buffer. - /// Duration in milliseconds it took for the device to execute the command. - public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, out double duration) - { - return ScsiInquiry(out buffer, out senseBuffer, Timeout, out duration); - } - - /// - /// Sends the SCSI INQUIRY command to the device. - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI INQUIRY response will be stored - /// Sense buffer. - /// Timeout in seconds. - public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, uint timeout) - { - double duration; - return ScsiInquiry(out buffer, out senseBuffer, timeout, out duration); - } - - /// - /// Sends the SCSI INQUIRY command to the device. - /// - /// 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 ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - buffer = new byte[36]; - senseBuffer = new byte[32]; - 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); - error = lastError != 0; - - if (sense) - return true; - - byte pagesLength = (byte)(buffer[4] + 5); - - cdb = new byte[] { (byte)ScsiCommands.Inquiry, 0, 0, 0, pagesLength, 0 }; - buffer = new byte[pagesLength]; - 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", "INQUIRY took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI INQUIRY command to the device with an Extended Vital Product Data page using default device timeout. - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI INQUIRY response will be stored - /// Sense buffer. - /// The Extended Vital Product Data - public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, byte page) - { - return ScsiInquiry(out buffer, out senseBuffer, page, Timeout); - } - - /// - /// Sends the SCSI INQUIRY command to the device with an Extended Vital Product Data page using default device timeout. - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI INQUIRY response will be stored - /// Sense buffer. - /// Duration in milliseconds it took for the device to execute the command. - /// The Extended Vital Product Data - public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, byte page, out double duration) - { - return ScsiInquiry(out buffer, out senseBuffer, page, Timeout, out duration); - } - - /// - /// Sends the SCSI INQUIRY command to the device with an Extended Vital Product Data page. - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI INQUIRY response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// The Extended Vital Product Data - public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, byte page, uint timeout) - { - double duration; - return ScsiInquiry(out buffer, out senseBuffer, page, timeout, out duration); - } - - /// - /// Sends the SCSI INQUIRY command to the device with an Extended Vital Product Data page. - /// - /// 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. - /// The Extended Vital Product Data - public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, byte page, uint timeout, out double duration) - { - buffer = new byte[36]; - senseBuffer = new byte[32]; - 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); - error = lastError != 0; - - 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 }; - buffer = new byte[pagesLength]; - 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", "INQUIRY took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI TEST UNIT READY command to the device - /// - /// true, if unit is NOT ready, false otherwise. - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ScsiTestUnitReady(out byte[] senseBuffer, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = { (byte)ScsiCommands.TestUnitReady, 0, 0, 0, 0, 0 }; - bool sense; - byte[] buffer = new byte[0]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "TEST UNIT READY took {0} ms.", duration); - - 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 MODE SENSE(6) 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 MODE SENSE(6) 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 MODE SENSE(6) 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 MODE SENSE(10) 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 MODE SENSE(10) 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 MODE SENSE(10) 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[4096]; - 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] + 2); - 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; - } - - /// - /// Sends the SCSI PREVENT ALLOW MEDIUM REMOVAL command to prevent medium removal - /// - /// true if the command failed and contains the sense buffer. - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool PreventMediumRemoval(out byte[] senseBuffer, uint timeout, out double duration) - { - return PreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Prevent, timeout, out duration); - } - - /// - /// Sends the SCSI PREVENT ALLOW MEDIUM REMOVAL command to allow medium removal - /// - /// true if the command failed and contains the sense buffer. - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool AllowMediumRemoval(out byte[] senseBuffer, uint timeout, out double duration) - { - return PreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Allow, timeout, out duration); - } - - /// - /// Sends the SCSI PREVENT ALLOW MEDIUM REMOVAL command - /// - /// true if the command failed and contains the sense buffer. - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// true to prevent medium removal, false to allow it. - public bool PreventAllowMediumRemoval(out byte[] senseBuffer, bool prevent, uint timeout, out double duration) - { - if (prevent) - return PreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Prevent, timeout, out duration); - else - return PreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Allow, timeout, out duration); - } - - /// - /// Sends the SCSI PREVENT ALLOW MEDIUM REMOVAL command - /// - /// true if the command failed and contains the sense buffer. - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Prevention mode. - public bool PreventAllowMediumRemoval(out byte[] senseBuffer, ScsiPreventAllowMode preventMode, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[6]; - bool sense; - byte[] buffer = new byte[0]; - - cdb[0] = (byte)ScsiCommands.PreventAllowMediumRemoval; - cdb[4] = (byte)((byte)preventMode & 0x03); - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PREVENT ALLOW MEDIUM REMOVAL took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI GET CONFIGURATION command for all Features - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI GET CONFIGURATION response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - return GetConfiguration(out buffer, out senseBuffer, 0x0000, MmcGetConfigurationRt.All, timeout, out duration); - } - - /// - /// Sends the SCSI GET CONFIGURATION command for all Features starting with specified one - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI GET CONFIGURATION response will be stored - /// Sense buffer. - /// Feature number where the feature list should start from - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, uint timeout, out double duration) - { - return GetConfiguration(out buffer, out senseBuffer, startingFeatureNumber, MmcGetConfigurationRt.All, timeout, out duration); - } - - /// - /// Sends the SCSI GET CONFIGURATION command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI GET CONFIGURATION response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Starting Feature number. - /// Return type, . - public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, MmcGetConfigurationRt RT, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; - buffer = new byte[8]; - bool sense; - - cdb[0] = (byte)ScsiCommands.GetConfiguration; - cdb[1] = (byte)((byte)RT & 0x03); - cdb[2] = (byte)((startingFeatureNumber & 0xFF00) >> 8); - cdb[3] = (byte)(startingFeatureNumber & 0xFF); - 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 confLength = (ushort)(((int)buffer[2] << 8) + buffer[3] + 4); - buffer = new byte[confLength]; - 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", "GET CONFIGURATION took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ DISC STRUCTURE command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ DISC STRUCTURE response will be stored - /// Sense buffer. - /// Medium type for requested disc structure - /// Medium address for requested disc structure - /// Medium layer for requested disc structure - /// Timeout in seconds. - /// Which disc structure are we requesting - /// AGID used in medium copy protection - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType, uint address, byte layerNumber, MmcDiscStructureFormat format, byte AGID, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - buffer = new byte[8]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadDiscStructure; - cdb[1] = (byte)((byte)mediaType & 0x0F); - cdb[2] = (byte)((address & 0xFF000000) >> 24); - cdb[3] = (byte)((address & 0xFF0000) >> 16); - cdb[4] = (byte)((address & 0xFF00) >> 8); - cdb[5] = (byte)(address & 0xFF); - cdb[6] = layerNumber; - cdb[7] = (byte)format; - cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[9] = (byte)(buffer.Length & 0xFF); - cdb[10] = (byte)((AGID & 0x03) << 6); - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - if (sense) - return true; - - ushort strctLength = (ushort)(((int)buffer[0] << 8) + buffer[1] + 2); - buffer = new byte[strctLength]; - cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[9] = (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", "READ DISC STRUCTURE took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ CAPACITY command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ CAPACITY response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadCapacity(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - return ReadCapacity(out buffer, out senseBuffer, false, 0, false, timeout, out duration); - } - - /// - /// Sends the SCSI READ CAPACITY command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ CAPACITY response will be stored - /// Sense buffer. - /// Indicates that is relative to current medium position - /// Address where information is requested from, only valid if is set - /// If set, it is requesting partial media capacity - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadCapacity(out byte[] buffer, out byte[] senseBuffer, bool RelAddr, uint address, bool PMI, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; - buffer = new byte[8]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadCapacity; - - if (PMI) - { - cdb[8] = 0x01; - if (RelAddr) - cdb[1] = 0x01; - - cdb[2] = (byte)((address & 0xFF000000) >> 24); - cdb[3] = (byte)((address & 0xFF0000) >> 16); - cdb[4] = (byte)((address & 0xFF00) >> 8); - cdb[5] = (byte)(address & 0xFF); - } - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ CAPACITY took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ CAPACITY(16) command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ CAPACITY(16) response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadCapacity16(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - return ReadCapacity16(out buffer, out senseBuffer, 0, false, timeout, out duration); - } - - /// - /// Sends the SCSI READ CAPACITY(16) command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ CAPACITY(16) response will be stored - /// Sense buffer. - /// Address where information is requested from, only valid if is set - /// If set, it is requesting partial media capacity - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadCapacity16(out byte[] buffer, out byte[] senseBuffer, ulong address, bool PMI, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[16]; - buffer = new byte[32]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ServiceActionIn; - cdb[1] = (byte)ScsiServiceActions.ReadCapacity16; - - if (PMI) - { - cdb[14] = 0x01; - byte[] temp = BitConverter.GetBytes(address); - cdb[2] = temp[7]; - cdb[3] = temp[6]; - cdb[4] = temp[5]; - cdb[5] = temp[4]; - cdb[6] = temp[3]; - cdb[7] = temp[2]; - cdb[8] = temp[1]; - cdb[9] = temp[0]; - } - - cdb[10] = (byte)((buffer.Length & 0xFF000000) >> 24); - cdb[11] = (byte)((buffer.Length & 0xFF0000) >> 16); - cdb[12] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[13] = (byte)(buffer.Length & 0xFF); - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ CAPACITY(16) took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ MEDIA SERIAL NUMBER command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ MEDIA SERIAL NUMBER response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadMediaSerialNumber(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - buffer = new byte[4]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadSerialNumber; - cdb[1] = 0x01; - cdb[6] = (byte)((buffer.Length & 0xFF000000) >> 24); - cdb[7] = (byte)((buffer.Length & 0xFF0000) >> 16); - cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[9] = (byte)(buffer.Length & 0xFF); - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - if (sense) - return true; - - uint strctLength = (uint)(((int)buffer[0] << 24) + ((int)buffer[1] << 16) + ((int)buffer[2] << 8) + buffer[3] + 4); - cdb[6] = (byte)((buffer.Length & 0xFF000000) >> 24); - cdb[7] = (byte)((buffer.Length & 0xFF0000) >> 16); - cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[9] = (byte)(buffer.Length & 0xFF); - buffer = new byte[strctLength]; - 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", "READ MEDIA SERIAL NUMBER took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ TOC/PMA/ATIP command to get formatted TOC from disc, in MM:SS:FF format - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored - /// Sense buffer. - /// Start TOC from this track - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadToc(out byte[] buffer, out byte[] senseBuffer, byte track, uint timeout, out double duration) - { - return ReadTocPmaAtip(out buffer, out senseBuffer, true, 0, track, timeout, out duration); - } - - /// - /// Sends the SCSI READ TOC/PMA/ATIP command to get formatted TOC from disc - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored - /// Sense buffer. - /// If true, request data in MM:SS:FF units, otherwise, in blocks - /// Start TOC from this track - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadToc(out byte[] buffer, out byte[] senseBuffer, bool MSF, byte track, uint timeout, out double duration) - { - return ReadTocPmaAtip(out buffer, out senseBuffer, MSF, 0, track, timeout, out duration); - } - - /// - /// Sends the SCSI READ TOC/PMA/ATIP command to get multi-session information, in MM:SS:FF format - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadSessionInfo(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - return ReadTocPmaAtip(out buffer, out senseBuffer, true, 1, 0, timeout, out duration); - } - - /// - /// Sends the SCSI READ TOC/PMA/ATIP command to get multi-session information - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored - /// Sense buffer. - /// If true, request data in MM:SS:FF units, otherwise, in blocks - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadSessionInfo(out byte[] buffer, out byte[] senseBuffer, bool MSF, uint timeout, out double duration) - { - return ReadTocPmaAtip(out buffer, out senseBuffer, MSF, 1, 0, timeout, out duration); - } - - /// - /// Sends the SCSI READ TOC/PMA/ATIP command to get raw TOC subchannels - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored - /// Sense buffer. - /// Session which TOC to get - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadRawToc(out byte[] buffer, out byte[] senseBuffer, byte sessionNumber, uint timeout, out double duration) - { - return ReadTocPmaAtip(out buffer, out senseBuffer, true, 2, sessionNumber, timeout, out duration); - } - - /// - /// Sends the SCSI READ TOC/PMA/ATIP command to get PMA - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadPma(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - return ReadTocPmaAtip(out buffer, out senseBuffer, true, 3, 0, timeout, out duration); - } - - /// - /// Sends the SCSI READ TOC/PMA/ATIP command to get ATIP - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadAtip(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - return ReadTocPmaAtip(out buffer, out senseBuffer, true, 4, 0, timeout, out duration); - } - - /// - /// Sends the SCSI READ TOC/PMA/ATIP command to get Lead-In CD-TEXT - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadCdText(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - return ReadTocPmaAtip(out buffer, out senseBuffer, true, 5, 0, timeout, out duration); - } - - /// - /// Sends the SCSI READ TOC/PMA/ATIP command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored - /// Sense buffer. - /// If true, request data in MM:SS:FF units, otherwise, in blocks - /// What structure is requested - /// Track/Session number - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadTocPmaAtip(out byte[] buffer, out byte[] senseBuffer, bool MSF, byte format, byte trackSessionNumber, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; - byte[] tmpBuffer; - bool sense; - - if(format == 5) - tmpBuffer = new byte[32768]; - else - tmpBuffer = new byte[1024]; - - cdb[0] = (byte)ScsiCommands.ReadTocPmaAtip; - if (MSF) - cdb[1] = 0x02; - cdb[2] = (byte)(format & 0x0F); - cdb[6] = trackSessionNumber; - cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8); - cdb[8] = (byte)(tmpBuffer.Length & 0xFF); - - lastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - uint strctLength = (uint)(((int)tmpBuffer[0] << 8) + tmpBuffer[1] + 2); - buffer = new byte[strctLength]; - - if (buffer.Length <= tmpBuffer.Length) - { - Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length); - DicConsole.DebugWriteLine("SCSI Device", "READ TOC/PMA/ATIP took {0} ms.", duration); - return sense; - } - - double tmpDuration = duration; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - duration += tmpDuration; - DicConsole.DebugWriteLine("SCSI Device", "READ TOC/PMA/ATIP took {0} ms.", duration); - return sense; - } - - /// - /// Sends the SCSI READ DISC INFORMATION command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ DISC INFORMATION response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - return ReadDiscInformation(out buffer, out senseBuffer, MmcDiscInformationDataTypes.DiscInformation, timeout, out duration); - } - - /// - /// Sends the SCSI READ DISC INFORMATION command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ DISC INFORMATION response will be stored - /// Sense buffer. - /// Which disc information to read - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, MmcDiscInformationDataTypes dataType, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; - byte[] tmpBuffer = new byte[804]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadDiscInformation; - cdb[1] = (byte)dataType; - cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8); - cdb[8] = (byte)(tmpBuffer.Length & 0xFF); - - lastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - uint strctLength = (uint)(((int)tmpBuffer[0] << 8) + tmpBuffer[1] + 2); - buffer = new byte[strctLength]; - Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length); - - DicConsole.DebugWriteLine("SCSI Device", "READ DISC INFORMATION took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ (6) command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Starting block. - /// Block size in bytes. - public bool Read6(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint timeout, out double duration) - { - return Read6(out buffer, out senseBuffer, lba, blockSize, 1, timeout, out duration); - } - - /// - /// Sends the SCSI READ (6) command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Starting block. - /// Block size in bytes. - /// How many blocks to read. - public bool Read6(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, byte transferLength, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[6]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Read6; - cdb[1] = (byte)((lba & 0x1F0000) >> 16); - cdb[2] = (byte)((lba & 0xFF00) >> 8); - cdb[3] = (byte)(lba & 0xFF); - cdb[4] = transferLength; - - if(transferLength == 0) - buffer = new byte[256 * blockSize]; - else - buffer = new byte[transferLength * blockSize]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ (6) took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ (10) command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Instructs the drive how to check for protection information on the medium. - /// If set to true requested blocks shall be assigned the lowest retention priority on cache fetch/retain. - /// If set to true requested blocks MUST bu read from medium and not the cache. - /// If set to true requested blocks will be returned from non-volatile cache. If they're not present they shall be stored there. - /// Starting block. - /// Block size in bytes. - /// Group number where attributes associated with this command should be collected. - /// How many blocks to read. - /// If set to true address is relative to current position. - public bool Read10(out byte[] buffer, out byte[] senseBuffer, byte rdprotect, bool dpo, bool fua, bool fuaNv, bool relAddr, uint lba, uint blockSize, byte groupNumber, ushort transferLength, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Read10; - cdb[1] = (byte)((rdprotect & 0x07) << 5); - if(dpo) - cdb[1] += 0x10; - if(fua) - cdb[1] += 0x08; - if(fuaNv) - cdb[1] += 0x02; - if(relAddr) - cdb[1] += 0x01; - cdb[2] = (byte)((lba & 0xFF000000) >> 24); - cdb[3] = (byte)((lba & 0xFF0000) >> 16); - cdb[4] = (byte)((lba & 0xFF00) >> 8); - cdb[5] = (byte)(lba & 0xFF); - cdb[6] = (byte)(groupNumber & 0x1F); - cdb[7] = (byte)((transferLength & 0xFF00) >> 8); - cdb[8] = (byte)(transferLength & 0xFF); - - buffer = new byte[transferLength * blockSize]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ (10) took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ (12) command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Instructs the drive how to check for protection information on the medium. - /// If set to true requested blocks shall be assigned the lowest retention priority on cache fetch/retain. - /// If set to true requested blocks MUST bu read from medium and not the cache. - /// If set to true requested blocks will be returned from non-volatile cache. If they're not present they shall be stored there. - /// Starting block. - /// Block size in bytes. - /// Group number where attributes associated with this command should be collected. - /// How many blocks to read. - /// If set to true the stream playback operation should be used (MMC only). - /// If set to true address is relative to current position. - public bool Read12(out byte[] buffer, out byte[] senseBuffer, byte rdprotect, bool dpo, bool fua, bool fuaNv, bool relAddr, uint lba, uint blockSize, byte groupNumber, uint transferLength, bool streaming, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Read12; - cdb[1] = (byte)((rdprotect & 0x07) << 5); - if(dpo) - cdb[1] += 0x10; - if(fua) - cdb[1] += 0x08; - if(fuaNv) - cdb[1] += 0x02; - if(relAddr) - cdb[1] += 0x01; - cdb[2] = (byte)((lba & 0xFF000000) >> 24); - cdb[3] = (byte)((lba & 0xFF0000) >> 16); - cdb[4] = (byte)((lba & 0xFF00) >> 8); - cdb[5] = (byte)(lba & 0xFF); - cdb[6] = (byte)((transferLength & 0xFF000000) >> 24); - cdb[7] = (byte)((transferLength & 0xFF0000) >> 16); - cdb[8] = (byte)((transferLength & 0xFF00) >> 8); - cdb[9] = (byte)(transferLength & 0xFF); - cdb[10] = (byte)(groupNumber & 0x1F); - if(streaming) - cdb[10] += 0x80; - - buffer = new byte[transferLength * blockSize]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ (12) took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ (16) command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Instructs the drive how to check for protection information on the medium. - /// If set to true requested blocks shall be assigned the lowest retention priority on cache fetch/retain. - /// If set to true requested blocks MUST bu read from medium and not the cache. - /// If set to true requested blocks will be returned from non-volatile cache. If they're not present they shall be stored there. - /// Starting block. - /// Block size in bytes. - /// Group number where attributes associated with this command should be collected. - /// How many blocks to read. - /// If set to true the stream playback operation should be used (MMC only). - public bool Read16(out byte[] buffer, out byte[] senseBuffer, byte rdprotect, bool dpo, bool fua, bool fuaNv, ulong lba, uint blockSize, byte groupNumber, uint transferLength, bool streaming, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[16]; - bool sense; - byte[] lbaBytes = BitConverter.GetBytes(lba); - - cdb[0] = (byte)ScsiCommands.Read16; - cdb[1] = (byte)((rdprotect & 0x07) << 5); - if(dpo) - cdb[1] += 0x10; - if(fua) - cdb[1] += 0x08; - if(fuaNv) - cdb[1] += 0x02; - cdb[2] = lbaBytes[7]; - cdb[3] = lbaBytes[6]; - cdb[4] = lbaBytes[5]; - cdb[5] = lbaBytes[4]; - cdb[6] = lbaBytes[3]; - cdb[7] = lbaBytes[2]; - cdb[8] = lbaBytes[1]; - cdb[9] = lbaBytes[0]; - cdb[10] = (byte)((transferLength & 0xFF000000) >> 24); - cdb[11] = (byte)((transferLength & 0xFF0000) >> 16); - cdb[12] = (byte)((transferLength & 0xFF00) >> 8); - cdb[13] = (byte)(transferLength & 0xFF); - cdb[14] = (byte)(groupNumber & 0x1F); - if(streaming) - cdb[14] += 0x80; - - buffer = new byte[transferLength * blockSize]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ (16) took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ LONG (10) command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ LONG 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 ask the drive to try to correct errors in the sector. - /// LBA to read. - /// How many bytes to read. If the number is not exactly the drive's size, the command will fail and incidate a delta of the size in SENSE. - public bool ReadLong10(out byte[] buffer, out byte[] senseBuffer, bool correct, bool relAddr, uint lba, ushort transferBytes, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadLong; - if(correct) - cdb[1] += 0x02; - if(relAddr) - cdb[1] += 0x01; - cdb[2] = (byte)((lba & 0xFF000000) >> 24); - cdb[3] = (byte)((lba & 0xFF0000) >> 16); - cdb[4] = (byte)((lba & 0xFF00) >> 8); - cdb[5] = (byte)(lba & 0xFF); - cdb[7] = (byte)((transferBytes & 0xFF00) >> 8); - cdb[8] = (byte)(transferBytes & 0xFF); - - buffer = new byte[transferBytes]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ LONG (10) took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the SCSI READ LONG (16) command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the SCSI READ LONG 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 ask the drive to try to correct errors in the sector. - /// LBA to read. - /// How many bytes to read. If the number is not exactly the drive's size, the command will fail and incidate a delta of the size in SENSE. - public bool ReadLong16(out byte[] buffer, out byte[] senseBuffer, bool correct, ulong lba, uint transferBytes, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[16]; - bool sense; - byte[] lbaBytes = BitConverter.GetBytes(lba); - - cdb[0] = (byte)ScsiCommands.ServiceActionIn; - cdb[1] = (byte)ScsiServiceActions.ReadLong16; - cdb[2] = lbaBytes[7]; - cdb[3] = lbaBytes[6]; - cdb[4] = lbaBytes[5]; - cdb[5] = lbaBytes[4]; - cdb[6] = lbaBytes[3]; - cdb[7] = lbaBytes[2]; - cdb[8] = lbaBytes[1]; - cdb[9] = lbaBytes[0]; - cdb[12] = (byte)((transferBytes & 0xFF00) >> 8); - cdb[13] = (byte)(transferBytes & 0xFF); - if(correct) - cdb[14] += 0x01; - - buffer = new byte[transferBytes]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ LONG (16) took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the MMC READ CD command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the MMC READ CD response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Start block address. - /// How many blocks to read. - /// Block size. - /// Expected sector type. - /// If set to true CD-DA should be modified by mute and interpolation - /// If set to true address is relative to current position. - /// If set to true we request the sync bytes for data sectors. - /// Header codes. - /// If set to true we request the user data. - /// If set to true we request the EDC/ECC fields for data sectors. - /// C2 error options. - /// Subchannel selection. - public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength, MmcSectorTypes expectedSectorType, - bool DAP, bool relAddr, bool sync, MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField C2Error, MmcSubchannel subchannel, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadCd; - cdb[1] = (byte)((byte)expectedSectorType << 2); - if(DAP) - cdb[1] += 0x02; - if(relAddr) - cdb[1] += 0x01; - cdb[2] = (byte)((lba & 0xFF000000) >> 24); - cdb[3] = (byte)((lba & 0xFF0000) >> 16); - cdb[4] = (byte)((lba & 0xFF00) >> 8); - cdb[5] = (byte)(lba & 0xFF); - cdb[6] = (byte)((transferLength & 0xFF0000) >> 16); - cdb[7] = (byte)((transferLength & 0xFF00) >> 8); - cdb[8] = (byte)(transferLength & 0xFF); - cdb[9] = (byte)((byte)C2Error << 1); - cdb[9] += (byte)((byte)headerCodes << 5); - if(sync) - cdb[9] += 0x80; - if(userData) - cdb[9] += 0x10; - if(edcEcc) - cdb[9] += 0x08; - cdb[10] = (byte)subchannel; - - buffer = new byte[blockSize * transferLength]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ CD took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the MMC READ CD MSF command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the MMC READ CD MSF response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Start MM:SS:FF of read encoded as 0x00MMSSFF. - /// End MM:SS:FF of read encoded as 0x00MMSSFF. - /// Block size. - /// Expected sector type. - /// If set to true CD-DA should be modified by mute and interpolation - /// If set to true we request the sync bytes for data sectors. - /// Header codes. - /// If set to true we request the user data. - /// If set to true we request the EDC/ECC fields for data sectors. - /// C2 error options. - /// Subchannel selection. - public bool ReadCdMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf, uint endMsf, uint blockSize, MmcSectorTypes expectedSectorType, - bool DAP, bool sync, MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField C2Error, MmcSubchannel subchannel, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadCdMsf; - cdb[1] = (byte)((byte)expectedSectorType << 2); - if(DAP) - cdb[1] += 0x02; - cdb[3] = (byte)((startMsf & 0xFF0000) >> 16); - cdb[4] = (byte)((startMsf & 0xFF00) >> 8); - cdb[5] = (byte)(startMsf & 0xFF); - cdb[6] = (byte)((endMsf & 0xFF0000) >> 16); - cdb[7] = (byte)((endMsf & 0xFF00) >> 8); - cdb[8] = (byte)(endMsf & 0xFF); - cdb[9] = (byte)((byte)C2Error << 1); - cdb[9] += (byte)((byte)headerCodes << 5); - if(sync) - cdb[9] += 0x80; - if(userData) - cdb[9] += 0x10; - if(edcEcc) - cdb[9] += 0x08; - cdb[10] = (byte)subchannel; - - uint transferLength = (uint)((cdb[6] - cdb[3]) * 60 * 75 + (cdb[7] - cdb[4]) * 75 + (cdb[8] - cdb[5])); - - buffer = new byte[blockSize * transferLength]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ CD MSF took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the Pioneer READ CD-DA command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the Pioneer READ CD-DA response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Start block address. - /// How many blocks to read. - /// Block size. - /// Subchannel selection. - public bool ReadCdDa(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength, PioneerSubchannel subchannel, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadCdDa; - cdb[2] = (byte)((lba & 0xFF000000) >> 24); - cdb[3] = (byte)((lba & 0xFF0000) >> 16); - cdb[4] = (byte)((lba & 0xFF00) >> 8); - cdb[5] = (byte)(lba & 0xFF); - cdb[7] = (byte)((transferLength & 0xFF0000) >> 16); - cdb[8] = (byte)((transferLength & 0xFF00) >> 8); - cdb[9] = (byte)(transferLength & 0xFF); - cdb[10] = (byte)subchannel; - - buffer = new byte[blockSize * transferLength]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ CD-DA took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the Pioneer READ CD-DA MSF command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the Pioneer READ CD-DA MSF response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Start MM:SS:FF of read encoded as 0x00MMSSFF. - /// End MM:SS:FF of read encoded as 0x00MMSSFF. - /// Block size. - /// Subchannel selection. - public bool ReadCdDaMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf, uint endMsf, uint blockSize, PioneerSubchannel subchannel, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadCdMsf; - cdb[3] = (byte)((startMsf & 0xFF0000) >> 16); - cdb[4] = (byte)((startMsf & 0xFF00) >> 8); - cdb[5] = (byte)(startMsf & 0xFF); - cdb[7] = (byte)((endMsf & 0xFF0000) >> 16); - cdb[8] = (byte)((endMsf & 0xFF00) >> 8); - cdb[9] = (byte)(endMsf & 0xFF); - cdb[10] = (byte)subchannel; - - uint transferLength = (uint)((cdb[6] - cdb[3]) * 60 * 75 + (cdb[7] - cdb[4]) * 75 + (cdb[8] - cdb[5])); - - buffer = new byte[blockSize * transferLength]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ CD-DA MSF took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the Plextor READ CD-DA command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the Plextor READ CD-DA response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Start block address. - /// How many blocks to read. - /// Block size. - /// Subchannel selection. - public bool ReadCdDa(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength, PlextorSubchannel subchannel, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadCdDa; - cdb[2] = (byte)((lba & 0xFF000000) >> 24); - cdb[3] = (byte)((lba & 0xFF0000) >> 16); - cdb[4] = (byte)((lba & 0xFF00) >> 8); - cdb[5] = (byte)(lba & 0xFF); - cdb[6] = (byte)((transferLength & 0xFF000000) >> 24); - cdb[7] = (byte)((transferLength & 0xFF0000) >> 16); - cdb[8] = (byte)((transferLength & 0xFF00) >> 8); - cdb[9] = (byte)(transferLength & 0xFF); - cdb[10] = (byte)subchannel; - - buffer = new byte[blockSize * transferLength]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ CD-DA took {0} ms.", duration); - - return sense; - } - - /// - /// Sends the NEC READ CD-DA command - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the NEC READ CD-DA response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Start block address. - /// How many blocks to read. - public bool ReadCdDa(out byte[] buffer, out byte[] senseBuffer, uint lba, uint transferLength, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; - bool sense; - - cdb[0] = (byte)ScsiCommands.NEC_ReadCdDa; - cdb[2] = (byte)((lba & 0xFF000000) >> 24); - cdb[3] = (byte)((lba & 0xFF0000) >> 16); - cdb[4] = (byte)((lba & 0xFF00) >> 8); - cdb[5] = (byte)(lba & 0xFF); - cdb[7] = (byte)((transferLength & 0xFF00) >> 8); - cdb[8] = (byte)(transferLength & 0xFF); - - buffer = new byte[2352 * transferLength]; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "READ CD-DA took {0} ms.", duration); - - return sense; - } - - /// - /// Reads a "raw" sector from DVD on Plextor drives. Does it reading drive's cache. - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the Plextor READ DVD (RAW) response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Start block address. - /// How many blocks to read. - public bool PlextorReadRawDvd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint transferLength, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; - buffer = new byte[2064 * transferLength]; - bool sense; - - cdb[0] = (byte)ScsiCommands.ReadBuffer; - cdb[1] = 0x02; - cdb[3] = (byte)((lba & 0xFF0000) >> 16); - cdb[4] = (byte)((lba & 0xFF00) >> 8); - cdb[5] = (byte)(lba & 0xFF); - cdb[3] = (byte)((buffer.Length & 0xFF0000) >> 16); - cdb[4] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[5] = (byte)(buffer.Length & 0xFF); - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "Plextor READ DVD (RAW) took {0} ms.", duration); - - return sense; - } - - /// - /// Reads a "raw" sector from DVD on HL-DT-ST drives. - /// - /// true if the command failed and contains the sense buffer. - /// Buffer where the HL-DT-ST READ DVD (RAW) response will be stored - /// Sense buffer. - /// Timeout in seconds. - /// Duration in milliseconds it took for the device to execute the command. - /// Start block address. - /// How many blocks to read. - public bool HlDtStReadRawDvd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint transferLength, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - buffer = new byte[2064 * transferLength]; - bool sense; - - cdb[0] = (byte)ScsiCommands.HlDtSt_Vendor; - cdb[1] = 0x48; - cdb[2] = 0x49; - cdb[3] = 0x54; - cdb[4] = 0x01; - cdb[6] = (byte)((lba & 0xFF000000) >> 24); - cdb[7] = (byte)((lba & 0xFF0000) >> 16); - cdb[8] = (byte)((lba & 0xFF00) >> 8); - cdb[9] = (byte)(lba & 0xFF); - cdb[10] = (byte)((buffer.Length & 0xFF00) >> 8); - cdb[11] = (byte)(buffer.Length & 0xFF); - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "HL-DT-ST READ DVD (RAW) took {0} ms.", duration); - - return sense; - } - - /// - /// Moves the device reading element to the specified block address - /// - /// Sense buffer. - /// LBA. - /// Timeout. - /// Duration. - public bool Seek6(out byte[] senseBuffer, uint lba, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[6]; - byte[] buffer = new byte[0]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Seek6; - cdb[1] = (byte)((lba & 0x1F0000) >> 16); - cdb[2] = (byte)((lba & 0xFF00) >> 8); - cdb[3] = (byte)(lba & 0xFF); - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "SEEK (6) took {0} ms.", duration); - - return sense; - } - - /// - /// Moves the device reading element to the specified block address - /// - /// Sense buffer. - /// LBA. - /// Timeout. - /// Duration. - public bool Seek10(out byte[] senseBuffer, uint lba, uint timeout, out double duration) - { - senseBuffer = new byte[32]; - byte[] cdb = new byte[10]; - byte[] buffer = new byte[0]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Seek10; - cdb[2] = (byte)((lba & 0xFF000000) >> 24); - cdb[3] = (byte)((lba & 0xFF0000) >> 16); - cdb[4] = (byte)((lba & 0xFF00) >> 8); - cdb[5] = (byte)(lba & 0xFF); - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "SEEK (10) took {0} ms.", duration); - - return sense; - } - - /// - /// Reads the statistics EEPROM from Plextor CD recorders - /// - /// true, if EEPROM is correctly read, false otherwise. - /// Buffer. - /// Sense buffer. - /// Timeout. - /// Duration. - public bool PlextorReadEepromCDR(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - buffer = new byte[256]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_ReadEeprom; - cdb[8] = 1; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR READ EEPROM took {0} ms.", duration); - - return sense; - } - - /// - /// Reads the statistics EEPROM from Plextor PX-708 and PX-712 recorders - /// - /// true, if EEPROM is correctly read, false otherwise. - /// Buffer. - /// Sense buffer. - /// Timeout. - /// Duration. - public bool PlextorReadEeprom(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - buffer = new byte[512]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_ReadEeprom; - cdb[8] = 2; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR READ EEPROM took {0} ms.", duration); - - return sense; - } - - /// - /// Reads a block from the statistics EEPROM from Plextor DVD recorders - /// - /// true, if EEPROM is correctly read, false otherwise. - /// Buffer. - /// Sense buffer. - /// EEPROM block to read - /// How many bytes are in the EEPROM block - /// Timeout. - /// Duration. - public bool PlextorReadEepromBlock(out byte[] buffer, out byte[] senseBuffer, byte block, ushort blockSize, uint timeout, out double duration) - { - buffer = new byte[blockSize]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_ReadEeprom; - cdb[1] = 1; - cdb[7] = block; - cdb[8] = (byte)((blockSize & 0xFF00) >> 8); - cdb[9] = (byte)(blockSize & 0xFF); - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR READ EEPROM took {0} ms.", duration); - - return sense; - } - - /// - /// Gets speeds set by Plextor PoweRec - /// - /// true, if speeds were got correctly, false otherwise. - /// Sense buffer. - /// Selected write speed. - /// Max speed for currently inserted media. - /// Last actual speed. - /// Timeout. - /// Duration. - public bool PlextorGetSpeeds(out byte[] senseBuffer, out ushort selected, out ushort max, out ushort last, uint timeout, out double duration) - { - byte[] buf = new byte[10]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - selected = 0; - max = 0; - last = 0; - - cdb[0] = (byte)ScsiCommands.Plextor_PoweRec; - cdb[9] = (byte)buf.Length; - - lastError = SendScsiCommand(cdb, ref buf, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR POWEREC GET SPEEDS took {0} ms.", duration); - - if (!sense && !error) - { - BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; - selected = BigEndianBitConverter.ToUInt16(buf, 4); - max = BigEndianBitConverter.ToUInt16(buf, 6); - last = BigEndianBitConverter.ToUInt16(buf, 8); - } - - return sense; - } - - /// - /// Gets the Plextor PoweRec status - /// - /// true, if PoweRec is supported, false otherwise. - /// Sense buffer. - /// PoweRec is enabled. - /// PoweRec recommended speed. - /// Timeout. - /// Duration. - public bool PlextorGetPoweRec(out byte[] senseBuffer, out bool enabled, out ushort speed, uint timeout, out double duration) - { - byte[] buf = new byte[8]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - enabled = false; - speed = 0; - - cdb[0] = (byte)ScsiCommands.Plextor_Extend2; - cdb[1] = (byte)PlextorSubCommands.GetMode; - cdb[9] = (byte)buf.Length; - - lastError = SendScsiCommand(cdb, ref buf, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR POWEREC GET SPEEDS took {0} ms.", duration); - - if (!sense && !error) - { - BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; - enabled = buf[2] != 0; - speed = BigEndianBitConverter.ToUInt16(buf, 4); - } - - return sense; - } - - /// - /// Gets the Plextor SilentMode status - /// - /// true, if SilentMode is supported, false otherwise. - /// Buffer. - /// Sense buffer. - /// Timeout. - /// Duration. - public bool PlextorGetSilentMode(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - buffer = new byte[8]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_Extend; - cdb[1] = (byte)PlextorSubCommands.GetMode; - cdb[2] = (byte)PlextorSubCommands.Silent; - cdb[3] = 4; - cdb[10] = (byte)buffer.Length; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SILENT MODE took {0} ms.", duration); - - return sense; - } - - /// - /// Gets the Plextor GigaRec status - /// - /// true, if GigaRec is supported, false otherwise. - /// Buffer. - /// Sense buffer. - /// Timeout. - /// Duration. - public bool PlextorGetGigaRec(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - buffer = new byte[8]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_Extend; - cdb[1] = (byte)PlextorSubCommands.GetMode; - cdb[2] = (byte)PlextorSubCommands.GigaRec; - cdb[10] = (byte)buffer.Length; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET GIGAREC took {0} ms.", duration); - - return sense; - } - - /// - /// Gets the Plextor VariRec status - /// - /// true, if VariRec is supported, false otherwise. - /// Buffer. - /// Sense buffer. - /// Timeout. - /// Duration. - public bool PlextorGetVariRec(out byte[] buffer, out byte[] senseBuffer, bool dvd, uint timeout, out double duration) - { - buffer = new byte[8]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_Extend; - cdb[1] = (byte)PlextorSubCommands.GetMode; - cdb[2] = (byte)PlextorSubCommands.VariRec; - cdb[10] = (byte)buffer.Length; - - if(dvd) - cdb[3] = 0x12; - else - cdb[3] = 0x02; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET VARIREC took {0} ms.", duration); - - return sense; - } - - /// - /// Gets the Plextor SecuRec status - /// - /// true, if SecuRec is supported, false otherwise. - /// Buffer. - /// Sense buffer. - /// Timeout. - /// Duration. - public bool PlextorGetSecuRec(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - buffer = new byte[8]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_Extend; - cdb[2] = (byte)PlextorSubCommands.SecuRec; - cdb[10] = (byte)buffer.Length; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SECUREC took {0} ms.", duration); - - return sense; - } - - /// - /// Gets the Plextor SpeedRead status - /// - /// true, if SpeedRead is supported, false otherwise. - /// Buffer. - /// Sense buffer. - /// Timeout. - /// Duration. - public bool PlextorGetSpeedRead(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - buffer = new byte[8]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_Extend; - cdb[1] = (byte)PlextorSubCommands.GetMode; - cdb[2] = (byte)PlextorSubCommands.SpeedRead; - cdb[10] = (byte)buffer.Length; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SPEEDREAD took {0} ms.", duration); - - return sense; - } - - /// - /// Gets the Plextor CD-R and multi-session hiding status - /// - /// true, if CD-R and multi-session hiding is supported, false otherwise. - /// Buffer. - /// Sense buffer. - /// Timeout. - /// Duration. - public bool PlextorGetHiding(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - buffer = new byte[8]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_Extend; - cdb[1] = (byte)PlextorSubCommands.GetMode; - cdb[2] = (byte)PlextorSubCommands.SessionHide; - cdb[9] = (byte)buffer.Length; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SINGLE-SESSION / HIDE CD-R took {0} ms.", duration); - - return sense; - } - - /// - /// Gets the Plextor DVD+ book bitsetting status - /// - /// true, if DVD+ book bitsetting is supported, false otherwise. - /// Buffer. - /// Sense buffer. - /// Timeout. - /// Duration. - public bool PlextorGetBitsetting(out byte[] buffer, out byte[] senseBuffer, bool dualLayer, uint timeout, out double duration) - { - buffer = new byte[8]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_Extend; - cdb[1] = (byte)PlextorSubCommands.GetMode; - cdb[2] = (byte)PlextorSubCommands.BitSet; - cdb[9] = (byte)buffer.Length; - - if(dualLayer) - cdb[3] = (byte)PlextorSubCommands.BitSetRDL; - else - cdb[3] = (byte)PlextorSubCommands.BitSetR; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET BOOK BITSETTING took {0} ms.", duration); - - return sense; - } - - /// - /// Gets the Plextor DVD+ test writing status - /// - /// true, if DVD+ test writing is supported, false otherwise. - /// Buffer. - /// Sense buffer. - /// Timeout. - /// Duration. - public bool PlextorGetTestWriteDvdPlus(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) - { - buffer = new byte[8]; - senseBuffer = new byte[32]; - byte[] cdb = new byte[12]; - bool sense; - - cdb[0] = (byte)ScsiCommands.Plextor_Extend; - cdb[1] = (byte)PlextorSubCommands.GetMode; - cdb[2] = (byte)PlextorSubCommands.TestWriteDvdPlus; - cdb[10] = (byte)buffer.Length; - - lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); - error = lastError != 0; - - DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET TEST WRITE DVD+ took {0} ms.", duration); - - return sense; - } - } -} - diff --git a/DiscImageChef.Devices/Device/ScsiCommands/HL-DT-ST.cs b/DiscImageChef.Devices/Device/ScsiCommands/HL-DT-ST.cs new file mode 100644 index 00000000..11543cf2 --- /dev/null +++ b/DiscImageChef.Devices/Device/ScsiCommands/HL-DT-ST.cs @@ -0,0 +1,83 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : HL-DT-ST.cs +// Version : 1.0 +// Author(s) : Natalia Portillo +// +// Component : HL-DT-ST vendor commands +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using DiscImageChef.Console; + +namespace DiscImageChef.Devices +{ + public partial class Device + { + /// + /// Reads a "raw" sector from DVD on HL-DT-ST drives. + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the HL-DT-ST READ DVD (RAW) response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Start block address. + /// How many blocks to read. + public bool HlDtStReadRawDvd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint transferLength, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + buffer = new byte[2064 * transferLength]; + bool sense; + + cdb[0] = (byte)ScsiCommands.HlDtSt_Vendor; + cdb[1] = 0x48; + cdb[2] = 0x49; + cdb[3] = 0x54; + cdb[4] = 0x01; + cdb[6] = (byte)((lba & 0xFF000000) >> 24); + cdb[7] = (byte)((lba & 0xFF0000) >> 16); + cdb[8] = (byte)((lba & 0xFF00) >> 8); + cdb[9] = (byte)(lba & 0xFF); + cdb[10] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[11] = (byte)(buffer.Length & 0xFF); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "HL-DT-ST READ DVD (RAW) took {0} ms.", duration); + + return sense; + } + } +} + diff --git a/DiscImageChef.Devices/Device/ScsiCommands/MMC.cs b/DiscImageChef.Devices/Device/ScsiCommands/MMC.cs new file mode 100644 index 00000000..d6b77020 --- /dev/null +++ b/DiscImageChef.Devices/Device/ScsiCommands/MMC.cs @@ -0,0 +1,497 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : MmcCommands.cs +// Version : 1.0 +// Author(s) : Natalia Portillo +// +// Component : SCSI MultiMedia Commands +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using DiscImageChef.Console; + +namespace DiscImageChef.Devices +{ + public partial class Device + { + /// + /// Sends the MMC GET CONFIGURATION command for all Features + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI GET CONFIGURATION response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return GetConfiguration(out buffer, out senseBuffer, 0x0000, MmcGetConfigurationRt.All, timeout, out duration); + } + + /// + /// Sends the MMC GET CONFIGURATION command for all Features starting with specified one + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI GET CONFIGURATION response will be stored + /// Sense buffer. + /// Feature number where the feature list should start from + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, uint timeout, out double duration) + { + return GetConfiguration(out buffer, out senseBuffer, startingFeatureNumber, MmcGetConfigurationRt.All, timeout, out duration); + } + + /// + /// Sends the MMC GET CONFIGURATION command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI GET CONFIGURATION response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Starting Feature number. + /// Return type, . + public bool GetConfiguration(out byte[] buffer, out byte[] senseBuffer, ushort startingFeatureNumber, MmcGetConfigurationRt RT, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + buffer = new byte[8]; + bool sense; + + cdb[0] = (byte)ScsiCommands.GetConfiguration; + cdb[1] = (byte)((byte)RT & 0x03); + cdb[2] = (byte)((startingFeatureNumber & 0xFF00) >> 8); + cdb[3] = (byte)(startingFeatureNumber & 0xFF); + 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 confLength = (ushort)(((int)buffer[2] << 8) + buffer[3] + 4); + buffer = new byte[confLength]; + 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", "GET CONFIGURATION took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the MMC READ DISC STRUCTURE command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ DISC STRUCTURE response will be stored + /// Sense buffer. + /// Medium type for requested disc structure + /// Medium address for requested disc structure + /// Medium layer for requested disc structure + /// Timeout in seconds. + /// Which disc structure are we requesting + /// AGID used in medium copy protection + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType, uint address, byte layerNumber, MmcDiscStructureFormat format, byte AGID, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + buffer = new byte[8]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadDiscStructure; + cdb[1] = (byte)((byte)mediaType & 0x0F); + cdb[2] = (byte)((address & 0xFF000000) >> 24); + cdb[3] = (byte)((address & 0xFF0000) >> 16); + cdb[4] = (byte)((address & 0xFF00) >> 8); + cdb[5] = (byte)(address & 0xFF); + cdb[6] = layerNumber; + cdb[7] = (byte)format; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + cdb[10] = (byte)((AGID & 0x03) << 6); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + if (sense) + return true; + + ushort strctLength = (ushort)(((int)buffer[0] << 8) + buffer[1] + 2); + buffer = new byte[strctLength]; + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (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", "READ DISC STRUCTURE took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the MMC READ TOC/PMA/ATIP command to get formatted TOC from disc, in MM:SS:FF format + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Start TOC from this track + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadToc(out byte[] buffer, out byte[] senseBuffer, byte track, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 0, track, timeout, out duration); + } + + /// + /// Sends the MMC READ TOC/PMA/ATIP command to get formatted TOC from disc + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// If true, request data in MM:SS:FF units, otherwise, in blocks + /// Start TOC from this track + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadToc(out byte[] buffer, out byte[] senseBuffer, bool MSF, byte track, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, MSF, 0, track, timeout, out duration); + } + + /// + /// Sends the MMC READ TOC/PMA/ATIP command to get multi-session information, in MM:SS:FF format + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadSessionInfo(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 1, 0, timeout, out duration); + } + + /// + /// Sends the MMC READ TOC/PMA/ATIP command to get multi-session information + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// If true, request data in MM:SS:FF units, otherwise, in blocks + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadSessionInfo(out byte[] buffer, out byte[] senseBuffer, bool MSF, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, MSF, 1, 0, timeout, out duration); + } + + /// + /// Sends the MMC READ TOC/PMA/ATIP command to get raw TOC subchannels + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Session which TOC to get + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadRawToc(out byte[] buffer, out byte[] senseBuffer, byte sessionNumber, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 2, sessionNumber, timeout, out duration); + } + + /// + /// Sends the MMC READ TOC/PMA/ATIP command to get PMA + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadPma(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 3, 0, timeout, out duration); + } + + /// + /// Sends the MMC READ TOC/PMA/ATIP command to get ATIP + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadAtip(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 4, 0, timeout, out duration); + } + + /// + /// Sends the MMC READ TOC/PMA/ATIP command to get Lead-In CD-TEXT + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadCdText(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadTocPmaAtip(out buffer, out senseBuffer, true, 5, 0, timeout, out duration); + } + + /// + /// Sends the MMC READ TOC/PMA/ATIP command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ TOC/PMA/ATIP response will be stored + /// Sense buffer. + /// If true, request data in MM:SS:FF units, otherwise, in blocks + /// What structure is requested + /// Track/Session number + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadTocPmaAtip(out byte[] buffer, out byte[] senseBuffer, bool MSF, byte format, byte trackSessionNumber, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + byte[] tmpBuffer; + bool sense; + + if(format == 5) + tmpBuffer = new byte[32768]; + else + tmpBuffer = new byte[1024]; + + cdb[0] = (byte)ScsiCommands.ReadTocPmaAtip; + if (MSF) + cdb[1] = 0x02; + cdb[2] = (byte)(format & 0x0F); + cdb[6] = trackSessionNumber; + cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(tmpBuffer.Length & 0xFF); + + lastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + uint strctLength = (uint)(((int)tmpBuffer[0] << 8) + tmpBuffer[1] + 2); + buffer = new byte[strctLength]; + + if (buffer.Length <= tmpBuffer.Length) + { + Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length); + DicConsole.DebugWriteLine("SCSI Device", "READ TOC/PMA/ATIP took {0} ms.", duration); + return sense; + } + + double tmpDuration = duration; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + duration += tmpDuration; + DicConsole.DebugWriteLine("SCSI Device", "READ TOC/PMA/ATIP took {0} ms.", duration); + return sense; + } + + /// + /// Sends the MMC READ DISC INFORMATION command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ DISC INFORMATION response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadDiscInformation(out buffer, out senseBuffer, MmcDiscInformationDataTypes.DiscInformation, timeout, out duration); + } + + /// + /// Sends the MMC READ DISC INFORMATION command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ DISC INFORMATION response will be stored + /// Sense buffer. + /// Which disc information to read + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadDiscInformation(out byte[] buffer, out byte[] senseBuffer, MmcDiscInformationDataTypes dataType, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + byte[] tmpBuffer = new byte[804]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadDiscInformation; + cdb[1] = (byte)dataType; + cdb[7] = (byte)((tmpBuffer.Length & 0xFF00) >> 8); + cdb[8] = (byte)(tmpBuffer.Length & 0xFF); + + lastError = SendScsiCommand(cdb, ref tmpBuffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + uint strctLength = (uint)(((int)tmpBuffer[0] << 8) + tmpBuffer[1] + 2); + buffer = new byte[strctLength]; + Array.Copy(tmpBuffer, 0, buffer, 0, buffer.Length); + + DicConsole.DebugWriteLine("SCSI Device", "READ DISC INFORMATION took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the MMC READ CD command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the MMC READ CD response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Start block address. + /// How many blocks to read. + /// Block size. + /// Expected sector type. + /// If set to true CD-DA should be modified by mute and interpolation + /// If set to true address is relative to current position. + /// If set to true we request the sync bytes for data sectors. + /// Header codes. + /// If set to true we request the user data. + /// If set to true we request the EDC/ECC fields for data sectors. + /// C2 error options. + /// Subchannel selection. + public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength, MmcSectorTypes expectedSectorType, + bool DAP, bool relAddr, bool sync, MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField C2Error, MmcSubchannel subchannel, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadCd; + cdb[1] = (byte)((byte)expectedSectorType << 2); + if(DAP) + cdb[1] += 0x02; + if(relAddr) + cdb[1] += 0x01; + cdb[2] = (byte)((lba & 0xFF000000) >> 24); + cdb[3] = (byte)((lba & 0xFF0000) >> 16); + cdb[4] = (byte)((lba & 0xFF00) >> 8); + cdb[5] = (byte)(lba & 0xFF); + cdb[6] = (byte)((transferLength & 0xFF0000) >> 16); + cdb[7] = (byte)((transferLength & 0xFF00) >> 8); + cdb[8] = (byte)(transferLength & 0xFF); + cdb[9] = (byte)((byte)C2Error << 1); + cdb[9] += (byte)((byte)headerCodes << 5); + if(sync) + cdb[9] += 0x80; + if(userData) + cdb[9] += 0x10; + if(edcEcc) + cdb[9] += 0x08; + cdb[10] = (byte)subchannel; + + buffer = new byte[blockSize * transferLength]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ CD took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the MMC READ CD MSF command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the MMC READ CD MSF response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Start MM:SS:FF of read encoded as 0x00MMSSFF. + /// End MM:SS:FF of read encoded as 0x00MMSSFF. + /// Block size. + /// Expected sector type. + /// If set to true CD-DA should be modified by mute and interpolation + /// If set to true we request the sync bytes for data sectors. + /// Header codes. + /// If set to true we request the user data. + /// If set to true we request the EDC/ECC fields for data sectors. + /// C2 error options. + /// Subchannel selection. + public bool ReadCdMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf, uint endMsf, uint blockSize, MmcSectorTypes expectedSectorType, + bool DAP, bool sync, MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField C2Error, MmcSubchannel subchannel, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadCdMsf; + cdb[1] = (byte)((byte)expectedSectorType << 2); + if(DAP) + cdb[1] += 0x02; + cdb[3] = (byte)((startMsf & 0xFF0000) >> 16); + cdb[4] = (byte)((startMsf & 0xFF00) >> 8); + cdb[5] = (byte)(startMsf & 0xFF); + cdb[6] = (byte)((endMsf & 0xFF0000) >> 16); + cdb[7] = (byte)((endMsf & 0xFF00) >> 8); + cdb[8] = (byte)(endMsf & 0xFF); + cdb[9] = (byte)((byte)C2Error << 1); + cdb[9] += (byte)((byte)headerCodes << 5); + if(sync) + cdb[9] += 0x80; + if(userData) + cdb[9] += 0x10; + if(edcEcc) + cdb[9] += 0x08; + cdb[10] = (byte)subchannel; + + uint transferLength = (uint)((cdb[6] - cdb[3]) * 60 * 75 + (cdb[7] - cdb[4]) * 75 + (cdb[8] - cdb[5])); + + buffer = new byte[blockSize * transferLength]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ CD MSF took {0} ms.", duration); + + return sense; + } + } +} + diff --git a/DiscImageChef.Devices/Device/ScsiCommands/NEC.cs b/DiscImageChef.Devices/Device/ScsiCommands/NEC.cs new file mode 100644 index 00000000..ceba6463 --- /dev/null +++ b/DiscImageChef.Devices/Device/ScsiCommands/NEC.cs @@ -0,0 +1,80 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : NEC.cs +// Version : 1.0 +// Author(s) : Natalia Portillo +// +// Component : NEC vendor commands +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using DiscImageChef.Console; + +namespace DiscImageChef.Devices +{ + public partial class Device + { + /// + /// Sends the NEC READ CD-DA command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the NEC READ CD-DA response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Start block address. + /// How many blocks to read. + public bool ReadCdDa(out byte[] buffer, out byte[] senseBuffer, uint lba, uint transferLength, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + bool sense; + + cdb[0] = (byte)ScsiCommands.NEC_ReadCdDa; + cdb[2] = (byte)((lba & 0xFF000000) >> 24); + cdb[3] = (byte)((lba & 0xFF0000) >> 16); + cdb[4] = (byte)((lba & 0xFF00) >> 8); + cdb[5] = (byte)(lba & 0xFF); + cdb[7] = (byte)((transferLength & 0xFF00) >> 8); + cdb[8] = (byte)(transferLength & 0xFF); + + buffer = new byte[2352 * transferLength]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ CD-DA took {0} ms.", duration); + + return sense; + } + } +} + diff --git a/DiscImageChef.Devices/Device/ScsiCommands/Pioneer.cs b/DiscImageChef.Devices/Device/ScsiCommands/Pioneer.cs new file mode 100644 index 00000000..9ff00b25 --- /dev/null +++ b/DiscImageChef.Devices/Device/ScsiCommands/Pioneer.cs @@ -0,0 +1,123 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : Pioneer.cs +// Version : 1.0 +// Author(s) : Natalia Portillo +// +// Component : Pioneer vendor commands +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using DiscImageChef.Console; + +namespace DiscImageChef.Devices +{ + public partial class Device + { + /// + /// Sends the Pioneer READ CD-DA command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the Pioneer READ CD-DA response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Start block address. + /// How many blocks to read. + /// Block size. + /// Subchannel selection. + public bool ReadCdDa(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength, PioneerSubchannel subchannel, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadCdDa; + cdb[2] = (byte)((lba & 0xFF000000) >> 24); + cdb[3] = (byte)((lba & 0xFF0000) >> 16); + cdb[4] = (byte)((lba & 0xFF00) >> 8); + cdb[5] = (byte)(lba & 0xFF); + cdb[7] = (byte)((transferLength & 0xFF0000) >> 16); + cdb[8] = (byte)((transferLength & 0xFF00) >> 8); + cdb[9] = (byte)(transferLength & 0xFF); + cdb[10] = (byte)subchannel; + + buffer = new byte[blockSize * transferLength]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ CD-DA took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the Pioneer READ CD-DA MSF command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the Pioneer READ CD-DA MSF response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Start MM:SS:FF of read encoded as 0x00MMSSFF. + /// End MM:SS:FF of read encoded as 0x00MMSSFF. + /// Block size. + /// Subchannel selection. + public bool ReadCdDaMsf(out byte[] buffer, out byte[] senseBuffer, uint startMsf, uint endMsf, uint blockSize, PioneerSubchannel subchannel, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadCdMsf; + cdb[3] = (byte)((startMsf & 0xFF0000) >> 16); + cdb[4] = (byte)((startMsf & 0xFF00) >> 8); + cdb[5] = (byte)(startMsf & 0xFF); + cdb[7] = (byte)((endMsf & 0xFF0000) >> 16); + cdb[8] = (byte)((endMsf & 0xFF00) >> 8); + cdb[9] = (byte)(endMsf & 0xFF); + cdb[10] = (byte)subchannel; + + uint transferLength = (uint)((cdb[6] - cdb[3]) * 60 * 75 + (cdb[7] - cdb[4]) * 75 + (cdb[8] - cdb[5])); + + buffer = new byte[blockSize * transferLength]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ CD-DA MSF took {0} ms.", duration); + + return sense; + } + } +} + diff --git a/DiscImageChef.Devices/Device/ScsiCommands/Plextor.cs b/DiscImageChef.Devices/Device/ScsiCommands/Plextor.cs new file mode 100644 index 00000000..1f1d3454 --- /dev/null +++ b/DiscImageChef.Devices/Device/ScsiCommands/Plextor.cs @@ -0,0 +1,514 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : Plextor.cs +// Version : 1.0 +// Author(s) : Natalia Portillo +// +// Component : Plextor vendor commands +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using DiscImageChef.Console; + +namespace DiscImageChef.Devices +{ + public partial class Device + { + /// + /// Sends the Plextor READ CD-DA command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the Plextor READ CD-DA response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Start block address. + /// How many blocks to read. + /// Block size. + /// Subchannel selection. + public bool ReadCdDa(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength, PlextorSubchannel subchannel, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadCdDa; + cdb[2] = (byte)((lba & 0xFF000000) >> 24); + cdb[3] = (byte)((lba & 0xFF0000) >> 16); + cdb[4] = (byte)((lba & 0xFF00) >> 8); + cdb[5] = (byte)(lba & 0xFF); + cdb[6] = (byte)((transferLength & 0xFF000000) >> 24); + cdb[7] = (byte)((transferLength & 0xFF0000) >> 16); + cdb[8] = (byte)((transferLength & 0xFF00) >> 8); + cdb[9] = (byte)(transferLength & 0xFF); + cdb[10] = (byte)subchannel; + + buffer = new byte[blockSize * transferLength]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ CD-DA took {0} ms.", duration); + + return sense; + } + + /// + /// Reads a "raw" sector from DVD on Plextor drives. Does it reading drive's cache. + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the Plextor READ DVD (RAW) response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Start block address. + /// How many blocks to read. + public bool PlextorReadRawDvd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint transferLength, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + buffer = new byte[2064 * transferLength]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadBuffer; + cdb[1] = 0x02; + cdb[3] = (byte)((lba & 0xFF0000) >> 16); + cdb[4] = (byte)((lba & 0xFF00) >> 8); + cdb[5] = (byte)(lba & 0xFF); + cdb[3] = (byte)((buffer.Length & 0xFF0000) >> 16); + cdb[4] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[5] = (byte)(buffer.Length & 0xFF); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "Plextor READ DVD (RAW) took {0} ms.", duration); + + return sense; + } + + /// + /// Reads the statistics EEPROM from Plextor CD recorders + /// + /// true, if EEPROM is correctly read, false otherwise. + /// Buffer. + /// Sense buffer. + /// Timeout. + /// Duration. + public bool PlextorReadEepromCDR(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + buffer = new byte[256]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_ReadEeprom; + cdb[8] = 1; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR READ EEPROM took {0} ms.", duration); + + return sense; + } + + /// + /// Reads the statistics EEPROM from Plextor PX-708 and PX-712 recorders + /// + /// true, if EEPROM is correctly read, false otherwise. + /// Buffer. + /// Sense buffer. + /// Timeout. + /// Duration. + public bool PlextorReadEeprom(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + buffer = new byte[512]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_ReadEeprom; + cdb[8] = 2; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR READ EEPROM took {0} ms.", duration); + + return sense; + } + + /// + /// Reads a block from the statistics EEPROM from Plextor DVD recorders + /// + /// true, if EEPROM is correctly read, false otherwise. + /// Buffer. + /// Sense buffer. + /// EEPROM block to read + /// How many bytes are in the EEPROM block + /// Timeout. + /// Duration. + public bool PlextorReadEepromBlock(out byte[] buffer, out byte[] senseBuffer, byte block, ushort blockSize, uint timeout, out double duration) + { + buffer = new byte[blockSize]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_ReadEeprom; + cdb[1] = 1; + cdb[7] = block; + cdb[8] = (byte)((blockSize & 0xFF00) >> 8); + cdb[9] = (byte)(blockSize & 0xFF); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR READ EEPROM took {0} ms.", duration); + + return sense; + } + + /// + /// Gets speeds set by Plextor PoweRec + /// + /// true, if speeds were got correctly, false otherwise. + /// Sense buffer. + /// Selected write speed. + /// Max speed for currently inserted media. + /// Last actual speed. + /// Timeout. + /// Duration. + public bool PlextorGetSpeeds(out byte[] senseBuffer, out ushort selected, out ushort max, out ushort last, uint timeout, out double duration) + { + byte[] buf = new byte[10]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + selected = 0; + max = 0; + last = 0; + + cdb[0] = (byte)ScsiCommands.Plextor_PoweRec; + cdb[9] = (byte)buf.Length; + + lastError = SendScsiCommand(cdb, ref buf, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR POWEREC GET SPEEDS took {0} ms.", duration); + + if (!sense && !error) + { + BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; + selected = BigEndianBitConverter.ToUInt16(buf, 4); + max = BigEndianBitConverter.ToUInt16(buf, 6); + last = BigEndianBitConverter.ToUInt16(buf, 8); + } + + return sense; + } + + /// + /// Gets the Plextor PoweRec status + /// + /// true, if PoweRec is supported, false otherwise. + /// Sense buffer. + /// PoweRec is enabled. + /// PoweRec recommended speed. + /// Timeout. + /// Duration. + public bool PlextorGetPoweRec(out byte[] senseBuffer, out bool enabled, out ushort speed, uint timeout, out double duration) + { + byte[] buf = new byte[8]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + enabled = false; + speed = 0; + + cdb[0] = (byte)ScsiCommands.Plextor_Extend2; + cdb[1] = (byte)PlextorSubCommands.GetMode; + cdb[9] = (byte)buf.Length; + + lastError = SendScsiCommand(cdb, ref buf, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR POWEREC GET SPEEDS took {0} ms.", duration); + + if (!sense && !error) + { + BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; + enabled = buf[2] != 0; + speed = BigEndianBitConverter.ToUInt16(buf, 4); + } + + return sense; + } + + /// + /// Gets the Plextor SilentMode status + /// + /// true, if SilentMode is supported, false otherwise. + /// Buffer. + /// Sense buffer. + /// Timeout. + /// Duration. + public bool PlextorGetSilentMode(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + buffer = new byte[8]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_Extend; + cdb[1] = (byte)PlextorSubCommands.GetMode; + cdb[2] = (byte)PlextorSubCommands.Silent; + cdb[3] = 4; + cdb[10] = (byte)buffer.Length; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SILENT MODE took {0} ms.", duration); + + return sense; + } + + /// + /// Gets the Plextor GigaRec status + /// + /// true, if GigaRec is supported, false otherwise. + /// Buffer. + /// Sense buffer. + /// Timeout. + /// Duration. + public bool PlextorGetGigaRec(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + buffer = new byte[8]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_Extend; + cdb[1] = (byte)PlextorSubCommands.GetMode; + cdb[2] = (byte)PlextorSubCommands.GigaRec; + cdb[10] = (byte)buffer.Length; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET GIGAREC took {0} ms.", duration); + + return sense; + } + + /// + /// Gets the Plextor VariRec status + /// + /// true, if VariRec is supported, false otherwise. + /// Buffer. + /// Sense buffer. + /// Timeout. + /// Duration. + public bool PlextorGetVariRec(out byte[] buffer, out byte[] senseBuffer, bool dvd, uint timeout, out double duration) + { + buffer = new byte[8]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_Extend; + cdb[1] = (byte)PlextorSubCommands.GetMode; + cdb[2] = (byte)PlextorSubCommands.VariRec; + cdb[10] = (byte)buffer.Length; + + if(dvd) + cdb[3] = 0x12; + else + cdb[3] = 0x02; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET VARIREC took {0} ms.", duration); + + return sense; + } + + /// + /// Gets the Plextor SecuRec status + /// + /// true, if SecuRec is supported, false otherwise. + /// Buffer. + /// Sense buffer. + /// Timeout. + /// Duration. + public bool PlextorGetSecuRec(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + buffer = new byte[8]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_Extend; + cdb[2] = (byte)PlextorSubCommands.SecuRec; + cdb[10] = (byte)buffer.Length; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SECUREC took {0} ms.", duration); + + return sense; + } + + /// + /// Gets the Plextor SpeedRead status + /// + /// true, if SpeedRead is supported, false otherwise. + /// Buffer. + /// Sense buffer. + /// Timeout. + /// Duration. + public bool PlextorGetSpeedRead(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + buffer = new byte[8]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_Extend; + cdb[1] = (byte)PlextorSubCommands.GetMode; + cdb[2] = (byte)PlextorSubCommands.SpeedRead; + cdb[10] = (byte)buffer.Length; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SPEEDREAD took {0} ms.", duration); + + return sense; + } + + /// + /// Gets the Plextor CD-R and multi-session hiding status + /// + /// true, if CD-R and multi-session hiding is supported, false otherwise. + /// Buffer. + /// Sense buffer. + /// Timeout. + /// Duration. + public bool PlextorGetHiding(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + buffer = new byte[8]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_Extend; + cdb[1] = (byte)PlextorSubCommands.GetMode; + cdb[2] = (byte)PlextorSubCommands.SessionHide; + cdb[9] = (byte)buffer.Length; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET SINGLE-SESSION / HIDE CD-R took {0} ms.", duration); + + return sense; + } + + /// + /// Gets the Plextor DVD+ book bitsetting status + /// + /// true, if DVD+ book bitsetting is supported, false otherwise. + /// Buffer. + /// Sense buffer. + /// Timeout. + /// Duration. + public bool PlextorGetBitsetting(out byte[] buffer, out byte[] senseBuffer, bool dualLayer, uint timeout, out double duration) + { + buffer = new byte[8]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_Extend; + cdb[1] = (byte)PlextorSubCommands.GetMode; + cdb[2] = (byte)PlextorSubCommands.BitSet; + cdb[9] = (byte)buffer.Length; + + if(dualLayer) + cdb[3] = (byte)PlextorSubCommands.BitSetRDL; + else + cdb[3] = (byte)PlextorSubCommands.BitSetR; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET BOOK BITSETTING took {0} ms.", duration); + + return sense; + } + + /// + /// Gets the Plextor DVD+ test writing status + /// + /// true, if DVD+ test writing is supported, false otherwise. + /// Buffer. + /// Sense buffer. + /// Timeout. + /// Duration. + public bool PlextorGetTestWriteDvdPlus(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + buffer = new byte[8]; + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Plextor_Extend; + cdb[1] = (byte)PlextorSubCommands.GetMode; + cdb[2] = (byte)PlextorSubCommands.TestWriteDvdPlus; + cdb[10] = (byte)buffer.Length; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PLEXTOR GET TEST WRITE DVD+ took {0} ms.", duration); + + return sense; + } + } +} + diff --git a/DiscImageChef.Devices/Device/ScsiCommands/SBC.cs b/DiscImageChef.Devices/Device/ScsiCommands/SBC.cs new file mode 100644 index 00000000..035cbbda --- /dev/null +++ b/DiscImageChef.Devices/Device/ScsiCommands/SBC.cs @@ -0,0 +1,400 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : SBC.cs +// Version : 1.0 +// Author(s) : Natalia Portillo +// +// Component : SCSI Block Commands +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using DiscImageChef.Console; + +namespace DiscImageChef.Devices +{ + public partial class Device + { + /// + /// Sends the SBC READ (6) command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Starting block. + /// Block size in bytes. + public bool Read6(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint timeout, out double duration) + { + return Read6(out buffer, out senseBuffer, lba, blockSize, 1, timeout, out duration); + } + + /// + /// Sends the SBC READ (6) command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Starting block. + /// Block size in bytes. + /// How many blocks to read. + public bool Read6(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, byte transferLength, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[6]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Read6; + cdb[1] = (byte)((lba & 0x1F0000) >> 16); + cdb[2] = (byte)((lba & 0xFF00) >> 8); + cdb[3] = (byte)(lba & 0xFF); + cdb[4] = transferLength; + + if(transferLength == 0) + buffer = new byte[256 * blockSize]; + else + buffer = new byte[transferLength * blockSize]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ (6) took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SBC READ (10) command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Instructs the drive how to check for protection information on the medium. + /// If set to true requested blocks shall be assigned the lowest retention priority on cache fetch/retain. + /// If set to true requested blocks MUST bu read from medium and not the cache. + /// If set to true requested blocks will be returned from non-volatile cache. If they're not present they shall be stored there. + /// Starting block. + /// Block size in bytes. + /// Group number where attributes associated with this command should be collected. + /// How many blocks to read. + /// If set to true address is relative to current position. + public bool Read10(out byte[] buffer, out byte[] senseBuffer, byte rdprotect, bool dpo, bool fua, bool fuaNv, bool relAddr, uint lba, uint blockSize, byte groupNumber, ushort transferLength, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Read10; + cdb[1] = (byte)((rdprotect & 0x07) << 5); + if(dpo) + cdb[1] += 0x10; + if(fua) + cdb[1] += 0x08; + if(fuaNv) + cdb[1] += 0x02; + if(relAddr) + cdb[1] += 0x01; + cdb[2] = (byte)((lba & 0xFF000000) >> 24); + cdb[3] = (byte)((lba & 0xFF0000) >> 16); + cdb[4] = (byte)((lba & 0xFF00) >> 8); + cdb[5] = (byte)(lba & 0xFF); + cdb[6] = (byte)(groupNumber & 0x1F); + cdb[7] = (byte)((transferLength & 0xFF00) >> 8); + cdb[8] = (byte)(transferLength & 0xFF); + + buffer = new byte[transferLength * blockSize]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ (10) took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SBC READ (12) command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Instructs the drive how to check for protection information on the medium. + /// If set to true requested blocks shall be assigned the lowest retention priority on cache fetch/retain. + /// If set to true requested blocks MUST bu read from medium and not the cache. + /// If set to true requested blocks will be returned from non-volatile cache. If they're not present they shall be stored there. + /// Starting block. + /// Block size in bytes. + /// Group number where attributes associated with this command should be collected. + /// How many blocks to read. + /// If set to true the stream playback operation should be used (MMC only). + /// If set to true address is relative to current position. + public bool Read12(out byte[] buffer, out byte[] senseBuffer, byte rdprotect, bool dpo, bool fua, bool fuaNv, bool relAddr, uint lba, uint blockSize, byte groupNumber, uint transferLength, bool streaming, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Read12; + cdb[1] = (byte)((rdprotect & 0x07) << 5); + if(dpo) + cdb[1] += 0x10; + if(fua) + cdb[1] += 0x08; + if(fuaNv) + cdb[1] += 0x02; + if(relAddr) + cdb[1] += 0x01; + cdb[2] = (byte)((lba & 0xFF000000) >> 24); + cdb[3] = (byte)((lba & 0xFF0000) >> 16); + cdb[4] = (byte)((lba & 0xFF00) >> 8); + cdb[5] = (byte)(lba & 0xFF); + cdb[6] = (byte)((transferLength & 0xFF000000) >> 24); + cdb[7] = (byte)((transferLength & 0xFF0000) >> 16); + cdb[8] = (byte)((transferLength & 0xFF00) >> 8); + cdb[9] = (byte)(transferLength & 0xFF); + cdb[10] = (byte)(groupNumber & 0x1F); + if(streaming) + cdb[10] += 0x80; + + buffer = new byte[transferLength * blockSize]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ (12) took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SBC READ (16) command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Instructs the drive how to check for protection information on the medium. + /// If set to true requested blocks shall be assigned the lowest retention priority on cache fetch/retain. + /// If set to true requested blocks MUST bu read from medium and not the cache. + /// If set to true requested blocks will be returned from non-volatile cache. If they're not present they shall be stored there. + /// Starting block. + /// Block size in bytes. + /// Group number where attributes associated with this command should be collected. + /// How many blocks to read. + /// If set to true the stream playback operation should be used (MMC only). + public bool Read16(out byte[] buffer, out byte[] senseBuffer, byte rdprotect, bool dpo, bool fua, bool fuaNv, ulong lba, uint blockSize, byte groupNumber, uint transferLength, bool streaming, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[16]; + bool sense; + byte[] lbaBytes = BitConverter.GetBytes(lba); + + cdb[0] = (byte)ScsiCommands.Read16; + cdb[1] = (byte)((rdprotect & 0x07) << 5); + if(dpo) + cdb[1] += 0x10; + if(fua) + cdb[1] += 0x08; + if(fuaNv) + cdb[1] += 0x02; + cdb[2] = lbaBytes[7]; + cdb[3] = lbaBytes[6]; + cdb[4] = lbaBytes[5]; + cdb[5] = lbaBytes[4]; + cdb[6] = lbaBytes[3]; + cdb[7] = lbaBytes[2]; + cdb[8] = lbaBytes[1]; + cdb[9] = lbaBytes[0]; + cdb[10] = (byte)((transferLength & 0xFF000000) >> 24); + cdb[11] = (byte)((transferLength & 0xFF0000) >> 16); + cdb[12] = (byte)((transferLength & 0xFF00) >> 8); + cdb[13] = (byte)(transferLength & 0xFF); + cdb[14] = (byte)(groupNumber & 0x1F); + if(streaming) + cdb[14] += 0x80; + + buffer = new byte[transferLength * blockSize]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ (16) took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SBC READ LONG (10) command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ LONG 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 ask the drive to try to correct errors in the sector. + /// LBA to read. + /// How many bytes to read. If the number is not exactly the drive's size, the command will fail and incidate a delta of the size in SENSE. + public bool ReadLong10(out byte[] buffer, out byte[] senseBuffer, bool correct, bool relAddr, uint lba, ushort transferBytes, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadLong; + if(correct) + cdb[1] += 0x02; + if(relAddr) + cdb[1] += 0x01; + cdb[2] = (byte)((lba & 0xFF000000) >> 24); + cdb[3] = (byte)((lba & 0xFF0000) >> 16); + cdb[4] = (byte)((lba & 0xFF00) >> 8); + cdb[5] = (byte)(lba & 0xFF); + cdb[7] = (byte)((transferBytes & 0xFF00) >> 8); + cdb[8] = (byte)(transferBytes & 0xFF); + + buffer = new byte[transferBytes]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ LONG (10) took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SBC READ LONG (16) command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ LONG 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 ask the drive to try to correct errors in the sector. + /// LBA to read. + /// How many bytes to read. If the number is not exactly the drive's size, the command will fail and incidate a delta of the size in SENSE. + public bool ReadLong16(out byte[] buffer, out byte[] senseBuffer, bool correct, ulong lba, uint transferBytes, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[16]; + bool sense; + byte[] lbaBytes = BitConverter.GetBytes(lba); + + cdb[0] = (byte)ScsiCommands.ServiceActionIn; + cdb[1] = (byte)ScsiServiceActions.ReadLong16; + cdb[2] = lbaBytes[7]; + cdb[3] = lbaBytes[6]; + cdb[4] = lbaBytes[5]; + cdb[5] = lbaBytes[4]; + cdb[6] = lbaBytes[3]; + cdb[7] = lbaBytes[2]; + cdb[8] = lbaBytes[1]; + cdb[9] = lbaBytes[0]; + cdb[12] = (byte)((transferBytes & 0xFF00) >> 8); + cdb[13] = (byte)(transferBytes & 0xFF); + if(correct) + cdb[14] += 0x01; + + buffer = new byte[transferBytes]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ LONG (16) took {0} ms.", duration); + + return sense; + } + + /// + /// Moves the device reading element to the specified block address + /// + /// Sense buffer. + /// LBA. + /// Timeout. + /// Duration. + public bool Seek6(out byte[] senseBuffer, uint lba, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[6]; + byte[] buffer = new byte[0]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Seek6; + cdb[1] = (byte)((lba & 0x1F0000) >> 16); + cdb[2] = (byte)((lba & 0xFF00) >> 8); + cdb[3] = (byte)(lba & 0xFF); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "SEEK (6) took {0} ms.", duration); + + return sense; + } + + /// + /// Moves the device reading element to the specified block address + /// + /// Sense buffer. + /// LBA. + /// Timeout. + /// Duration. + public bool Seek10(out byte[] senseBuffer, uint lba, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + byte[] buffer = new byte[0]; + bool sense; + + cdb[0] = (byte)ScsiCommands.Seek10; + cdb[2] = (byte)((lba & 0xFF000000) >> 24); + cdb[3] = (byte)((lba & 0xFF0000) >> 16); + cdb[4] = (byte)((lba & 0xFF00) >> 8); + cdb[5] = (byte)(lba & 0xFF); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "SEEK (10) took {0} ms.", duration); + + return sense; + } + } +} + diff --git a/DiscImageChef.Devices/Device/ScsiCommands/SPC.cs b/DiscImageChef.Devices/Device/ScsiCommands/SPC.cs new file mode 100644 index 00000000..86bf186e --- /dev/null +++ b/DiscImageChef.Devices/Device/ScsiCommands/SPC.cs @@ -0,0 +1,602 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : SpcCommands.cs +// Version : 1.0 +// Author(s) : Natalia Portillo +// +// Component : SCSI Primary Commands +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using DiscImageChef.Console; + +namespace DiscImageChef.Devices +{ + public partial class Device + { + /// + /// Sends the SPC INQUIRY command to the device using default device timeout. + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer) + { + return ScsiInquiry(out buffer, out senseBuffer, Timeout); + } + + /// + /// Sends the SPC INQUIRY command to the device using default device timeout. + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// Duration in milliseconds it took for the device to execute the command. + public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, out double duration) + { + return ScsiInquiry(out buffer, out senseBuffer, Timeout, out duration); + } + + /// + /// Sends the SPC INQUIRY command to the device. + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// Timeout in seconds. + public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, uint timeout) + { + double duration; + return ScsiInquiry(out buffer, out senseBuffer, timeout, out duration); + } + + /// + /// Sends the SPC INQUIRY command to the device. + /// + /// 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 ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + buffer = new byte[36]; + senseBuffer = new byte[32]; + 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); + error = lastError != 0; + + if (sense) + return true; + + byte pagesLength = (byte)(buffer[4] + 5); + + cdb = new byte[] { (byte)ScsiCommands.Inquiry, 0, 0, 0, pagesLength, 0 }; + buffer = new byte[pagesLength]; + 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", "INQUIRY took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SPC INQUIRY command to the device with an Extended Vital Product Data page using default device timeout. + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// The Extended Vital Product Data + public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, byte page) + { + return ScsiInquiry(out buffer, out senseBuffer, page, Timeout); + } + + /// + /// Sends the SPC INQUIRY command to the device with an Extended Vital Product Data page using default device timeout. + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// Duration in milliseconds it took for the device to execute the command. + /// The Extended Vital Product Data + public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, byte page, out double duration) + { + return ScsiInquiry(out buffer, out senseBuffer, page, Timeout, out duration); + } + + /// + /// Sends the SPC INQUIRY command to the device with an Extended Vital Product Data page. + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI INQUIRY response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// The Extended Vital Product Data + public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, byte page, uint timeout) + { + double duration; + return ScsiInquiry(out buffer, out senseBuffer, page, timeout, out duration); + } + + /// + /// Sends the SPC INQUIRY command to the device with an Extended Vital Product Data page. + /// + /// 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. + /// The Extended Vital Product Data + public bool ScsiInquiry(out byte[] buffer, out byte[] senseBuffer, byte page, uint timeout, out double duration) + { + buffer = new byte[36]; + senseBuffer = new byte[32]; + 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); + error = lastError != 0; + + 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 }; + buffer = new byte[pagesLength]; + 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", "INQUIRY took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SPC TEST UNIT READY command to the device + /// + /// true, if unit is NOT ready, false otherwise. + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ScsiTestUnitReady(out byte[] senseBuffer, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = { (byte)ScsiCommands.TestUnitReady, 0, 0, 0, 0, 0 }; + bool sense; + byte[] buffer = new byte[0]; + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "TEST UNIT READY took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SPC 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 MODE SENSE(6) 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 SPC 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 MODE SENSE(6) 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 SPC 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 MODE SENSE(6) 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 SPC 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 MODE SENSE(10) 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 SPC 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 MODE SENSE(10) 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 SPC 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 MODE SENSE(10) 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[4096]; + 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] + 2); + 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; + } + + /// + /// Sends the SPC PREVENT ALLOW MEDIUM REMOVAL command to prevent medium removal + /// + /// true if the command failed and contains the sense buffer. + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool PreventMediumRemoval(out byte[] senseBuffer, uint timeout, out double duration) + { + return PreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Prevent, timeout, out duration); + } + + /// + /// Sends the SPC PREVENT ALLOW MEDIUM REMOVAL command to allow medium removal + /// + /// true if the command failed and contains the sense buffer. + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool AllowMediumRemoval(out byte[] senseBuffer, uint timeout, out double duration) + { + return PreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Allow, timeout, out duration); + } + + /// + /// Sends the SPC PREVENT ALLOW MEDIUM REMOVAL command + /// + /// true if the command failed and contains the sense buffer. + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// true to prevent medium removal, false to allow it. + public bool PreventAllowMediumRemoval(out byte[] senseBuffer, bool prevent, uint timeout, out double duration) + { + if (prevent) + return PreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Prevent, timeout, out duration); + else + return PreventAllowMediumRemoval(out senseBuffer, ScsiPreventAllowMode.Allow, timeout, out duration); + } + + /// + /// Sends the SPC PREVENT ALLOW MEDIUM REMOVAL command + /// + /// true if the command failed and contains the sense buffer. + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + /// Prevention mode. + public bool PreventAllowMediumRemoval(out byte[] senseBuffer, ScsiPreventAllowMode preventMode, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[6]; + bool sense; + byte[] buffer = new byte[0]; + + cdb[0] = (byte)ScsiCommands.PreventAllowMediumRemoval; + cdb[4] = (byte)((byte)preventMode & 0x03); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "PREVENT ALLOW MEDIUM REMOVAL took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SPC READ CAPACITY command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ CAPACITY response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadCapacity(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadCapacity(out buffer, out senseBuffer, false, 0, false, timeout, out duration); + } + + /// + /// Sends the SPC READ CAPACITY command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ CAPACITY response will be stored + /// Sense buffer. + /// Indicates that is relative to current medium position + /// Address where information is requested from, only valid if is set + /// If set, it is requesting partial media capacity + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadCapacity(out byte[] buffer, out byte[] senseBuffer, bool RelAddr, uint address, bool PMI, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[10]; + buffer = new byte[8]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadCapacity; + + if (PMI) + { + cdb[8] = 0x01; + if (RelAddr) + cdb[1] = 0x01; + + cdb[2] = (byte)((address & 0xFF000000) >> 24); + cdb[3] = (byte)((address & 0xFF0000) >> 16); + cdb[4] = (byte)((address & 0xFF00) >> 8); + cdb[5] = (byte)(address & 0xFF); + } + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ CAPACITY took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SPC READ CAPACITY(16) command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ CAPACITY(16) response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadCapacity16(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + return ReadCapacity16(out buffer, out senseBuffer, 0, false, timeout, out duration); + } + + /// + /// Sends the SPC READ CAPACITY(16) command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ CAPACITY(16) response will be stored + /// Sense buffer. + /// Address where information is requested from, only valid if is set + /// If set, it is requesting partial media capacity + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadCapacity16(out byte[] buffer, out byte[] senseBuffer, ulong address, bool PMI, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[16]; + buffer = new byte[32]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ServiceActionIn; + cdb[1] = (byte)ScsiServiceActions.ReadCapacity16; + + if (PMI) + { + cdb[14] = 0x01; + byte[] temp = BitConverter.GetBytes(address); + cdb[2] = temp[7]; + cdb[3] = temp[6]; + cdb[4] = temp[5]; + cdb[5] = temp[4]; + cdb[6] = temp[3]; + cdb[7] = temp[2]; + cdb[8] = temp[1]; + cdb[9] = temp[0]; + } + + cdb[10] = (byte)((buffer.Length & 0xFF000000) >> 24); + cdb[11] = (byte)((buffer.Length & 0xFF0000) >> 16); + cdb[12] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[13] = (byte)(buffer.Length & 0xFF); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + DicConsole.DebugWriteLine("SCSI Device", "READ CAPACITY(16) took {0} ms.", duration); + + return sense; + } + + /// + /// Sends the SPC READ MEDIA SERIAL NUMBER command + /// + /// true if the command failed and contains the sense buffer. + /// Buffer where the SCSI READ MEDIA SERIAL NUMBER response will be stored + /// Sense buffer. + /// Timeout in seconds. + /// Duration in milliseconds it took for the device to execute the command. + public bool ReadMediaSerialNumber(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) + { + senseBuffer = new byte[32]; + byte[] cdb = new byte[12]; + buffer = new byte[4]; + bool sense; + + cdb[0] = (byte)ScsiCommands.ReadSerialNumber; + cdb[1] = 0x01; + cdb[6] = (byte)((buffer.Length & 0xFF000000) >> 24); + cdb[7] = (byte)((buffer.Length & 0xFF0000) >> 16); + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + + lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); + error = lastError != 0; + + if (sense) + return true; + + uint strctLength = (uint)(((int)buffer[0] << 24) + ((int)buffer[1] << 16) + ((int)buffer[2] << 8) + buffer[3] + 4); + cdb[6] = (byte)((buffer.Length & 0xFF000000) >> 24); + cdb[7] = (byte)((buffer.Length & 0xFF0000) >> 16); + cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); + cdb[9] = (byte)(buffer.Length & 0xFF); + buffer = new byte[strctLength]; + 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", "READ MEDIA SERIAL NUMBER took {0} ms.", duration); + + return sense; + } + } +} + diff --git a/DiscImageChef.Devices/DiscImageChef.Devices.csproj b/DiscImageChef.Devices/DiscImageChef.Devices.csproj index a49ff650..f409fdc2 100644 --- a/DiscImageChef.Devices/DiscImageChef.Devices.csproj +++ b/DiscImageChef.Devices/DiscImageChef.Devices.csproj @@ -48,15 +48,22 @@ - + + + + + + + +