Example #1
0
        private T ParseResponse <T>(ProtocolDataUnit pdu)
            where T : BaseResponse, new()
        {
            BaseResponse resp;

            switch (pdu.OpCode)
            {
            case OpCode.LoginResponse:
                resp = new LoginResponse();
                break;

            case OpCode.LogoutResponse:
                resp = new LogoutResponse();
                break;

            case OpCode.ReadyToTransfer:
                resp = new ReadyToTransferPacket();
                break;

            case OpCode.Reject:
                resp = new RejectPacket();
                break;

            case OpCode.ScsiDataIn:
                resp = new DataInPacket();
                break;

            case OpCode.ScsiResponse:
                resp = new Response();
                break;

            case OpCode.TextResponse:
                resp = new TextResponse();
                break;

            default:
                throw new InvalidProtocolException("Unrecognized response opcode: " + pdu.OpCode);
            }

            resp.Parse(pdu);
            if (resp.StatusPresent)
            {
                SeenStatusSequenceNumber(resp.StatusSequenceNumber);
            }

            T result = resp as T;

            if (result == null)
            {
                throw new InvalidProtocolException("Unexpected response, expected " + typeof(T) + ", got " + result.GetType());
            }

            return(result);
        }
Example #2
0
        /// <summary>
        /// Sends an SCSI command (aka task) to a LUN via the connected target.
        /// </summary>
        /// <param name="cmd">The command to send</param>
        /// <param name="outBuffer">The data to send with the command</param>
        /// <param name="outBufferOffset">The offset of the first byte to send</param>
        /// <param name="outBufferCount">The number of bytes to send, if any</param>
        /// <param name="inBuffer">The buffer to fill with returned data</param>
        /// <param name="inBufferOffset">The first byte to fill with returned data</param>
        /// <param name="inBufferMax">The maximum amount of data to receive</param>
        /// <returns>The number of bytes received</returns>
        public int Send(ScsiCommand cmd, byte[] outBuffer, int outBufferOffset, int outBufferCount, byte[] inBuffer, int inBufferOffset, int inBufferMax)
        {
            CommandRequest req = new CommandRequest(this, cmd.TargetLun);

            int toSend = Math.Min(Math.Min(outBufferCount, _session.ImmediateData ? _session.FirstBurstLength : 0), MaxTargetReceiveDataSegmentLength);

            byte[] packet = req.GetBytes(cmd, outBuffer, outBufferOffset, toSend, true, inBufferMax != 0, outBufferCount != 0, (uint)(outBufferCount != 0 ? outBufferCount : inBufferMax));
            _stream.Write(packet, 0, packet.Length);
            _stream.Flush();

            int numApproved = 0;
            int numSent     = toSend;
            int pktsSent    = 0;

            while (numSent < outBufferCount)
            {
                ProtocolDataUnit pdu = ReadPdu();

                ReadyToTransferPacket resp = ParseResponse <ReadyToTransferPacket>(pdu);
                numApproved = (int)resp.DesiredTransferLength;
                uint targetTransferTag = resp.TargetTransferTag;

                while (numApproved > 0)
                {
                    toSend = Math.Min(Math.Min(outBufferCount - numSent, numApproved), MaxTargetReceiveDataSegmentLength);

                    DataOutPacket pkt = new DataOutPacket(this, cmd.TargetLun);
                    packet = pkt.GetBytes(outBuffer, outBufferOffset + numSent, toSend, toSend == numApproved, pktsSent++, (uint)numSent, targetTransferTag);
                    _stream.Write(packet, 0, packet.Length);
                    _stream.Flush();

                    numApproved -= toSend;
                    numSent     += toSend;
                }
            }

            bool isFinal = false;
            int  numRead = 0;

            while (!isFinal)
            {
                ProtocolDataUnit pdu = ReadPdu();

                if (pdu.OpCode == OpCode.ScsiResponse)
                {
                    Response resp = ParseResponse <Response>(pdu);

                    if (resp.StatusPresent && resp.Status == ScsiStatus.CheckCondition)
                    {
                        ushort senseLength = Utilities.ToUInt16BigEndian(pdu.ContentData, 0);
                        byte[] senseData   = new byte[senseLength];
                        Array.Copy(pdu.ContentData, 2, senseData, 0, senseLength);
                        throw new ScsiCommandException(resp.Status, "Target indicated SCSI failure", senseData);
                    }
                    else if (resp.StatusPresent && resp.Status != ScsiStatus.Good)
                    {
                        throw new ScsiCommandException(resp.Status, "Target indicated SCSI failure");
                    }

                    isFinal = resp.Header.FinalPdu;
                }
                else if (pdu.OpCode == OpCode.ScsiDataIn)
                {
                    DataInPacket resp = ParseResponse <DataInPacket>(pdu);

                    if (resp.StatusPresent && resp.Status != ScsiStatus.Good)
                    {
                        throw new ScsiCommandException(resp.Status, "Target indicated SCSI failure");
                    }

                    if (resp.ReadData != null)
                    {
                        Array.Copy(resp.ReadData, 0, inBuffer, inBufferOffset + resp.BufferOffset, resp.ReadData.Length);
                        numRead += resp.ReadData.Length;
                    }

                    isFinal = resp.Header.FinalPdu;
                }
            }

            _session.NextTaskTag();
            _session.NextCommandSequenceNumber();

            return(numRead);
        }