From 6928fc1363cc8fdebc6b76297c8e29a9d00f6cab Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 26 Dec 2015 19:02:31 +0000 Subject: [PATCH] Added all known READ, READ LONG, READ CD and READ CD-DA commands. --- DiscImageChef.Devices/ChangeLog | 7 + DiscImageChef.Devices/Device/ScsiCommands.cs | 638 +++++++++++++++++++ DiscImageChef.Devices/Enums.cs | 137 +++- 3 files changed, 781 insertions(+), 1 deletion(-) diff --git a/DiscImageChef.Devices/ChangeLog b/DiscImageChef.Devices/ChangeLog index a514a33b..919c206f 100644 --- a/DiscImageChef.Devices/ChangeLog +++ b/DiscImageChef.Devices/ChangeLog @@ -1,3 +1,10 @@ +2015-12-26 Natalia Portillo + + * Enums.cs: + * Device/ScsiCommands.cs: + Added all known READ, READ LONG, READ CD and READ CD-DA + commands. + 2015-12-04 Natalia Portillo * Device/ScsiCommands.cs: diff --git a/DiscImageChef.Devices/Device/ScsiCommands.cs b/DiscImageChef.Devices/Device/ScsiCommands.cs index ae042235..6126a750 100644 --- a/DiscImageChef.Devices/Device/ScsiCommands.cs +++ b/DiscImageChef.Devices/Device/ScsiCommands.cs @@ -930,6 +930,644 @@ namespace DiscImageChef.Devices 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 ReadCdMsf(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; + } } } diff --git a/DiscImageChef.Devices/Enums.cs b/DiscImageChef.Devices/Enums.cs index 54268244..a71b26ea 100644 --- a/DiscImageChef.Devices/Enums.cs +++ b/DiscImageChef.Devices/Enums.cs @@ -2580,8 +2580,15 @@ namespace DiscImageChef.Devices /// /// Sends debugging commands to HL-DT-ST DVD drives /// - HlDtSt_Vendor = 0xE7 + HlDtSt_Vendor = 0xE7, #endregion HL-DT-ST vendor commands + + #region NEC vendor commands + /// + /// Reads CD-DA data + /// + NEC_ReadCdDa = 0xD4 + #endregion NEC vendor commands } #endregion SCSI Commands @@ -3034,5 +3041,133 @@ namespace DiscImageChef.Devices /// POWResources = 0x02 } + + public enum MmcSectorTypes : byte + { + /// + /// No checking of data type is performed + /// + AllTypes = 0x00, + /// + /// Only CD-DA sectors shall be returned + /// + CDDA = 0x01, + /// + /// Only Mode 1 sectors shall be returned + /// + Mode1 = 0x02, + /// + /// Only Mode 2 formless sectors shall be returned + /// + Mode2 = 0x03, + /// + /// Only Mode 2 Form 1 sectors shall be returned + /// + Mode2Form1 = 0x04, + /// + /// Only Mode 2 Form 2 sectors shall be returned + /// + Mode2Form2 = 0x05 + } + + public enum MmcHeaderCodes : byte + { + /// + /// No header information shall be returned + /// + None = 0x00, + /// + /// Only the four byte header shall be returned + /// + HeaderOnly = 0x01, + /// + /// Only the mode 2 form x subheader shall be returned + /// + SubHeaderOnly = 0x02, + /// + /// Return both header and subheader + /// + AllHeaders = 0x03 + } + + public enum MmcErrorField : byte + { + /// + /// No error information is returned + /// + None = 0x00, + /// + /// The C2 pointer bits will be included + /// + C2Pointers = 0x01, + /// + /// The C2 pointer bits will be included as well as the block error byte with a padding byte + /// + C2PointersAndBlock = 0x02 + } + + public enum MmcSubchannel : byte + { + /// + /// No subchannel shall be returned + /// + None = 0x00, + /// + /// The raw P to W subchannel data shall be transferred + /// + Raw = 0x01, + /// + /// Q data shall be transferred + /// + Q16 = 0x02, + /// + /// De-interleaved and error-corrected R to W subchannel data shall be transferred + /// + RW = 0x04 + } + + public enum PioneerSubchannel : byte + { + /// + /// No subchannel shall be returned + /// + None = 0x00, + /// + /// Q data shall be transferred + /// + Q16 = 0x01, + /// + /// The raw P to W subchannel data shall be transferred + /// + All = 0x02, + /// + /// The raw P to W subchannel data shall be transferred WITHOUT user data + /// + Only = 0x03 + } + + public enum PlextorSubchannel : byte + { + /// + /// No subchannel shall be returned + /// + None = 0x00, + /// + /// Q data shall be transferred + /// + Q16 = 0x01, + /// + /// The packed and corrected P to W subchannel data shall be transferred + /// + Pack = 0x02, + /// + /// The raw P to W subchannel data shall be transferred + /// + All = 0x03, + /// + /// The raw P to W subchannel data, plus C2 error data shall be transferred + /// + RawC2 = 0x08 + } }