Пример #1
0
        public byte[] GetBytes(ScsiCommand cmd, byte[] immediateData, int offset, int count, bool isFinalData, bool willRead, bool willWrite, uint expected)
        {
            BasicHeaderSegment _basicHeader = new BasicHeaderSegment();
            _basicHeader.Immediate = cmd.ImmediateDelivery;
            _basicHeader.OpCode = OpCode.ScsiCommand;
            _basicHeader.FinalPdu = isFinalData;
            _basicHeader.TotalAhsLength = 0;
            _basicHeader.DataSegmentLength = count;
            _basicHeader.InitiatorTaskTag = _connection.Session.CurrentTaskTag;

            byte[] buffer = new byte[48 + Utilities.RoundUp(count, 4)];
            _basicHeader.WriteTo(buffer, 0);
            buffer[1] = PackAttrByte(isFinalData, willRead, willWrite, cmd.TaskAttributes);
            Utilities.WriteBytesBigEndian(_lun, buffer, 8);
            Utilities.WriteBytesBigEndian(expected, buffer, 20);
            Utilities.WriteBytesBigEndian(_connection.Session.CommandSequenceNumber, buffer, 24);
            Utilities.WriteBytesBigEndian(_connection.ExpectedStatusSequenceNumber, buffer, 28);
            cmd.WriteTo(buffer, 32);

            if (immediateData != null && count != 0)
            {
                Array.Copy(immediateData, offset, buffer, 48, count);
            }

            return buffer;
        }
Пример #2
0
        public byte[] GetBytes(ScsiCommand cmd, byte[] immediateData, int offset, int count, bool isFinalData, bool willRead, bool willWrite, uint expected)
        {
            BasicHeaderSegment _basicHeader = new BasicHeaderSegment();

            _basicHeader.Immediate         = cmd.ImmediateDelivery;
            _basicHeader.OpCode            = OpCode.ScsiCommand;
            _basicHeader.FinalPdu          = isFinalData;
            _basicHeader.TotalAhsLength    = 0;
            _basicHeader.DataSegmentLength = count;
            _basicHeader.InitiatorTaskTag  = _connection.Session.CurrentTaskTag;

            byte[] buffer = new byte[48 + Utilities.RoundUp(count, 4)];
            _basicHeader.WriteTo(buffer, 0);
            buffer[1] = PackAttrByte(isFinalData, willRead, willWrite, cmd.TaskAttributes);
            Utilities.WriteBytesBigEndian(_lun, buffer, 8);
            Utilities.WriteBytesBigEndian(expected, buffer, 20);
            Utilities.WriteBytesBigEndian(_connection.Session.CommandSequenceNumber, buffer, 24);
            Utilities.WriteBytesBigEndian(_connection.ExpectedStatusSequenceNumber, buffer, 28);
            cmd.WriteTo(buffer, 32);

            if (immediateData != null && count != 0)
            {
                Array.Copy(immediateData, offset, buffer, 48, count);
            }

            return(buffer);
        }
Пример #3
0
        public T Send <T>(ScsiCommand cmd, byte[] buffer, int offset, int count, int expected)
            where T : ScsiResponse, new()
        {
            byte[] tempBuffer = new byte[expected];
            int    numRead    = Send(cmd, buffer, offset, count, tempBuffer, 0, expected);

            T result = new T();

            result.ReadFrom(tempBuffer, 0, numRead);
            return(result);
        }
Пример #4
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 = EndianUtilities.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);
                    }
                    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, (int)(inBufferOffset + resp.BufferOffset), resp.ReadData.Length);
                        numRead += resp.ReadData.Length;
                    }

                    isFinal = resp.Header.FinalPdu;
                }
            }

            Session.NextTaskTag();
            Session.NextCommandSequenceNumber();

            return(numRead);
        }
Пример #5
0
 private T Send <T>(ScsiCommand cmd, byte[] buffer, int offset, int count, int expected)
     where T : ScsiResponse, new()
 {
     return(_currentConnection.Send <T>(cmd, buffer, offset, count, expected));
 }
Пример #6
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>
 private int Send(ScsiCommand cmd, byte[] outBuffer, int outBufferOffset, int outBufferCount, byte[] inBuffer, int inBufferOffset, int inBufferMax)
 {
     return(_currentConnection.Send(cmd, outBuffer, outBufferOffset, outBufferCount, inBuffer, inBufferOffset, inBufferMax));
 }