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; } }