Esempio n. 1
0
        public byte[] Read(ushort LUN, ulong sectorIndex, uint sectorCount, int bytesPerSector)
        {
            if (!m_isConnected)
            {
                throw new InvalidOperationException("iSCSI client is not connected");
            }
            SCSICommandPDU readCommand = ClientHelper.GetRead16Command(m_session, m_connection, LUN, sectorIndex, sectorCount, bytesPerSector);

            SendPDU(readCommand);
            // RFC 3720: Data payload is associated with a specific SCSI command through the Initiator Task Tag
            SCSIDataInPDU data = WaitForPDU(readCommand.InitiatorTaskTag) as SCSIDataInPDU;

            byte[] result = new byte[sectorCount * bytesPerSector];
            while (data != null)
            {
                Array.Copy(data.Data, 0, result, data.BufferOffset, data.DataSegmentLength);
                if (data.StatusPresent)
                {
                    break;
                }
                data = WaitForPDU(readCommand.InitiatorTaskTag) as SCSIDataInPDU;
            }
            if (data != null && data.Status == SCSIStatusCodeName.Good)
            {
                return(result);
            }
            else
            {
                return(null);
            }
        }
Esempio n. 2
0
        /// <returns>Capacity in bytes</returns>
        public ulong ReadCapacity(ushort LUN, out int bytesPerSector)
        {
            if (!m_isConnected)
            {
                throw new InvalidOperationException("iSCSI client is not connected");
            }
            SCSICommandPDU readCapacity = ClientHelper.GetReadCapacity10Command(m_session, m_connection, LUN);

            SendPDU(readCapacity);
            // SCSIResponsePDU with CheckCondition could be returned in case of an error
            SCSIDataInPDU data = WaitForPDU(readCapacity.InitiatorTaskTag) as SCSIDataInPDU;

            if (data != null && data.StatusPresent && data.Status == SCSIStatusCodeName.Good)
            {
                ReadCapacity10Parameter capacity = new ReadCapacity10Parameter(data.Data);
                if (capacity.ReturnedLBA != 0xFFFFFFFF)
                {
                    bytesPerSector = (int)capacity.BlockLengthInBytes;
                    return((capacity.ReturnedLBA + 1) * capacity.BlockLengthInBytes);
                }

                readCapacity = ClientHelper.GetReadCapacity16Command(m_session, m_connection, LUN);
                m_clientSocket.Send(readCapacity.GetBytes());
                data = WaitForPDU(readCapacity.InitiatorTaskTag) as SCSIDataInPDU;
                if (data != null && data.StatusPresent && data.Status == SCSIStatusCodeName.Good)
                {
                    ReadCapacity16Parameter capacity16 = new ReadCapacity16Parameter(data.Data);
                    bytesPerSector = (int)capacity16.BlockLengthInBytes;
                    return((capacity16.ReturnedLBA + 1) * capacity16.BlockLengthInBytes);
                }
            }

            bytesPerSector = 0;
            return(0);
        }
Esempio n. 3
0
 public static void EnforceExpectedDataTransferLength(SCSIDataInPDU response, uint expectedDataTransferLength)
 {
     if (response.Data.Length > expectedDataTransferLength)
     {
         response.ResidualOverflow = true;
         response.ResidualCount    = (uint)(response.Data.Length - expectedDataTransferLength);
         response.Data             = ByteReader.ReadBytes(response.Data, 0, (int)expectedDataTransferLength);
     }
     else if (response.Data.Length < expectedDataTransferLength)
     {
         response.ResidualUnderflow = true;
         response.ResidualCount     = (uint)(expectedDataTransferLength - response.Data.Length);
     }
 }
Esempio n. 4
0
        public List <ushort> GetLUNList()
        {
            if (!m_isConnected)
            {
                throw new InvalidOperationException("iSCSI client is not connected");
            }
            SCSICommandPDU reportLUNs = ClientHelper.GetReportLUNsCommand(m_session, m_connection, ReportLUNsParameter.MinimumAllocationLength);

            SendPDU(reportLUNs);
            SCSIDataInPDU data = WaitForPDU(reportLUNs.InitiatorTaskTag) as SCSIDataInPDU;

            if (data != null && data.StatusPresent && data.Status == SCSIStatusCodeName.Good)
            {
                uint requiredAllocationLength = ReportLUNsParameter.GetRequiredAllocationLength(data.Data);
                if (requiredAllocationLength > ReportLUNsParameter.MinimumAllocationLength)
                {
                    reportLUNs = ClientHelper.GetReportLUNsCommand(m_session, m_connection, requiredAllocationLength);
                    m_clientSocket.Send(reportLUNs.GetBytes());
                    data = WaitForPDU(reportLUNs.InitiatorTaskTag) as SCSIDataInPDU;

                    if (data == null || !data.StatusPresent || data.Status != SCSIStatusCodeName.Good)
                    {
                        return(null);
                    }
                }

                ReportLUNsParameter parameter = new ReportLUNsParameter(data.Data);
                List <ushort>       result    = new List <ushort>();
                foreach (LUNStructure lun in parameter.LUNList)
                {
                    if (lun.IsSingleLevelLUN)
                    {
                        result.Add(lun);
                    }
                }
                return(result);
            }
            return(null);
        }
Esempio n. 5
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);
        }