Esempio n. 1
0
        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);
            }
        }
Esempio n. 3
0
        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);
            }
        }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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);
        }
Esempio n. 6
0
        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);
            }
        }
Esempio n. 7
0
        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);
        }