internal static SCSICommandPDU GetReportLUNsCommand(SessionParameters session, ConnectionParameters connection, uint allocationLength) { SCSICommandDescriptorBlock reportLUNs = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.ReportLUNs); reportLUNs.TransferLength = allocationLength; SCSICommandPDU scsiCommand = new SCSICommandPDU(); scsiCommand.CommandDescriptorBlock = reportLUNs.GetBytes(); scsiCommand.InitiatorTaskTag = session.GetNextTaskTag(); scsiCommand.Final = true; scsiCommand.Read = true; scsiCommand.CmdSN = session.GetNextCmdSN(true); scsiCommand.ExpectedDataTransferLength = allocationLength; return(scsiCommand); }
internal static SCSICommandPDU GetReadCapacity10Command(SessionParameters session, ConnectionParameters connection, ushort LUN) { SCSICommandDescriptorBlock readCapacity10 = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.ReadCapacity10); readCapacity10.TransferLength = ReadCapacity10Parameter.Length; SCSICommandPDU scsiCommand = new SCSICommandPDU(); scsiCommand.CommandDescriptorBlock = readCapacity10.GetBytes(); scsiCommand.InitiatorTaskTag = session.GetNextTaskTag(); scsiCommand.Final = true; scsiCommand.Read = true; scsiCommand.LUN = LUN; scsiCommand.CmdSN = session.GetNextCmdSN(true); scsiCommand.ExpectedDataTransferLength = ReadCapacity10Parameter.Length; return(scsiCommand); }
public SCSIStatusCodeName ExecuteCommand(byte[] commandBytes, LUNStructure lun, byte[] data, out byte[] response) { SCSICommandDescriptorBlock command; try { command = SCSICommandDescriptorBlock.FromBytes(commandBytes, 0); } catch (UnsupportedSCSICommandException) { ISCSIServer.Log("[ExecuteCommand] Unsupported SCSI Command (0x{0})", commandBytes[0].ToString("X")); response = SCSITarget.FormatSenseData(SenseDataParameter.GetIllegalRequestUnsupportedCommandCodeSenseData()); return(SCSIStatusCodeName.CheckCondition); } return(ExecuteCommand(command, lun, data, out response)); }
internal static SCSICommandPDU GetRead16Command(SessionParameters session, ConnectionParameters connection, ushort LUN, ulong sectorIndex, uint sectorCount, int bytesPerSector) { SCSICommandDescriptorBlock read16 = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.Read16); read16.LogicalBlockAddress64 = sectorIndex; read16.TransferLength = sectorCount; SCSICommandPDU scsiCommand = new SCSICommandPDU(); scsiCommand.CommandDescriptorBlock = read16.GetBytes(); scsiCommand.LUN = LUN; scsiCommand.InitiatorTaskTag = session.GetNextTaskTag(); scsiCommand.Final = true; scsiCommand.Read = true; scsiCommand.CmdSN = session.GetNextCmdSN(true); scsiCommand.ExpectedDataTransferLength = (uint)(sectorCount * bytesPerSector); return(scsiCommand); }
internal static SCSICommandPDU GetReadCapacity16Command(ConnectionParameters connection, ushort LUN) { ISCSISession session = connection.Session; SCSICommandDescriptorBlock serviceActionIn = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.ServiceActionIn16); serviceActionIn.ServiceAction = ServiceAction.ReadCapacity16; serviceActionIn.TransferLength = ReadCapacity16Parameter.Length; SCSICommandPDU scsiCommand = new SCSICommandPDU(); scsiCommand.CommandDescriptorBlock = serviceActionIn.GetBytes(); scsiCommand.InitiatorTaskTag = session.GetNextTaskTag(); scsiCommand.Final = true; scsiCommand.Read = true; scsiCommand.LUN = LUN; scsiCommand.CmdSN = session.GetNextCmdSN(true); scsiCommand.ExpectedDataTransferLength = ReadCapacity16Parameter.Length; return(scsiCommand); }
public SCSIStatusCodeName Read(SCSICommandDescriptorBlock command, LUNStructure lun, out byte[] response) { if (lun >= m_disks.Count) { response = FormatSenseData(SenseDataParameter.GetIllegalRequestInvalidLUNSenseData()); return(SCSIStatusCodeName.CheckCondition); } Disk disk = m_disks[lun]; int sectorCount = (int)command.TransferLength; try { lock (IOLock) { response = disk.ReadSectors((long)command.LogicalBlockAddress64, sectorCount); } return(SCSIStatusCodeName.Good); } catch (ArgumentOutOfRangeException) { ISCSIServer.Log("[Read] Read error: LBA out of range"); response = FormatSenseData(SenseDataParameter.GetIllegalRequestLBAOutOfRangeSenseData()); return(SCSIStatusCodeName.CheckCondition); } catch (IOException ex) { int error = Marshal.GetHRForException(ex); if (error == (int)Win32Error.ERROR_CRC) { ISCSIServer.Log("[Read] Read error: CRC error"); response = FormatSenseData(SenseDataParameter.GetWriteFaultSenseData()); return(SCSIStatusCodeName.CheckCondition); } else { ISCSIServer.Log("[Read] Read error: {0}", ex.ToString()); response = FormatSenseData(SenseDataParameter.GetMediumErrorUnrecoverableReadErrorSenseData()); return(SCSIStatusCodeName.CheckCondition); } } }
public void HandleCommand(byte[] packet) { var command = SCSICommandDescriptorBlock.DecodeCommand(packet, 0); this.Log(LogLevel.Debug, "Decoded command: {0}", command); switch (command) { case SCSICommand.TestUnitReady: break; case SCSICommand.Inquiry: // this is just an empty stub QueueData(new byte[36]); break; case SCSICommand.Read10: var cmd = Packet.DecodeDynamic <IReadWrite10Command>(packet, 0); this.Log(LogLevel.Debug, "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.Debug, "Reading {0} bytes from address 0x{1:x}", bytesCount, readPosition); QueueData(data); break; case SCSICommand.ModeSense6: // this is just an empty stub QueueData(new byte[192]); break; case SCSICommand.RequestSense: // this is just an empty stub QueueData(new byte[512]); break; default: this.Log(LogLevel.Error, "Unsupported SCSI command: {0}", command); break; } }
public SCSIStatusCodeName Write(SCSICommandDescriptorBlock command, LUNStructure lun, byte[] data, out byte[] response) { if (lun >= m_disks.Count) { response = FormatSenseData(SenseDataParameter.GetIllegalRequestInvalidLUNSenseData()); return(SCSIStatusCodeName.CheckCondition); } Disk disk = m_disks[lun]; if (disk.IsReadOnly) { SenseDataParameter senseData = SenseDataParameter.GetDataProtectSenseData(); response = senseData.GetBytes(); return(SCSIStatusCodeName.CheckCondition); } try { lock (IOLock) { disk.WriteSectors((long)command.LogicalBlockAddress64, data); } response = new byte[0]; return(SCSIStatusCodeName.Good); } catch (ArgumentOutOfRangeException) { ISCSIServer.Log("[Write] Write error: LBA out of range"); response = FormatSenseData(SenseDataParameter.GetIllegalRequestLBAOutOfRangeSenseData()); return(SCSIStatusCodeName.CheckCondition); } catch (IOException ex) { ISCSIServer.Log("[Write] Write error: {0}", ex.ToString()); response = FormatSenseData(SenseDataParameter.GetMediumErrorWriteFaultSenseData()); return(SCSIStatusCodeName.CheckCondition); } }
internal static SCSICommandPDU GetWrite16Command(SessionParameters session, ConnectionParameters connection, ushort LUN, ulong sectorIndex, byte[] data, int bytesPerSector) { SCSICommandDescriptorBlock write16 = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.Write16); write16.LogicalBlockAddress64 = sectorIndex; write16.TransferLength = (uint)(data.Length / bytesPerSector); SCSICommandPDU scsiCommand = new SCSICommandPDU(); scsiCommand.CommandDescriptorBlock = write16.GetBytes(); if (session.ImmediateData) { int immediateDataLength = Math.Min(data.Length, session.FirstBurstLength); scsiCommand.Data = ByteReader.ReadBytes(data, 0, immediateDataLength); } scsiCommand.LUN = LUN; scsiCommand.InitiatorTaskTag = session.GetNextTaskTag(); scsiCommand.Final = true; scsiCommand.Write = true; scsiCommand.CmdSN = session.GetNextCmdSN(true); scsiCommand.ExpectedDataTransferLength = (uint)(data.Length); return(scsiCommand); }
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; } }
public SCSIStatusCodeName ExecuteCommand(SCSICommandDescriptorBlock command, LUNStructure lun, byte[] data, out byte[] response) { ISCSIServer.Log("[ExecuteCommand] {0}", command.OpCode); if (command.OpCode == SCSIOpCodeName.TestUnitReady) { return(TestUnitReady(lun, out response)); } else if (command.OpCode == SCSIOpCodeName.RequestSense) { return(RequestSense(lun, out response)); } else if (command.OpCode == SCSIOpCodeName.Inquiry) { return(Inquiry((InquiryCommand)command, lun, out response)); } else if (command.OpCode == SCSIOpCodeName.Reserve6) { return(Reserve6(lun, out response)); } else if (command.OpCode == SCSIOpCodeName.Release6) { return(Release6(lun, out response)); } else if (command.OpCode == SCSIOpCodeName.ModeSense6) { return(ModeSense6((ModeSense6CommandDescriptorBlock)command, lun, out response)); } else if (command.OpCode == SCSIOpCodeName.ReadCapacity10) { return(ReadCapacity10(lun, out response)); } else if (command.OpCode == SCSIOpCodeName.Read6 || command.OpCode == SCSIOpCodeName.Read10 || command.OpCode == SCSIOpCodeName.Read16) { return(Read(command, lun, out response)); } else if (command.OpCode == SCSIOpCodeName.Write6 || command.OpCode == SCSIOpCodeName.Write10 || command.OpCode == SCSIOpCodeName.Write16) { return(Write(command, lun, data, out response)); } else if (command.OpCode == SCSIOpCodeName.Verify10 || command.OpCode == SCSIOpCodeName.Verify16) { return(Verify(lun, out response)); } else if (command.OpCode == SCSIOpCodeName.SynchronizeCache10) { return(SynchronizeCache10(lun, out response)); } else if (command.OpCode == SCSIOpCodeName.ServiceActionIn && command.ServiceAction == ServiceAction.ReadCapacity16) { uint allocationLength = command.TransferLength; return(ReadCapacity16(lun, allocationLength, out response)); } else if (command.OpCode == SCSIOpCodeName.ReportLUNs) { return(ReportLUNs(out response)); } else { ISCSIServer.Log("[ExecuteCommand] Unsupported SCSI Command (0x{0})", command.OpCode.ToString("X")); response = FormatSenseData(SenseDataParameter.GetIllegalRequestUnsupportedCommandCodeSenseData()); return(SCSIStatusCodeName.CheckCondition); } }