public void OnCommandCompleted(SCSIStatusCodeName status, byte[] responseBytes, object task) { RunningSCSICommands.Decrement(); SCSICommandPDU command = (SCSICommandPDU)task; List <ISCSIPDU> responseList = TargetResponseHelper.PrepareSCSICommandResponse(command, status, responseBytes, ConnectionParameters); SendQueue.Enqueue(responseList); }
internal static ISCSIPDU GetSCSIDataOutResponsePDU(SCSIDataOutPDU request, ISCSITarget target, SessionParameters session, ConnectionParameters connection) { string connectionIdentifier = StateObject.GetConnectionIdentifier(session, connection); TransferEntry transfer = connection.GetTransferEntry(request.TargetTransferTag); if (transfer == null) { ISCSIServer.Log("[{0}][GetSCSIDataOutResponsePDU] Invalid TargetTransferTag {1}", connectionIdentifier, request.TargetTransferTag); RejectPDU reject = new RejectPDU(); reject.InitiatorTaskTag = request.InitiatorTaskTag; reject.Reason = RejectReason.InvalidPDUField; reject.Data = ByteReader.ReadBytes(request.GetBytes(), 0, 48); return(reject); } ushort LUN = (ushort)request.LUN; Disk disk = target.Disks[LUN]; uint offset = request.BufferOffset; uint totalLength = (uint)transfer.CommandDataBuffer.Length; // Store segment (we only execute the command after receiving all of its data) Array.Copy(request.Data, 0, transfer.CommandDataBuffer, offset, request.DataSegmentLength); ISCSIServer.Log(String.Format("[{0}][GetSCSIDataOutResponsePDU] Buffer offset: {1}, Total length: {2}", connectionIdentifier, offset, totalLength)); if (offset + request.DataSegmentLength == totalLength) { // Last Data-out PDU ISCSIServer.Log("[{0}][GetSCSIDataOutResponsePDU] Last Data-out PDU", connectionIdentifier); byte[] scsiResponse; SCSIStatusCodeName status = target.ExecuteCommand(transfer.CommandBytes, request.LUN, transfer.CommandDataBuffer, out scsiResponse); SCSIResponsePDU response = new SCSIResponsePDU(); response.InitiatorTaskTag = request.InitiatorTaskTag; response.Status = status; response.Data = scsiResponse; connection.RemoveTransfer(request.TargetTransferTag); return(response); } else { // Send R2T ReadyToTransferPDU response = new ReadyToTransferPDU(); response.InitiatorTaskTag = request.InitiatorTaskTag; response.TargetTransferTag = request.TargetTransferTag; response.R2TSN = transfer.NextR2NSN; response.BufferOffset = offset + request.DataSegmentLength; // where we left off response.DesiredDataTransferLength = Math.Min((uint)connection.TargetMaxRecvDataSegmentLength, totalLength - response.BufferOffset); transfer.NextR2NSN++; return(response); } }
private void ProcessCommandQueue() { while (true) { SCSICommand command; bool stopping = !m_commandQueue.TryDequeue(out command); if (stopping) { return; } byte[] responseBytes; SCSIStatusCodeName status = ExecuteCommand(command.CommandBytes, command.LUN, command.Data, out responseBytes); command.OnCommandCompleted(status, responseBytes, command.Task); } }
public SCSIResponsePDU(byte[] buffer) : base(buffer) { BidirectionalReadResidualOverflow = (OpCodeSpecificHeader[0] & 0x10) != 0; BidirectionalReadResidualUnderflow = (OpCodeSpecificHeader[0] & 0x08) != 0; ResidualOverflow = (OpCodeSpecificHeader[0] & 0x04) != 0; ResidualUnderflow = (OpCodeSpecificHeader[0] & 0x02) != 0; Response = (ISCSIResponseName)OpCodeSpecificHeader[1]; Status = (SCSIStatusCodeName)OpCodeSpecificHeader[2]; SNACKTag = BigEndianConverter.ToUInt32(OpCodeSpecific, 0); StatSN = BigEndianConverter.ToUInt32(OpCodeSpecific, 4); ExpCmdSN = BigEndianConverter.ToUInt32(OpCodeSpecific, 8); MaxCmdSN = BigEndianConverter.ToUInt32(OpCodeSpecific, 12); ExpDataSN = BigEndianConverter.ToUInt32(OpCodeSpecific, 16); BidirectionalReadResidualCount = BigEndianConverter.ToUInt32(OpCodeSpecific, 20); ResidualCount = BigEndianConverter.ToUInt32(OpCodeSpecific, 24); }
public SCSIDataInPDU(byte[] buffer, int offset) : base(buffer, offset) { Acknowledge = (OpCodeSpecificHeader[0] & 0x40) != 0; ResidualOverflow = (OpCodeSpecificHeader[0] & 0x04) != 0; ResidualUnderflow = (OpCodeSpecificHeader[0] & 0x02) != 0; StatusPresent = (OpCodeSpecificHeader[0] & 0x01) != 0; Status = (SCSIStatusCodeName)OpCodeSpecificHeader[2]; LUN = new LUNStructure(LUNOrOpCodeSpecific, 0); TargetTransferTag = BigEndianConverter.ToUInt32(OpCodeSpecific, 0); StatSN = BigEndianConverter.ToUInt32(OpCodeSpecific, 4); ExpCmdSN = BigEndianConverter.ToUInt32(OpCodeSpecific, 8); MaxCmdSN = BigEndianConverter.ToUInt32(OpCodeSpecific, 12); DataSN = BigEndianConverter.ToUInt32(OpCodeSpecific, 16); BufferOffset = BigEndianConverter.ToUInt32(OpCodeSpecific, 20); ResidualCount = BigEndianConverter.ToUInt32(OpCodeSpecific, 24); }
private void ProcessCommandQueue() { while (true) { SCSICommand command; bool stopping = !m_commandQueue.TryDequeue(out command); if (stopping) { return; } byte[] responseBytes; SCSIStatusCodeName status = ExecuteCommand(command.CommandBytes, command.LUN, command.Data, out responseBytes); /* * //logging to console * Console.WriteLine("CommandBytes:" + BitConverter.ToString(command.CommandBytes) ); * Console.WriteLine("LUN:" + command.LUN); * Console.WriteLine("Data:" + BitConverter.ToString(command.Data)); */ command.OnCommandCompleted(status, responseBytes, command.Task); } }
internal static List <ISCSIPDU> PrepareSCSICommandResponse(SCSICommandPDU command, SCSIStatusCodeName status, byte[] scsiResponse, ConnectionParameters connection) { List <ISCSIPDU> responseList = new List <ISCSIPDU>(); if (!command.Read || status != SCSIStatusCodeName.Good) { // RFC 3720: if the command is completed with an error, then the response and sense data MUST be sent in a SCSI Response PDU SCSIResponsePDU response = new SCSIResponsePDU(); response.InitiatorTaskTag = command.InitiatorTaskTag; response.Status = status; response.Data = scsiResponse; if (command.Read) { EnforceExpectedDataTransferLength(response, command.ExpectedDataTransferLength); } responseList.Add(response); } else if (scsiResponse.Length <= connection.InitiatorMaxRecvDataSegmentLength) { SCSIDataInPDU response = new SCSIDataInPDU(); response.InitiatorTaskTag = command.InitiatorTaskTag; response.Status = status; response.StatusPresent = true; response.Final = true; response.Data = scsiResponse; EnforceExpectedDataTransferLength(response, command.ExpectedDataTransferLength); responseList.Add(response); } else // we have to split the response to multiple Data-In PDUs { int bytesLeftToSend = scsiResponse.Length; uint dataSN = 0; while (bytesLeftToSend > 0) { int dataSegmentLength = Math.Min(connection.InitiatorMaxRecvDataSegmentLength, bytesLeftToSend); int dataOffset = scsiResponse.Length - bytesLeftToSend; SCSIDataInPDU response = new SCSIDataInPDU(); response.InitiatorTaskTag = command.InitiatorTaskTag; if (bytesLeftToSend == dataSegmentLength) { // last Data-In PDU response.Status = status; response.StatusPresent = true; response.Final = true; } response.BufferOffset = (uint)dataOffset; response.DataSN = dataSN; dataSN++; response.Data = new byte[dataSegmentLength]; Array.Copy(scsiResponse, dataOffset, response.Data, 0, dataSegmentLength); responseList.Add(response); bytesLeftToSend -= dataSegmentLength; } } return(responseList); }
internal static List <ISCSIPDU> GetSCSIResponsePDU(SCSICommandPDU command, ISCSITarget target, SessionParameters session, ConnectionParameters connection) { // We return either SCSIResponsePDU or List<SCSIDataInPDU> List <ISCSIPDU> responseList = new List <ISCSIPDU>(); string connectionIdentifier = StateObject.GetConnectionIdentifier(session, connection); if (command.Write && command.DataSegmentLength < command.ExpectedDataTransferLength) { uint transferTag = session.GetNextTransferTag(); // Store segment (we only execute the command after receiving all of its data) byte[] commandDataBuffer = new byte[command.ExpectedDataTransferLength]; Array.Copy(command.Data, 0, commandDataBuffer, 0, command.DataSegmentLength); // Send R2T ReadyToTransferPDU response = new ReadyToTransferPDU(); response.InitiatorTaskTag = command.InitiatorTaskTag; response.R2TSN = 0; // R2Ts are sequenced per command and must start with 0 for each new command; response.TargetTransferTag = transferTag; response.BufferOffset = command.DataSegmentLength; response.DesiredDataTransferLength = Math.Min((uint)connection.TargetMaxRecvDataSegmentLength, command.ExpectedDataTransferLength - response.BufferOffset); connection.AddTransfer(transferTag, command.CommandDescriptorBlock, commandDataBuffer, 1); responseList.Add(response); return(responseList); } byte[] scsiResponse; SCSIStatusCodeName status = target.ExecuteCommand(command.CommandDescriptorBlock, command.LUN, command.Data, out scsiResponse); if (!command.Read || status != SCSIStatusCodeName.Good) { // RFC 3720: if the command is completed with an error, then the response and sense data MUST be sent in a SCSI Response PDU SCSIResponsePDU response = new SCSIResponsePDU(); response.InitiatorTaskTag = command.InitiatorTaskTag; response.Status = status; response.Data = scsiResponse; if (command.Read) { EnforceExpectedDataTransferLength(response, command.ExpectedDataTransferLength); } responseList.Add(response); } else if (scsiResponse.Length <= connection.InitiatorMaxRecvDataSegmentLength) { SCSIDataInPDU response = new SCSIDataInPDU(); response.InitiatorTaskTag = command.InitiatorTaskTag; response.Status = status; response.StatusPresent = true; response.Final = true; response.Data = scsiResponse; EnforceExpectedDataTransferLength(response, command.ExpectedDataTransferLength); responseList.Add(response); } else // we have to split the response to multiple Data-In PDUs { int bytesLeftToSend = scsiResponse.Length; uint dataSN = 0; while (bytesLeftToSend > 0) { int dataSegmentLength = Math.Min(connection.InitiatorMaxRecvDataSegmentLength, bytesLeftToSend); int dataOffset = scsiResponse.Length - bytesLeftToSend; SCSIDataInPDU response = new SCSIDataInPDU(); response.InitiatorTaskTag = command.InitiatorTaskTag; if (bytesLeftToSend == dataSegmentLength) { // last Data-In PDU response.Status = status; response.StatusPresent = true; response.Final = true; } response.BufferOffset = (uint)dataOffset; response.DataSN = dataSN; dataSN++; response.Data = new byte[dataSegmentLength]; Array.Copy(scsiResponse, dataOffset, response.Data, 0, dataSegmentLength); responseList.Add(response); bytesLeftToSend -= dataSegmentLength; } } return(responseList); }