// /*************************************************************************** // The Disc Image Chef // ---------------------------------------------------------------------------- // // Filename : SSC.cs // Version : 1.0 // Author(s) : Natalia Portillo // // Component : SCSI Stream 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 { /// /// Prepares the medium for reading /// /// true, if load was successful, false otherwise. /// Sense buffer. /// Timeout. /// Duration. public bool Load(out byte[] senseBuffer, uint timeout, out double duration) { return LoadUnload(out senseBuffer, false, true, false, false, false, timeout, out duration); } /// /// Prepares the medium for ejection /// /// true, if unload was successful, false otherwise. /// Sense buffer. /// Timeout. /// Duration. public bool Unload(out byte[] senseBuffer, uint timeout, out double duration) { return LoadUnload(out senseBuffer, false, false, false, false, false, timeout, out duration); } /// /// Prepares the medium for reading or ejection /// /// true, if load/unload was successful, false otherwise. /// Sense buffer. /// If set to true, return from the command immediately. /// If set to true load the medium for reading. /// If set to true retense the tape. /// If set to true move the medium to the EOT mark. /// If set to true and is also set to true, moves the medium to the drive but does not prepare it for reading. /// Timeout. /// Duration. public bool LoadUnload(out byte[] senseBuffer, bool immediate, bool load, bool retense, bool endOfTape, bool hold, 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.LoadUnload; if (immediate) cdb[1] = 0x01; if (load) cdb[4] += 0x01; if (retense) cdb[4] += 0x02; if (endOfTape) cdb[4] += 0x04; if (hold) cdb[4] += 0x08; lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); error = lastError != 0; DicConsole.DebugWriteLine("SCSI Device", "LOAD UNLOAD (6) took {0} ms.", duration); return sense; } /// /// Positions the medium to the specified block in the current partition /// /// Sense buffer. /// Logical block address. /// Timeout. /// Duration. public bool Locate(out byte[] senseBuffer, uint lba, uint timeout, out double duration) { return Locate(out senseBuffer, false, false, true, 0, lba, timeout, out duration); } /// /// Positions the medium to the specified block in the specified partition /// /// Sense buffer. /// Partition to position to. /// Logical block address. /// Timeout. /// Duration. public bool Locate(out byte[] senseBuffer, byte partition, uint lba, uint timeout, out double duration) { return Locate(out senseBuffer, false, false, true, partition, lba, timeout, out duration); } /// /// Positions the medium to the specified block in the current partition /// /// Sense buffer. /// If set to true, return from the command immediately. /// Logical block address. /// Timeout. /// Duration. public bool Locate(out byte[] senseBuffer, bool immediate, uint lba, uint timeout, out double duration) { return Locate(out senseBuffer, immediate, false, true, 0, lba, timeout, out duration); } /// /// Positions the medium to the specified block in the specified partition /// /// Sense buffer. /// If set to true, return from the command immediately. /// Partition to position to. /// Logical block address. /// Timeout. /// Duration. public bool Locate(out byte[] senseBuffer, bool immediate, byte partition, uint lba, uint timeout, out double duration) { return Locate(out senseBuffer, immediate, false, true, partition, lba, timeout, out duration); } /// /// Positions the medium to the specified object identifier /// /// Sense buffer. /// If set to true, return from the command immediately. /// If set to true object identifier is vendor specified. /// If set to true change partition. /// Partition to position to. /// Object identifier. /// Timeout. /// Duration. public bool Locate(out byte[] senseBuffer, bool immediate, bool blockType, bool changePartition, byte partition, uint objectId, 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.Locate; if (immediate) cdb[1] += 0x01; if (changePartition) cdb[1] += 0x02; if (blockType) cdb[1] += 0x04; cdb[3] = (byte)((objectId & 0xFF000000) >> 24); cdb[4] = (byte)((objectId & 0xFF0000) >> 16); cdb[5] = (byte)((objectId & 0xFF00) >> 8); cdb[6] = (byte)(objectId & 0xFF); cdb[8] = partition; lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); error = lastError != 0; DicConsole.DebugWriteLine("SCSI Device", "LOCATE (10) took {0} ms.", duration); return sense; } /// /// Positions the medium to the specified block in the current partition /// /// Sense buffer. /// Logical block address. /// Timeout. /// Duration. public bool Locate16(out byte[] senseBuffer, ulong lba, uint timeout, out double duration) { return Locate16(out senseBuffer, false, false, SscLogicalIdTypes.ObjectId, false, 0, lba, timeout, out duration); } /// /// Positions the medium to the specified block in the specified partition /// /// Sense buffer. /// Partition to position to. /// Logical block address. /// Timeout. /// Duration. public bool Locate16(out byte[] senseBuffer, byte partition, ulong lba, uint timeout, out double duration) { return Locate16(out senseBuffer, false, true, SscLogicalIdTypes.ObjectId, false, partition, lba, timeout, out duration); } /// /// Positions the medium to the specified block in the current partition /// /// Sense buffer. /// If set to true, return from the command immediately. /// Logical block address. /// Timeout. /// Duration. public bool Locate16(out byte[] senseBuffer, bool immediate, ulong lba, uint timeout, out double duration) { return Locate16(out senseBuffer, immediate, false, SscLogicalIdTypes.ObjectId, false, 0, lba, timeout, out duration); } /// /// Positions the medium to the specified block in the specified partition /// /// Sense buffer. /// If set to true, return from the command immediately. /// Partition to position to. /// Logical block address. /// Timeout. /// Duration. public bool Locate16(out byte[] senseBuffer, bool immediate, byte partition, ulong lba, uint timeout, out double duration) { return Locate16(out senseBuffer, immediate, true, SscLogicalIdTypes.ObjectId, false, partition, lba, timeout, out duration); } /// /// Positions the medium to the specified object identifier /// /// Sense buffer. /// If set to true, return from the command immediately. /// If set to true change partition. /// Destination type. /// If set to true objectId is explicit. /// Partition to position to. /// Destination identifier. /// Timeout. /// Duration. public bool Locate16(out byte[] senseBuffer, bool immediate, bool changePartition, SscLogicalIdTypes destType, bool bam, byte partition, ulong identifier, uint timeout, out double duration) { senseBuffer = new byte[32]; byte[] cdb = new byte[16]; byte[] buffer = new byte[0]; bool sense; byte[] idBytes = BitConverter.GetBytes(identifier); cdb[0] = (byte)ScsiCommands.Locate16; cdb[1] = (byte)((byte)destType << 3); if (immediate) cdb[1] += 0x01; if (changePartition) cdb[1] += 0x02; if (bam) cdb[2] = 0x01; cdb[3] = partition; cdb[4] = idBytes[7]; cdb[5] = idBytes[6]; cdb[6] = idBytes[5]; cdb[7] = idBytes[4]; cdb[8] = idBytes[3]; cdb[9] = idBytes[2]; cdb[10] = idBytes[1]; cdb[11] = idBytes[0]; lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); error = lastError != 0; DicConsole.DebugWriteLine("SCSI Device", "LOCATE (16) took {0} ms.", duration); return sense; } /*/// /// Reads the specified number of blocks from the medium /// /// Buffer. /// Sense buffer. /// How many blocks to read. /// Block size in bytes. /// Timeout. /// Duration. public bool Read6(out byte[] buffer, out byte[] senseBuffer, uint blocks, uint blockSize, uint timeout, out double duration) { return Read6(out buffer, out senseBuffer, false, true, blocks, blockSize, timeout, out duration); }*/ /// /// Reads the specified number of bytes or of blocks from the medium /// /// Buffer. /// Sense buffer. /// If set to true suppress the incorrect-length indication. /// How many bytes to read. /// Block size in bytes. /// Timeout. /// Duration. public bool Read6(out byte[] buffer, out byte[] senseBuffer, bool sili, uint transferLen, uint blockSize, uint timeout, out double duration) { return Read6(out buffer, out senseBuffer, sili, false, transferLen, blockSize, timeout, out duration); } /// /// Reads the specified number of bytes or of blocks from the medium /// /// Buffer. /// Sense buffer. /// If set to true suppress the incorrect-length indication. Cannot be set while is set also. /// If set to true indicates how many blocks to read of a fixed size. /// Transfer length in blocks or bytes depending of status. /// Block size in bytes. /// Timeout. /// Duration. public bool Read6(out byte[] buffer, out byte[] senseBuffer, bool sili, bool fixedLen, uint transferLen, uint blockSize, uint timeout, out double duration) { if (fixedLen) buffer = new byte[blockSize * transferLen]; else buffer = new byte[transferLen]; byte[] cdb = new byte[6]; senseBuffer = new byte[32]; bool sense; cdb[0] = (byte)ScsiCommands.Read6; if (fixedLen) cdb[1] += 0x01; if (sili) cdb[1] += 0x02; cdb[2] = (byte)((transferLen & 0xFF0000) >> 16); cdb[3] = (byte)((transferLen & 0xFF00) >> 8); cdb[4] = (byte)(transferLen & 0xFF); 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; } /// /// Reads a number of fixed-length blocks starting at specified object /// /// Buffer. /// Sense buffer. /// If set to true suppress the incorrect-length indication. /// Object identifier. /// How many blocks to read. /// Object size in bytes. /// Timeout. /// Duration. public bool Read16(out byte[] buffer, out byte[] senseBuffer, bool sili, ulong objectId, uint blocks, uint blockSize, uint timeout, out double duration) { return Read16(out buffer, out senseBuffer, sili, false, 0, objectId, blocks, blockSize, timeout, out duration); } /// /// Reads a number of fixed-length blocks starting at specified block from the specified partition /// /// Buffer. /// Sense buffer. /// If set to true suppress the incorrect-length indication. /// Partition to read object from. /// Object identifier. /// How many blocks to read. /// Object size in bytes. /// Timeout. /// Duration. public bool Read16(out byte[] buffer, out byte[] senseBuffer, bool sili, byte partition, ulong objectId, uint blocks, uint blockSize, uint timeout, out double duration) { return Read16(out buffer, out senseBuffer, sili, false, partition, objectId, blocks, blockSize, timeout, out duration); } /// /// Reads a number of fixed-length blocks starting at specified object /// /// Buffer. /// Sense buffer. /// Object identifier. /// How many blocks to read. /// Object size in bytes. /// Timeout. /// Duration. public bool Read16(out byte[] buffer, out byte[] senseBuffer, ulong objectId, uint blocks, uint blockSize, uint timeout, out double duration) { return Read16(out buffer, out senseBuffer, false, true, 0, objectId, blocks, blockSize, timeout, out duration); } /// /// Reads a number of fixed-length blocks starting at specified block from the specified partition /// /// Buffer. /// Sense buffer. /// Partition to read object from. /// Object identifier. /// How many blocks to read. /// Object size in bytes. /// Timeout. /// Duration. public bool Read16(out byte[] buffer, out byte[] senseBuffer, byte partition, ulong objectId, uint blocks, uint blockSize, uint timeout, out double duration) { return Read16(out buffer, out senseBuffer, false, true, partition, objectId, blocks, blockSize, timeout, out duration); } /// /// Reads a number of bytes or objects starting at specified object from the specified partition /// /// Buffer. /// Sense buffer. /// If set to true suppress the incorrect-length indication. Cannot be set while is set also. /// If set to true indicates how many blocks to read of a fixed size. /// Partition to read object from. /// Object identifier. /// Transfer length in blocks or bytes depending of status. /// Object size in bytes. /// Timeout. /// Duration. public bool Read16(out byte[] buffer, out byte[] senseBuffer, bool sili, bool fixedLen, byte partition, ulong objectId, uint transferLen, uint objectSize, uint timeout, out double duration) { if (fixedLen) buffer = new byte[objectSize * transferLen]; else buffer = new byte[transferLen]; byte[] cdb = new byte[6]; senseBuffer = new byte[32]; bool sense; byte[] idBytes = BitConverter.GetBytes(objectId); cdb[0] = (byte)ScsiCommands.Read16; if (fixedLen) cdb[1] += 0x01; if (sili) cdb[1] += 0x02; cdb[3] = partition; cdb[4] = idBytes[7]; cdb[5] = idBytes[6]; cdb[6] = idBytes[5]; cdb[7] = idBytes[4]; cdb[8] = idBytes[3]; cdb[9] = idBytes[2]; cdb[10] = idBytes[1]; cdb[11] = idBytes[0]; cdb[12] = (byte)((transferLen & 0xFF0000) >> 16); cdb[13] = (byte)((transferLen & 0xFF00) >> 8); cdb[14] = (byte)(transferLen & 0xFF); 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; } /// /// Requests the drive the maximum and minimum block size /// /// Buffer. /// Sense buffer. /// Timeout. /// Duration. public bool ReadBlockLimits(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) { buffer = new byte[6]; byte[] cdb = new byte[6]; senseBuffer = new byte[32]; bool sense; cdb[0] = (byte)ScsiCommands.ReadBlockLimits; lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); error = lastError != 0; DicConsole.DebugWriteLine("SCSI Device", "READ BLOCK LIMITS took {0} ms.", duration); return sense; } /// /// Reports current reading/writing elements position on the medium /// /// Buffer. /// Sense buffer. /// Timeout. /// Duration. public bool ReadPosition(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) { return ReadPosition(out buffer, out senseBuffer, SscPositionForms.Short, timeout, out duration); } /// /// Reports current reading/writing elements position on the medium using 32 bytes response /// /// Buffer. /// Sense buffer. /// Timeout. /// Duration. public bool ReadPositionLong(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) { return ReadPosition(out buffer, out senseBuffer, SscPositionForms.Long, timeout, out duration); } /// /// Reports current reading/writing elements position on the medium /// /// Buffer. /// Sense buffer. /// Requests the position to be given in vendor-specified meaning. /// Requests the response to be 32 bytes format. /// Requests current logical position. /// Timeout. /// Duration. public bool ReadPosition(out byte[] buffer, out byte[] senseBuffer, bool vendorType, bool longForm, bool totalPosition, uint timeout, out double duration) { byte responseForm = 0; if (vendorType) responseForm += 0x01; if (longForm) responseForm += 0x02; if (totalPosition) responseForm += 0x04; return ReadPosition(out buffer, out senseBuffer, (SscPositionForms)responseForm, timeout, out duration); } /// /// Reports current reading/writing elements position on the medium /// /// Buffer. /// Sense buffer. /// Response form. /// Timeout. /// Duration. public bool ReadPosition(out byte[] buffer, out byte[] senseBuffer, SscPositionForms responseForm, uint timeout, out double duration) { switch (responseForm) { case SscPositionForms.Long: case SscPositionForms.OldLong: case SscPositionForms.OldLongTclpVendor: case SscPositionForms.OldLongVendor: case SscPositionForms.Extended: buffer = new byte[32]; break; case SscPositionForms.OldTclp: case SscPositionForms.OldTclpVendor: case SscPositionForms.Short: case SscPositionForms.VendorShort: buffer = new byte[20]; break; default: buffer = new byte[32]; // Invalid break; } byte[] cdb = new byte[10]; senseBuffer = new byte[32]; bool sense; cdb[0] = (byte)ScsiCommands.ReadPosition; cdb[1] = (byte)((byte)responseForm & 0x1F); if(responseForm == SscPositionForms.Extended) { cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[8] = (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 POSITION took {0} ms.", duration); return sense; } /// /// Reads the specified number of blocks from the medium, backwards /// /// Buffer. /// Sense buffer. /// How many blocks to read. /// Block size in bytes. /// Timeout. /// Duration. public bool ReadReverse6(out byte[] buffer, out byte[] senseBuffer, uint blocks, uint blockSize, uint timeout, out double duration) { return ReadReverse6(out buffer, out senseBuffer, false, false, true, blocks, blockSize, timeout, out duration); } /// /// Reads the specified number of bytes or of blocks from the medium, backwards /// /// Buffer. /// Sense buffer. /// If set to true suppress the incorrect-length indication. /// How many bytes to read. /// Block size in bytes. /// Timeout. /// Duration. public bool ReadReverse6(out byte[] buffer, out byte[] senseBuffer, bool sili, uint transferLen, uint blockSize, uint timeout, out double duration) { return ReadReverse6(out buffer, out senseBuffer, false, sili, false, transferLen, blockSize, timeout, out duration); } /// /// Reads the specified number of bytes or of blocks from the medium, backwards /// /// Buffer. /// Sense buffer. /// If set to true drive should un-reverse the blocks and bytes /// If set to true suppress the incorrect-length indication. Cannot be set while is set also. /// If set to true indicates how many blocks to read of a fixed size. /// Transfer length in blocks or bytes depending of status. /// Block size in bytes. /// Timeout. /// Duration. public bool ReadReverse6(out byte[] buffer, out byte[] senseBuffer, bool byteOrder, bool sili, bool fixedLen, uint transferLen, uint blockSize, uint timeout, out double duration) { if (fixedLen) buffer = new byte[blockSize * transferLen]; else buffer = new byte[transferLen]; byte[] cdb = new byte[6]; senseBuffer = new byte[32]; bool sense; cdb[0] = (byte)ScsiCommands.ReadReverse; if (fixedLen) cdb[1] += 0x01; if (sili) cdb[1] += 0x02; if (byteOrder) cdb[1] += 0x04; cdb[2] = (byte)((transferLen & 0xFF0000) >> 16); cdb[3] = (byte)((transferLen & 0xFF00) >> 8); cdb[4] = (byte)(transferLen & 0xFF); lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); error = lastError != 0; DicConsole.DebugWriteLine("SCSI Device", "READ REVERSE (6) took {0} ms.", duration); return sense; } /// /// Reads a number of fixed-length blocks starting at specified object, backwards /// /// Buffer. /// Sense buffer. /// If set to true suppress the incorrect-length indication. /// Object identifier. /// How many blocks to read. /// Object size in bytes. /// Timeout. /// Duration. public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, bool sili, ulong objectId, uint blocks, uint blockSize, uint timeout, out double duration) { return ReadReverse16(out buffer, out senseBuffer, false, sili, false, 0, objectId, blocks, blockSize, timeout, out duration); } /// /// Reads a number of fixed-length blocks starting at specified block from the specified partition, backwards /// /// Buffer. /// Sense buffer. /// If set to true suppress the incorrect-length indication. /// Partition to read object from. /// Object identifier. /// How many blocks to read. /// Object size in bytes. /// Timeout. /// Duration. public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, bool sili, byte partition, ulong objectId, uint blocks, uint blockSize, uint timeout, out double duration) { return ReadReverse16(out buffer, out senseBuffer, false, sili, false, partition, objectId, blocks, blockSize, timeout, out duration); } /// /// Reads a number of fixed-length blocks starting at specified object, backwards /// /// Buffer. /// Sense buffer. /// Object identifier. /// How many blocks to read. /// Object size in bytes. /// Timeout. /// Duration. public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, ulong objectId, uint blocks, uint blockSize, uint timeout, out double duration) { return ReadReverse16(out buffer, out senseBuffer, false, false, true, 0, objectId, blocks, blockSize, timeout, out duration); } /// /// Reads a number of fixed-length blocks starting at specified block from the specified partition, backwards /// /// Buffer. /// Sense buffer. /// Partition to read object from. /// Object identifier. /// How many blocks to read. /// Object size in bytes. /// Timeout. /// Duration. public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, byte partition, ulong objectId, uint blocks, uint blockSize, uint timeout, out double duration) { return ReadReverse16(out buffer, out senseBuffer, false, false, true, partition, objectId, blocks, blockSize, timeout, out duration); } /// /// Reads a number of bytes or objects starting at specified object from the specified partition, backwards /// /// Buffer. /// Sense buffer. /// If set to true drive should un-reverse the blocks and bytes /// If set to true suppress the incorrect-length indication. Cannot be set while is set also. /// If set to true indicates how many blocks to read of a fixed size. /// Partition to read object from. /// Object identifier. /// Transfer length in blocks or bytes depending of status. /// Object size in bytes. /// Timeout. /// Duration. public bool ReadReverse16(out byte[] buffer, out byte[] senseBuffer, bool byteOrder, bool sili, bool fixedLen, byte partition, ulong objectId, uint transferLen, uint objectSize, uint timeout, out double duration) { if (fixedLen) buffer = new byte[objectSize * transferLen]; else buffer = new byte[transferLen]; byte[] cdb = new byte[6]; senseBuffer = new byte[32]; bool sense; byte[] idBytes = BitConverter.GetBytes(objectId); cdb[0] = (byte)ScsiCommands.Read16; if (fixedLen) cdb[1] += 0x01; if (sili) cdb[1] += 0x02; if (byteOrder) cdb[1] += 0x04; cdb[3] = partition; cdb[4] = idBytes[7]; cdb[5] = idBytes[6]; cdb[6] = idBytes[5]; cdb[7] = idBytes[4]; cdb[8] = idBytes[3]; cdb[9] = idBytes[2]; cdb[10] = idBytes[1]; cdb[11] = idBytes[0]; cdb[12] = (byte)((transferLen & 0xFF0000) >> 16); cdb[13] = (byte)((transferLen & 0xFF00) >> 8); cdb[14] = (byte)(transferLen & 0xFF); lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); error = lastError != 0; DicConsole.DebugWriteLine("SCSI Device", "READ REVERSE (16) took {0} ms.", duration); return sense; } /// /// Reads the specified number of blocks from the device's buffer /// /// Buffer. /// Sense buffer. /// How many blocks to read. /// Block size in bytes. /// Timeout. /// Duration. public bool RecoverBufferedData(out byte[] buffer, out byte[] senseBuffer, uint blocks, uint blockSize, uint timeout, out double duration) { return RecoverBufferedData(out buffer, out senseBuffer, false, true, blocks, blockSize, timeout, out duration); } /// /// Reads the specified number of bytes or of blocks from the device's buffer /// /// Buffer. /// Sense buffer. /// If set to true suppress the incorrect-length indication. /// How many bytes to read. /// Block size in bytes. /// Timeout. /// Duration. public bool RecoverBufferedData(out byte[] buffer, out byte[] senseBuffer, bool sili, uint transferLen, uint blockSize, uint timeout, out double duration) { return RecoverBufferedData(out buffer, out senseBuffer, sili, false, transferLen, blockSize, timeout, out duration); } /// /// Reads the specified number of bytes or of blocks from the device's buffer /// /// Buffer. /// Sense buffer. /// If set to true suppress the incorrect-length indication. Cannot be set while is set also. /// If set to true indicates how many blocks to read of a fixed size. /// Transfer length in blocks or bytes depending of status. /// Block size in bytes. /// Timeout. /// Duration. public bool RecoverBufferedData(out byte[] buffer, out byte[] senseBuffer, bool sili, bool fixedLen, uint transferLen, uint blockSize, uint timeout, out double duration) { if (fixedLen) buffer = new byte[blockSize * transferLen]; else buffer = new byte[transferLen]; byte[] cdb = new byte[6]; senseBuffer = new byte[32]; bool sense; cdb[0] = (byte)ScsiCommands.RecoverBufferedData; if (fixedLen) cdb[1] += 0x01; if (sili) cdb[1] += 0x02; cdb[2] = (byte)((transferLen & 0xFF0000) >> 16); cdb[3] = (byte)((transferLen & 0xFF00) >> 8); cdb[4] = (byte)(transferLen & 0xFF); lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); error = lastError != 0; DicConsole.DebugWriteLine("SCSI Device", "RECOVER BUFFERED DATA took {0} ms.", duration); return sense; } /// /// Requests the device to return descriptors for supported densities or medium types /// /// Buffer. /// Sense buffer. /// Timeout. /// Duration. public bool ReportDensitySupport(out byte[] buffer, out byte[] senseBuffer, uint timeout, out double duration) { return ReportDensitySupport(out buffer, out senseBuffer, false, false, timeout, out duration); } /// /// Requests the device to return descriptors for supported densities or medium types /// /// Buffer. /// Sense buffer. /// If set to true descriptors should apply to currently inserted media. /// Timeout. /// Duration. public bool ReportDensitySupport(out byte[] buffer, out byte[] senseBuffer, bool currentMedia, uint timeout, out double duration) { return ReportDensitySupport(out buffer, out senseBuffer, false, currentMedia, timeout, out duration); } /// /// Requests the device to return descriptors for supported densities or medium types /// /// Buffer. /// Sense buffer. /// If set to true descriptors should be about medium types. /// If set to true descriptors should apply to currently inserted media. /// Timeout. /// Duration. public bool ReportDensitySupport(out byte[] buffer, out byte[] senseBuffer, bool mediumType, bool currentMedia, uint timeout, out double duration) { buffer = new byte[256]; byte[] cdb = new byte[10]; senseBuffer = new byte[32]; bool sense; cdb[0] = (byte)ScsiCommands.ReportDensitySupport; if (mediumType) cdb[1] += 0x01; if (currentMedia) cdb[1] += 0x02; cdb[7] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[8] = (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; ushort availableLength = (ushort)(((int)buffer[0] << 8) + buffer[1] + 2); buffer = new byte[availableLength]; 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", "REPORT DENSITY SUPPORT took {0} ms.", duration); return sense; } /// /// Positions the reading/writing element to the beginning of current partition /// /// Sense buffer. /// Timeout. /// Duration. public bool Rewind(out byte[] senseBuffer, uint timeout, out double duration) { return Rewind(out senseBuffer, false, timeout, out duration); } /// /// Positions the reading/writing element to the beginning of current partition /// /// Sense buffer. /// If set to true return from the command immediately. /// Timeout. /// Duration. public bool Rewind(out byte[] senseBuffer, bool immediate, 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.Rewind; if (immediate) cdb[1] += 0x01; lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); error = lastError != 0; DicConsole.DebugWriteLine("SCSI Device", "REWIND took {0} ms.", duration); return sense; } /// /// Selects the specified track /// /// true, if select was tracked, false otherwise. /// Sense buffer. /// Track. /// Timeout. /// Duration. public bool TrackSelect(out byte[] senseBuffer, byte track, 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.TrackSelect; cdb[5] = track; lastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.None, out duration, out sense); error = lastError != 0; DicConsole.DebugWriteLine("SCSI Device", "TRACK SELECT took {0} ms.", duration); return sense; } } }