Click here to Skip to main content
15,895,256 members
Articles / Programming Languages / C#

SCSI Library in C# - Burn CDs and DVDs, Access Hard Disks, etc.

Rate me:
Please Sign up or sign in to vote.
4.77/5 (48 votes)
19 Jun 2017Ms-PL6 min read 146.2K   8.1K   146  
Ever wonder how programs like Nero work? They make their own SCSI libraries... like this!
using System.Runtime.InteropServices;
using System.Diagnostics;
using System;
using SCSI.Multimedia;
using Helper;
namespace SCSI
{
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public abstract class SCSICommand : IMarshalable
	{
		protected SCSICommand(OpCode opCode) : base() { this.OpCode = opCode; }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		internal OpCode _OpCode;  //Internal so we can pin it
		public OpCode OpCode { get { return this._OpCode; } set { this._OpCode = value; } }
		public abstract Control Control { get; set; }

		public override string ToString() { /*return this.OpCode.ToString();*/ return Internal.GenericToString(this, true); }
		
		protected virtual void MarshalFrom(BufferWithSize buffer) { Marshaler.DefaultPtrToStructure(buffer, this); }
		protected virtual void MarshalTo(BufferWithSize buffer) { Marshaler.DefaultStructureToPtr((object)this, buffer); }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		protected virtual int MarshaledSize { get { return Marshal.SizeOf(this); } }

		void IMarshalable.MarshalFrom(BufferWithSize buffer) { this.MarshalFrom(buffer); }
		void IMarshalable.MarshalTo(BufferWithSize buffer) { this.MarshalTo(buffer); }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		int IMarshalable.MarshaledSize { get { return this.MarshaledSize; } }

		public static SCSICommand CreateInstance(OpCode opCode)
		{
			var result = TryCreateInstance(opCode);
			if (result == null) { throw new ArgumentOutOfRangeException("opCode", opCode, "Unsupported OpCode."); }
			return result;
		}

		public static SCSICommand TryCreateInstance(OpCode opCode)
		{
			SCSICommand result;
			switch (opCode)
			{
				case OpCode.Blank:
					result = new BlankCommand();
					break;
				case OpCode.CloseSessionOrTrack:
					result = new CloseSessionOrTrackCommand();
					break;
				case OpCode.Erase10:
					result = new Erase10Command();
					break;
				case OpCode.FormatUnit:
					result = new FormatUnitCommand();
					break;
				case OpCode.GetConfiguration:
					result = new GetConfigurationCommand();
					break;
				case OpCode.GetEventStatusNotification:
					result = new GetEventStatusNotificationCommand();
					break;
				case OpCode.GetPerformance:
					result = new GetPerformanceCommand();
					break;
				case OpCode.Inquiry:
					result = new InquiryCommand();
					break;
				case OpCode.LoadUnloadMedium:
					result = new LoadUnloadMediumCommand();
					break;
				case OpCode.ModeSelect10:
					result = new ModeSelect10Command();
					break;
				case OpCode.ModeSense10:
					result = new ModeSense10Command();
					break;
				case OpCode.PreventAllowMediumRemoval:
					result = new PreventAllowMediumRemovalCommand();
					break;
				case OpCode.Read10:
					result = new Read10Command();
					break;
				case OpCode.Read12:
					result = new Read12Command();
					break;
				case OpCode.ReadBuffer:
					result = new ReadBufferCommand();
					break;
				case OpCode.ReadBufferCapacity:
					result = new ReadBufferCapacityCommand();
					break;
				case OpCode.ReadCapacity:
					result = new ReadCapacityCommand();
					break;
				case OpCode.ReadCD:
					result = new ReadCDCommand();
					break;
				case OpCode.ReadDiscInformation:
					result = new ReadDiscInformationCommand();
					break;
				case OpCode.ReadFormatCapacities:
					result = new ReadFormatCapacitiesCommand();
					break;
				case OpCode.ReadTrackInformation:
					result = new ReadTrackInformationCommand();
					break;
				case OpCode.Receive:
					result = new ReceiveCommand();
					break;
				case OpCode.ReportKey:
					result = new ReportKeyCommand();
					break;
				case OpCode.RequestSense:
					result = new RequestSenseCommand();
					break;
				case OpCode.ReserveTrack:
					result = new ReserveTrackCommand();
					break;
				case OpCode.Seek10:
					result = new Seek10Command();
					break;
				case OpCode.SendDiagnostic:
					result = new SendDiagnosticCommand();
					break;
				case OpCode.SendOPCInformation:
					result = new SendOPCInformationCommand();
					break;
				case OpCode.SetCDSpeed:
					result = new SetCDSpeedCommand();
					break;
				case OpCode.SetReadAhead:
					result = new SetReadAheadCommand();
					break;
				case OpCode.SetRemovableMediaBit:
					result = new SetRemovableMediaBitCommand();
					break;
				case OpCode.SetStreaming:
					result = new SetStreamingCommand();
					break;
				case OpCode.StartStopUnit:
					result = new StartStopUnitCommand();
					break;
				case OpCode.SynchronizeCache10:
					result = new SynchronizeCache10Command();
					break;
				case OpCode.TestUnitReady:
					result = new TestUnitReadyCommand();
					break;
				case OpCode.Verify10:
					result = new Verify10Command();
					break;
				case OpCode.Write10:
					result = new Write10Command();
					break;
				case OpCode.Write12:
					result = new Write12Command();
					break;
				case OpCode.WriteBuffer:
					result = new WriteBufferCommand();
					break;
				default:
					result = null;
					break;
			}
			return result;
		}

		public static SCSICommand FromBuffer(IntPtr pBuffer, int bufferLength)
		{
			var buffer = new BufferWithSize(pBuffer, bufferLength);
			var instance = CreateInstance(buffer.Read<OpCode>());
			Marshaler.PtrToStructure(buffer, ref instance);
			return instance;
		}

		public static SCSICommand TryFromBuffer(IntPtr pBuffer, int bufferLength)
		{
			var buffer = new BufferWithSize(pBuffer, bufferLength);
			var instance = TryCreateInstance(buffer.Read<OpCode>());
			if (instance != null) { Marshaler.PtrToStructure(buffer, ref instance); }
			return instance;
		}

		public static OpCode ReadOpCode(IntPtr pCDB, int cdbLength) { return new BufferWithSize(pCDB, cdbLength).Read<OpCode>(); }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class InquiryCommand : SCSICommand
	{
		public InquiryCommand() : base(OpCode.Inquiry) { }
		public InquiryCommand(VitalProductDataPageCode? pageCode) : this() { this.PageCode = pageCode; }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		/// <summary>If <c>false</c>, the <see cref="PageCode"/> property must not be set.</summary>
		private bool EVitalProductData { get { return this.byte1[0]; } set { this.byte1[0] = value; } }
		public bool CommandSupportData { get { return this.byte1[1]; } set { this.byte1[1] = value; } }
		private VitalProductDataPageCode _PageCode;
		public VitalProductDataPageCode? PageCode { get { return this.EVitalProductData ? (VitalProductDataPageCode?)this._PageCode : null; } set { this.EVitalProductData = value.HasValue; this._PageCode = value.GetValueOrDefault(); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _AllocationLength;
		internal ushort AllocationLength { get { return Bits.FromBigEndian(this._AllocationLength); } set { this._AllocationLength = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}
	
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class ModeSelect10Command : SCSICommand
	{
		public ModeSelect10Command() : base(OpCode.ModeSelect10) { this.PageFormat = true; }
		public ModeSelect10Command(bool savePages, bool pageFormat)
			: this()
		{
			this.SavePages = savePages;
			this.PageFormat = pageFormat;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		public bool SavePages { get { return this.byte1[0]; } set { this.byte1[0] = value; } }
		/// <summary>Indicates whether or not the commands are as defined in the SPC-2 standard.</summary>
		public bool PageFormat { get { return this.byte1[4]; } set { this.byte1[4] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte2;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte3;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte4;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte5;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte6;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _ParameterListLength;
		internal ushort ParameterListLength { get { return Bits.FromBigEndian(this._ParameterListLength); } set { this._ParameterListLength = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;

		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class ModeSense10Command : SCSICommand
	{
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private const byte PAGE_CODE_MASK = 0x3F;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private const byte PAGE_CONTROL_MASK = 0xC0;

		public ModeSense10Command() : base(OpCode.ModeSense10) { this.DisableBlockDescriptors = true; this.PageControl = PageControl.CurrentValues; }

		public ModeSense10Command(PageControl pageControl) : this() { this.PageControl = pageControl; }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		public bool DisableBlockDescriptors { get { return this.byte1[3]; } set { this.byte1[3] = value; } }
		public bool LongLBAAccepted { get { return this.byte1[4]; } set { this.byte1[4] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte2;
		internal byte PageCode
		{
			get { return Bits.ExtractValueMask((byte)this.byte2, 0, PAGE_CODE_MASK); }
			set { this.byte2 = Bits.PutValueMask((byte)this.byte2, (byte)value, 0, PAGE_CODE_MASK); }
		}
		public PageControl PageControl
		{
			get { return (PageControl)Bits.ExtractValueMask((byte)this.byte2, 6, PAGE_CONTROL_MASK); }
			set { this.byte2 = Bits.PutValueMask((byte)this.byte2, (byte)value, 6, PAGE_CONTROL_MASK); }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte3;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte4;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte5;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte6;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _AllocationLength;
		internal ushort AllocationLength { get { return Bits.FromBigEndian(this._AllocationLength); } set { this._AllocationLength = Bits.ToBigEndian(value); } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class Read10Command : SCSICommand
	{
		private static readonly byte GROUP_NUMBER_MASK = 0x1F;

		public Read10Command() : base(OpCode.Read10) { }

		public Read10Command(bool forceUnitAccess, uint lba, ushort transferLength)
			: this()
		{
			this.ForceUnitAccess = forceUnitAccess;
			this.LBA = lba;
			this.TransferLength = transferLength;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		public bool DisablePageOut { get { return this.byte1[4]; } set { this.byte1[4] = value; } }
		public bool ForceUnitAccess { get { return this.byte1[3]; } set { this.byte1[3] = value; } }
		/// <summary>Must be zero.</summary>
		public bool RelativeAddress { get { return this.byte1[0]; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _LBA;
		public uint LBA { get { return Bits.FromBigEndian(this._LBA); } set { this._LBA = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte6;
		public byte GroupNumber { get { return Bits.ExtractValueMask((byte)this.byte6, 0, GROUP_NUMBER_MASK); } set { this.byte6 = Bits.PutValueMask((byte)this.byte6, (byte)value, 0, GROUP_NUMBER_MASK); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _TransferLength;
		/// <summary>
		/// The Transfer Length field specifies the number of contiguous logical blocks of data that shall be transferred.
		/// A Transfer Length of zero indicates that no logical blocks shall be transferred.
		/// This condition shall not be considered an error.
		/// Any other value indicates the number of logical blocks that shall be transferred.
		/// </summary>
		public ushort TransferLength { get { return Bits.FromBigEndian(this._TransferLength); } set { this._TransferLength = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;

		public override Control Control { get { return this._Control; } set { this._Control = value; } }

		protected override int MarshaledSize { get { return 0x0A; } } //Faster than computing
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class Read12Command : SCSICommand
	{
		private static readonly byte GROUP_NUMBER_MASK = 0x1F;

		public Read12Command() : base(OpCode.Read12) { }

		public Read12Command(bool forceUnitAccess, uint lba, uint transferLength, bool streaming)
			: this()
		{
			this.ForceUnitAccess = forceUnitAccess;
			this.LBA = lba;
			this.TransferLength = transferLength;
			this.Streaming = streaming;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		public bool DisablePageOut { get { return this.byte1[4]; } set { this.byte1[4] = value; } }
		public bool ForceUnitAccess { get { return this.byte1[3]; } set { this.byte1[3] = value; } }
		/// <summary>Must be zero.</summary>
		public bool RelativeAddress { get { return this.byte1[0]; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _LBA;
		public uint LBA { get { return Bits.FromBigEndian(this._LBA); } set { this._LBA = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _TransferLength;
		/// <summary>
		/// The Transfer Length field specifies the number of contiguous logical blocks of data that shall be transferred.
		/// A Transfer Length of zero indicates that no logical blocks shall be transferred.
		/// This condition shall not be considered an error.
		/// Any other value indicates the number of logical blocks that shall be transferred.
		/// </summary>
		public uint TransferLength { get { return Bits.FromBigEndian(this._TransferLength); } set { this._TransferLength = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte10;
		public byte GroupNumber { get { return Bits.ExtractValueMask((byte)this.byte10, 0, GROUP_NUMBER_MASK); } set { this.byte10 = Bits.PutValueMask((byte)this.byte10, (byte)value, 0, GROUP_NUMBER_MASK); } }
		public bool Streaming { get { return this.byte10[7]; } set { this.byte10[7] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;

		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class Read16Command : SCSICommand
	{
		private static readonly byte GROUP_NUMBER_MASK = 0x1F;

		public Read16Command() : base(OpCode.Read16) { }

		public Read16Command(bool forceUnitAccess, ulong lba, uint transferLength, bool streaming)
			: this()
		{
			this.ForceUnitAccess = forceUnitAccess;
			this.LBA = lba;
			this.TransferLength = transferLength;
			this.Streaming = streaming;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		public bool DisablePageOut { get { return this.byte1[4]; } set { this.byte1[4] = value; } }
		public bool ForceUnitAccess { get { return this.byte1[3]; } set { this.byte1[3] = value; } }
		/// <summary>Must be zero.</summary>
		public bool RelativeAddress { get { return this.byte1[0]; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ulong _LBA;
		public ulong LBA { get { return Bits.FromBigEndian(this._LBA); } set { this._LBA = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _TransferLength;
		/// <summary>
		/// The Transfer Length field specifies the number of contiguous logical blocks of data that shall be transferred.
		/// A Transfer Length of zero indicates that no logical blocks shall be transferred.
		/// This condition shall not be considered an error.
		/// Any other value indicates the number of logical blocks that shall be transferred.
		/// </summary>
		public uint TransferLength { get { return Bits.FromBigEndian(this._TransferLength); } set { this._TransferLength = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte10;
		public byte GroupNumber { get { return Bits.ExtractValueMask((byte)this.byte10, 0, GROUP_NUMBER_MASK); } set { this.byte10 = Bits.PutValueMask((byte)this.byte10, (byte)value, 0, GROUP_NUMBER_MASK); } }
		public bool Streaming { get { return this.byte10[7]; } set { this.byte10[7] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;

		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class Read32Command : SCSICommand
	{
		private static readonly byte GROUP_NUMBER_MASK = 0x1F;

		public Read32Command() : base(OpCode.Read32) { }

		public Read32Command(bool forceUnitAccess, ulong lba, uint transferLength)
			: this()
		{
			this.ForceUnitAccess = forceUnitAccess;
			this.LBA = lba;
			this.TransferLength = transferLength;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private byte byte2;
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private byte byte3;
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private byte byte4;
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private byte byte5;
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private BitVector8 byte6;
		public byte GroupNumber { get { return Bits.ExtractValueMask((byte)this.byte6, 0, GROUP_NUMBER_MASK); } set { this.byte6 = Bits.PutValueMask((byte)this.byte6, (byte)value, 0, GROUP_NUMBER_MASK); } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private byte _AdditionalCDBLength = Bits.ReverseBytes((byte)0x18);
		public byte AdditionalCDBLength { get { return this._AdditionalCDBLength; } set { this._AdditionalCDBLength = value; } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private ServiceAction _ServiceAction = Bits.ReverseBytes(ServiceAction.Read32);
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte10;
		public bool DisablePageOut { get { return this.byte10[4]; } set { this.byte10[4] = value; } }
		public bool ForceUnitAccess { get { return this.byte10[3]; } set { this.byte10[3] = value; } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private byte byte11;
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private ulong _LBA;
		public ulong LBA { get { return Bits.ReverseBytes(this._LBA); } set { this._LBA = Bits.ReverseBytes(value); } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private uint _ExpectedInitialLogicalBlockReferenceTag;
		public uint ExpectedInitialLogicalBlockReferenceTag { get { return Bits.ReverseBytes(this._ExpectedInitialLogicalBlockReferenceTag); } set { this._ExpectedInitialLogicalBlockReferenceTag = Bits.ReverseBytes(value); } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private ushort _ExpectedLogicalBlockApplicationTag;
		public ushort ExpectedLogicalBlockApplicationTag { get { return Bits.ReverseBytes(this._ExpectedLogicalBlockApplicationTag); } set { this._ExpectedLogicalBlockApplicationTag = Bits.ReverseBytes(value); } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private ushort _LogicalBlockApplicationTagMask;
		public ushort LogicalBlockApplicationTagMask { get { return Bits.ReverseBytes(this._LogicalBlockApplicationTagMask); } set { this._LogicalBlockApplicationTagMask = Bits.ReverseBytes(value); } }
		[DebuggerBrowsableAttribute(DebuggerBrowsableState.Never)]
		private uint _TransferLength;
		public uint TransferLength { get { return Bits.ReverseBytes(this._TransferLength); } set { this._TransferLength = Bits.ReverseBytes(value); } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class ReadBufferCommand : SCSICommand
	{
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private const byte MODE_MASK = 0x1F;
		public ReadBufferCommand() : base(OpCode.ReadBuffer) { }
		public ReadBufferCommand(byte bufferID, uint offset) : this() { this.BufferID = bufferID; this.BufferOffset = offset; }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte1;
		internal ReadBufferMode Mode
		{
			get { return (ReadBufferMode)Bits.ExtractValueMask((byte)this.byte1, 0, MODE_MASK); }
			set { this.byte1 = Bits.PutValueMask((byte)this.byte1, (byte)value, 0, MODE_MASK); }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _BufferID;
		public byte BufferID { get { return this._BufferID; } set { this._BufferID = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte3; //MSB
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte4;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte5; //LSB
		public uint BufferOffset
		{
			get { unchecked { return (uint)this._byte5 | ((uint)this._byte4 << 8) | ((uint)this._byte3 << 16); } }
			set { unchecked { this._byte5 = (byte)(value >> 0); this._byte4 = (byte)(value >> 8); this._byte3 = (byte)(value >> 16); } }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte6; //MSB
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte7;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte8; //LSB
		internal uint AllocationLength
		{
			get { unchecked { return (uint)this._byte8 | ((uint)this._byte7 << 8) | ((uint)this._byte6 << 16); } }
			set { unchecked { this._byte8 = (byte)(value >> 0); this._byte7 = (byte)(value >> 8); this._byte6 = (byte)(value >> 16); } }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class ReadCapacityCommand : SCSICommand
	{
		public ReadCapacityCommand() : base(OpCode.ReadCapacity) { }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte0;
		/// <summary>Must be zero.</summary>
		public bool RelativeAddress { get { return this.byte0[0]; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _LBA;
		/// <summary>Should be zero.</summary>
		public uint LBA { get { return Bits.FromBigEndian(this._LBA); } set { this._LBA = Bits.ToBigEndian(value); } }
		private byte byte6;
		private byte byte7;
		private BitVector8 byte8;
		/// <summary>Should be zero.</summary>
		public bool PMI { get { return this.byte8[0]; } set { this.byte8[0] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;

		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class ReceiveCommand : SCSICommand
	{
		public ReceiveCommand() : base(OpCode.Receive) { }
		public ReceiveCommand(uint transferLength) : this() { this.TransferLength = transferLength; }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte1;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte2; //MSB
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte3;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte4; //LSB
		public uint TransferLength
		{
			get { unchecked { return (uint)this._byte4 | ((uint)this._byte3 << 8) | ((uint)this._byte2 << 16); } }
			set { unchecked { this._byte4 = (byte)(value >> 0); this._byte3 = (byte)(value >> 8); this._byte2 = (byte)(value >> 16); } }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class RequestSenseCommand : SCSICommand
	{
		public RequestSenseCommand() : base(OpCode.RequestSense) { }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte1;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte2;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte3;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _AllocationLength;
		internal byte AllocationLength { get { return this._AllocationLength; } set { this._AllocationLength = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class ReportDeviceIdentifierCommand : SCSICommand
	{
		private const byte SERVICE_ACTION_MASK = 0x1F;
		public ReportDeviceIdentifierCommand() : base(OpCode.ModeSense10) { this.ServiceAction = 0x05; }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		public byte ServiceAction
		{
			get { return (byte)Bits.ExtractValueMask((byte)this.byte1, 0, SERVICE_ACTION_MASK); }
			set { this.byte1 = Bits.PutValueMask((byte)this.byte1, (byte)value, 0, SERVICE_ACTION_MASK); }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte2;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte3;
		public byte RestrictedByte4;
		public byte RestrictedByte5;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _AllocationLength;
		internal uint AllocationLength { get { return Bits.FromBigEndian(this._AllocationLength); } set { this._AllocationLength = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte10;
		public bool RestrictedByte10Bit1 { get { return this.byte10[1]; } set { this.byte10[1] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class Seek10Command : SCSICommand
	{
		public Seek10Command() : base(OpCode.Seek10) { }
		public Seek10Command(uint lba) : this() { this.LBA = lba; }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte1;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _LBA;
		public uint LBA { get { return Bits.FromBigEndian(this._LBA); } set { this._LBA = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte6;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte7;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte8;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class SendDiagnosticCommand : SCSICommand
	{
		private const byte SELF_TEST_CODE_MASK = 0xE0;
		public SendDiagnosticCommand() : base(OpCode.SendDiagnostic) { }
		public SendDiagnosticCommand(SelfTestCode? selfTestCode, bool unitOffline, bool deviceOffline)
			: this()
		{
			this.SelfTestCode = selfTestCode;
			this.UnitOffline = unitOffline;
			this.DeviceOffline = deviceOffline;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		public SelfTestCode? SelfTestCode
		{
			get { return this.SelfTest ? (SelfTestCode?)Bits.ExtractValueMask((byte)this.byte1, 5, SELF_TEST_CODE_MASK) : null; }
			set
			{
				this.byte1 = Bits.PutValueMask((byte)this.byte1, (byte)value.GetValueOrDefault(), 5, SELF_TEST_CODE_MASK);
				this.SelfTest = !value.HasValue;
			}
		}
		public bool PageFormat { get { return this.byte1[4]; } set { this.byte1[4] = value; } }
		private bool SelfTest { get { return this.byte1[2]; } set { this.byte1[2] = value; } }
		public bool UnitOffline { get { return this.byte1[1]; } set { this.byte1[1] = value; } }
		public bool DeviceOffline { get { return this.byte1[0]; } set { this.byte1[0] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte2;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _ParameterListLength;
		internal ushort ParameterListLength { get { return Bits.FromBigEndian(this._ParameterListLength); } set { this._ParameterListLength = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class SetRemovableMediaBitCommand : SCSICommand
	{
		public SetRemovableMediaBitCommand() : base(OpCode.SetRemovableMediaBit) { }
		public SetRemovableMediaBitCommand(bool removable) : this() { this.RemovableBit = removable; }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte1 = 0x03;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte2;
		public bool RemovableBit { get { return this.byte2[0]; } set { this.byte2[0] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class SynchronizeCache10Command : SCSICommand
	{
		public SynchronizeCache10Command() : base(OpCode.SynchronizeCache10) { }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		public bool Immediate { get { return this.byte1[1]; } set { this.byte1[1] = value; } }
		/// <summary>Must be zero.</summary>
		public bool RelativeAddress { get { return this.byte1[0]; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _LogicalBlockAddress;
		public uint LogicalBlockAddress { get { return Bits.FromBigEndian(this._LogicalBlockAddress); } set { this._LogicalBlockAddress = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte6;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _NumBlocks;
		public ushort NumBlocks { get { return Bits.FromBigEndian(this._NumBlocks); } set { this._NumBlocks = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class TestUnitReadyCommand : SCSICommand
	{
		public TestUnitReadyCommand() : base(OpCode.TestUnitReady) { }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte1;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte2;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte3;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte4;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;

		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class Write10Command : SCSICommand
	{
		public Write10Command() : base(OpCode.Write10) { }

		public Write10Command(bool forceUnitAccess, uint lba)
			: this() { this.ForceUnitAccess = forceUnitAccess; this.LBA = lba; }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		/// <summary>Must be zero.</summary>
		public bool DisablePageOut { get { return this.byte1[4]; } }
		public bool ForceUnitAccess { get { return this.byte1[3]; } set { this.byte1[3] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _LBA;
		public uint LBA { get { return Bits.FromBigEndian(this._LBA); } set { this._LBA = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte6;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private ushort _TransferLength;
		internal ushort TransferLength { get { return Bits.FromBigEndian(this._TransferLength); } set { this._TransferLength = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;

		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class Write12Command : SCSICommand
	{
		public Write12Command() : base(OpCode.Write12) { }

		public Write12Command(bool forceUnitAccess, uint lba, bool streaming)
			: this()
		{
			this.ForceUnitAccess = forceUnitAccess;
			this.LBA = lba;
			this.Streaming = streaming;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte1;
		/// <summary>Must be zero.</summary>
		public bool DisablePageOut { get { return this.byte1[4]; } }
		public bool ForceUnitAccess { get { return this.byte1[3]; } set { this.byte1[3] = value; } }
		public bool TimelySafeRecording { get { return this.byte1[2]; } set { this.byte1[2] = value; } }
		/// <summary>Must be zero.</summary>
		public bool RelativeAddress { get { return this.byte1[0]; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _LBA;
		public uint LBA { get { return Bits.FromBigEndian(this._LBA); } set { this._LBA = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private uint _TransferLength;
		internal uint TransferLength { get { return Bits.FromBigEndian(this._TransferLength); } set { this._TransferLength = Bits.ToBigEndian(value); } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private BitVector8 byte10;
		public bool Streaming { get { return this.byte10[7]; } set { this.byte10[7] = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;

		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public class WriteBufferCommand : SCSICommand
	{
		private const byte MODE_MASK = 0x1F;
		public WriteBufferCommand() : base(OpCode.WriteBuffer) { }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte byte1;
		public WriteBufferMode Mode
		{
			get { return (WriteBufferMode)Bits.ExtractValueMask((byte)this.byte1, 0, MODE_MASK); }
			set { this.byte1 = Bits.PutValueMask((byte)this.byte1, (byte)value, 0, MODE_MASK); }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _BufferID;
		public byte BufferID { get { return this._BufferID; } set { this._BufferID = value; } }
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte3; //MSB
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte4;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte5; //LSB
		public uint BufferOffset
		{
			get { unchecked { return (uint)this._byte5 | ((uint)this._byte4 << 8) | ((uint)this._byte3 << 16); } }
			set { unchecked { this._byte5 = (byte)(value >> 0); this._byte4 = (byte)(value >> 8); this._byte3 = (byte)(value >> 16); } }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte6; //MSB
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte7;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private byte _byte8; //LSB
		internal uint AllocationLength
		{
			get { unchecked { return (uint)this._byte8 | ((uint)this._byte7 << 8) | ((uint)this._byte6 << 16); } }
			set { unchecked { this._byte8 = (byte)(value >> 0); this._byte7 = (byte)(value >> 8); this._byte6 = (byte)(value >> 16); } }
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private Control _Control;
		public override Control Control { get { return this._Control; } set { this._Control = value; } }
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions