示例#1
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);
        }