private void SendResult(BulkOnlyTransportCommandBlockWrapper commandBlockWrapper, CommandStatus status = CommandStatus.Success, uint dataResidue = 0)
        {
            var response = new CommandStatusWrapper(commandBlockWrapper.Tag, dataResidue, status);

            this.Log(LogLevel.Debug, "Sending result: {0}", response);
            deviceToHostEndpoint.HandlePacket(Packet.Encode(response));
        }
        private void HandleCommand(byte[] packet)
        {
            if (!BulkOnlyTransportCommandBlockWrapper.TryParse(packet, out var commandBlockWrapper))
            {
                this.Log(LogLevel.Warning, "Broken SCSI command block wrapper detected. Ignoring it.");
                return;
            }

            this.Log(LogLevel.Noisy, "Parsed command block wrapper: {0}", commandBlockWrapper);
            var command = SCSICommandDescriptorBlock.DecodeCommand(packet, BulkOnlyTransportCommandBlockWrapper.CommandOffset);

            this.Log(LogLevel.Noisy, "Decoded command: {0}", command);
            switch (command)
            {
            case SCSICommand.TestUnitReady:
                SendResult(commandBlockWrapper);
                break;

            case SCSICommand.Inquiry:
                // this is just an empty stub
                SendData(new byte[36]);
                SendResult(commandBlockWrapper);
                break;

            case SCSICommand.ReadCapacity:
                var result = new ReadCapcity10Result
                {
                    BlockLengthInBytes          = BlockSize,
                    ReturnedLogicalBlockAddress = (uint)(dataBackend.Length / BlockSize - 1)
                };
                SendData(Packet.Encode(result));
                SendResult(commandBlockWrapper);
                break;

            case SCSICommand.Read10:
                var cmd = Packet.DecodeDynamic <IReadWrite10Command>(packet, BulkOnlyTransportCommandBlockWrapper.CommandOffset);
                this.Log(LogLevel.Noisy, "Command args: LogicalBlockAddress: 0x{0:x}, TransferLength: {1}", (uint)cmd.LogicalBlockAddress, (ushort)cmd.TransferLength);
                var bytesCount   = (int)(cmd.TransferLength * BlockSize);
                var readPosition = (long)cmd.LogicalBlockAddress * BlockSize;
                dataBackend.Position = readPosition;
                var data = dataBackend.ReadBytes(bytesCount);
                this.Log(LogLevel.Noisy, "Reading {0} bytes from address 0x{1:x}", bytesCount, readPosition);
                SendData(data);
                SendResult(commandBlockWrapper, CommandStatus.Success, (uint)(commandBlockWrapper.DataTransferLength - data.Length));
                break;

            case SCSICommand.Write10:
                // the actual write will be triggered after receiving the next packet with data
                // we should not send result now
                writeCommandWrapper    = commandBlockWrapper;
                writeCommandDescriptor = Packet.DecodeDynamic <IReadWrite10Command>(packet, BulkOnlyTransportCommandBlockWrapper.CommandOffset);
                var position = (long)((dynamic)writeCommandDescriptor).LogicalBlockAddress * BlockSize;
                dataBackend.Position = position;
                bytesToWrite         = (uint)((dynamic)writeCommandDescriptor).TransferLength * BlockSize;
                this.Log(LogLevel.Noisy, "Preparing to write {1} bytes of data at address: 0x{0:x}", dataBackend.Position, bytesToWrite);
                mode = Mode.Data;
                break;

            case SCSICommand.ModeSense6:
                // this is just an empty stub
                SendData(new byte[192]);
                SendResult(commandBlockWrapper);
                break;

            case SCSICommand.RequestSense:
                // this is just an empty stub
                SendData(new byte[commandBlockWrapper.DataTransferLength]);
                SendResult(commandBlockWrapper);
                break;

            default:
                this.Log(LogLevel.Warning, "Unsupported SCSI command: {0}", command);
                SendResult(commandBlockWrapper, CommandStatus.Failure, commandBlockWrapper.DataTransferLength);
                break;
            }
        }