internal static NOPOutPDU GetPingRequest(SessionParameters session, ConnectionParameters connection) { // Microsoft iSCSI Target v3.1 expects that CmdSN won't be incremented after this request regardless of whether the ImmediateDelivery bit is set or not, // So we set the ImmediateDelivery bit to work around the issue. NOPOutPDU request = new NOPOutPDU(); request.ImmediateDelivery = true; request.InitiatorTaskTag = session.GetNextTaskTag(); request.CmdSN = session.GetNextCmdSN(false); // RFC 3720: The NOP-Out MUST only have the Target Transfer Tag set if it is issued in response to a NOP-In (with a valid Target Transfer Tag). // Otherwise, the Target Transfer Tag MUST be set to 0xffffffff. request.TargetTransferTag = 0xFFFFFFFF; return(request); }
internal static NOPOutPDU GetPingResponse(NOPInPDU request, SessionParameters session, ConnectionParameters connection) { NOPOutPDU response = new NOPOutPDU(); // If the Initiator Task Tag contains 0xffffffff, the I bit MUST be set to 1 and the CmdSN is not advanced after this PDU is sent. response.ImmediateDelivery = true; // RFC 3720: The NOP-Out MUST have the Initiator Task Tag set to a valid value only if a response in the form of NOP-In is requested. // Otherwise, the Initiator Task Tag MUST be set to 0xffffffff response.InitiatorTaskTag = 0xFFFFFFFF; response.CmdSN = session.GetNextCmdSN(false); response.TargetTransferTag = request.TargetTransferTag; // p.s. the Data Segment (of the request sent by the target) MUST NOT contain any data return(response); }
internal static SCSICommandPDU GetReportLUNsCommand(SessionParameters session, ConnectionParameters connection, uint allocationLength) { SCSICommandDescriptorBlock reportLUNs = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.ReportLUNs); reportLUNs.TransferLength = allocationLength; SCSICommandPDU scsiCommand = new SCSICommandPDU(); scsiCommand.CommandDescriptorBlock = reportLUNs.GetBytes(); scsiCommand.InitiatorTaskTag = session.GetNextTaskTag(); scsiCommand.Final = true; scsiCommand.Read = true; scsiCommand.CmdSN = session.GetNextCmdSN(true); scsiCommand.ExpectedDataTransferLength = allocationLength; return(scsiCommand); }
internal static SCSICommandPDU GetReadCapacity10Command(SessionParameters session, ConnectionParameters connection, ushort LUN) { SCSICommandDescriptorBlock readCapacity10 = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.ReadCapacity10); readCapacity10.TransferLength = ReadCapacity10Parameter.Length; SCSICommandPDU scsiCommand = new SCSICommandPDU(); scsiCommand.CommandDescriptorBlock = readCapacity10.GetBytes(); scsiCommand.InitiatorTaskTag = session.GetNextTaskTag(); scsiCommand.Final = true; scsiCommand.Read = true; scsiCommand.LUN = LUN; scsiCommand.CmdSN = session.GetNextCmdSN(true); scsiCommand.ExpectedDataTransferLength = ReadCapacity10Parameter.Length; return(scsiCommand); }
internal static SCSICommandPDU GetRead16Command(SessionParameters session, ConnectionParameters connection, ushort LUN, ulong sectorIndex, uint sectorCount, int bytesPerSector) { SCSICommandDescriptorBlock read16 = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.Read16); read16.LogicalBlockAddress64 = sectorIndex; read16.TransferLength = sectorCount; SCSICommandPDU scsiCommand = new SCSICommandPDU(); scsiCommand.CommandDescriptorBlock = read16.GetBytes(); scsiCommand.LUN = LUN; scsiCommand.InitiatorTaskTag = session.GetNextTaskTag(); scsiCommand.Final = true; scsiCommand.Read = true; scsiCommand.CmdSN = session.GetNextCmdSN(true); scsiCommand.ExpectedDataTransferLength = (uint)(sectorCount * bytesPerSector); return(scsiCommand); }
internal static SCSICommandPDU GetWrite16Command(SessionParameters session, ConnectionParameters connection, ushort LUN, ulong sectorIndex, byte[] data, int bytesPerSector) { SCSICommandDescriptorBlock write16 = SCSICommandDescriptorBlock.Create(SCSIOpCodeName.Write16); write16.LogicalBlockAddress64 = sectorIndex; write16.TransferLength = (uint)(data.Length / bytesPerSector); SCSICommandPDU scsiCommand = new SCSICommandPDU(); scsiCommand.CommandDescriptorBlock = write16.GetBytes(); if (session.ImmediateData) { int immediateDataLength = Math.Min(data.Length, session.FirstBurstLength); scsiCommand.Data = ByteReader.ReadBytes(data, 0, immediateDataLength); } scsiCommand.LUN = LUN; scsiCommand.InitiatorTaskTag = session.GetNextTaskTag(); scsiCommand.Final = true; scsiCommand.Write = true; scsiCommand.CmdSN = session.GetNextCmdSN(true); scsiCommand.ExpectedDataTransferLength = (uint)(data.Length); return(scsiCommand); }
internal static List <SCSIDataOutPDU> GetWriteData(SessionParameters session, ConnectionParameters connection, ushort LUN, ulong sectorIndex, byte[] data, int bytesPerSector, ReadyToTransferPDU readyToTransfer) { List <SCSIDataOutPDU> result = new List <SCSIDataOutPDU>(); // if readyToTransfer.DesiredDataTransferLength <= connection.TargetMaxRecvDataSegmentLength we must send multiple Data-Out PDUs // We assume DesiredDataTransferLength does not violate session.MaxBurstLength int numberOfChunks = (int)Math.Ceiling((double)readyToTransfer.DesiredDataTransferLength / connection.TargetMaxRecvDataSegmentLength); for (int chunkIndex = 0; chunkIndex < numberOfChunks; chunkIndex++) { int chunkOffset = chunkIndex * connection.TargetMaxRecvDataSegmentLength; int chunkLength = (int)Math.Min(connection.TargetMaxRecvDataSegmentLength, readyToTransfer.DesiredDataTransferLength - chunkOffset); SCSIDataOutPDU dataOut = new SCSIDataOutPDU(); dataOut.BufferOffset = readyToTransfer.BufferOffset + (uint)chunkOffset; dataOut.Data = ByteReader.ReadBytes(data, (int)dataOut.BufferOffset, chunkLength); dataOut.TargetTransferTag = readyToTransfer.TargetTransferTag; dataOut.InitiatorTaskTag = readyToTransfer.InitiatorTaskTag; if (chunkIndex == numberOfChunks - 1) { dataOut.Final = true; } result.Add(dataOut); } return(result); }
internal static LoginRequestPDU GetSingleStageLoginRequest(string initiatorName, string targetName, SessionParameters session, ConnectionParameters connection) { LoginRequestPDU request = new LoginRequestPDU(); request.ISID = session.ISID; request.TSIH = session.TSIH; request.CID = connection.CID; request.InitiatorTaskTag = session.GetNextTaskTag(); request.CmdSN = session.GetNextCmdSN(false); request.CurrentStage = 1; request.NextStage = 3; request.Transit = true; request.VersionMax = 0; request.VersionMin = 0; request.LoginParameters.Add("InitiatorName", initiatorName); if (targetName == null) { request.LoginParameters.Add("SessionType", "Discovery"); } else { request.LoginParameters.Add("SessionType", "Normal"); request.LoginParameters.Add("TargetName", targetName); } request.LoginParameters.Add("DataDigest", "None"); request.LoginParameters.Add("MaxRecvDataSegmentLength", connection.InitiatorMaxRecvDataSegmentLength.ToString()); if (targetName != null) { request.LoginParameters.Add("ErrorRecoveryLevel", ISCSIClient.OfferedErrorRecoveryLevel.ToString()); request.LoginParameters.Add("InitialR2T", ISCSIClient.OfferedInitialR2T ? "Yes" : "No"); request.LoginParameters.Add("ImmediateData", ISCSIClient.OfferedImmediateData ? "Yes" : "No"); request.LoginParameters.Add("MaxBurstLength", ISCSIClient.OfferedMaxBurstLength.ToString()); request.LoginParameters.Add("FirstBurstLength", ISCSIClient.OfferedFirstBurstLength.ToString()); request.LoginParameters.Add("MaxConnections", ISCSIClient.OfferedMaxConnections.ToString()); request.LoginParameters.Add("DataPDUInOrder", ISCSIClient.OfferedDataPDUInOrder ? "Yes" : "No"); request.LoginParameters.Add("DataSequenceInOrder", ISCSIClient.OfferedDataSequenceInOrder ? "Yes" : "No"); request.LoginParameters.Add("MaxOutstandingR2T", ISCSIClient.OfferedMaxOutstandingR2T.ToString()); } request.LoginParameters.Add("DefaultTime2Wait", ISCSIClient.OfferedDefaultTime2Wait.ToString()); request.LoginParameters.Add("DefaultTime2Retain", ISCSIClient.OfferedDefaultTime2Retain.ToString()); return(request); }
internal static LoginRequestPDU GetSecondStageLoginRequest(LoginResponsePDU firstStageResponse, SessionParameters session, ConnectionParameters connection, bool isDiscovery) { LoginRequestPDU request = new LoginRequestPDU(); request.ISID = firstStageResponse.ISID; request.TSIH = firstStageResponse.TSIH; request.CID = connection.CID; request.InitiatorTaskTag = session.GetNextTaskTag(); request.CmdSN = session.GetNextCmdSN(false); request.CurrentStage = firstStageResponse.NextStage; request.NextStage = 3; request.Transit = true; request.VersionMax = 0; request.VersionMin = 0; request.LoginParameters.Add("HeaderDigest", "None"); request.LoginParameters.Add("DataDigest", "None"); request.LoginParameters.Add("MaxRecvDataSegmentLength", connection.InitiatorMaxRecvDataSegmentLength.ToString()); if (!isDiscovery) { request.LoginParameters.Add("ErrorRecoveryLevel", ISCSIClient.OfferedErrorRecoveryLevel.ToString()); request.LoginParameters.Add("InitialR2T", ISCSIClient.OfferedInitialR2T ? "Yes" : "No"); request.LoginParameters.Add("ImmediateData", ISCSIClient.OfferedImmediateData ? "Yes" : "No"); request.LoginParameters.Add("MaxBurstLength", ISCSIClient.OfferedMaxBurstLength.ToString()); request.LoginParameters.Add("FirstBurstLength", ISCSIClient.OfferedFirstBurstLength.ToString()); request.LoginParameters.Add("MaxConnections", ISCSIClient.OfferedMaxConnections.ToString()); request.LoginParameters.Add("DataPDUInOrder", ISCSIClient.OfferedDataPDUInOrder ? "Yes" : "No"); request.LoginParameters.Add("DataSequenceInOrder", ISCSIClient.OfferedDataSequenceInOrder ? "Yes" : "No"); request.LoginParameters.Add("MaxOutstandingR2T", ISCSIClient.OfferedMaxOutstandingR2T.ToString()); } request.LoginParameters.Add("DefaultTime2Wait", ISCSIClient.OfferedDefaultTime2Wait.ToString()); request.LoginParameters.Add("DefaultTime2Retain", ISCSIClient.OfferedDefaultTime2Retain.ToString()); return(request); }
/// <param name="targetName">Set to null for discovery session</param> internal static LoginRequestPDU GetFirstStageLoginRequest(string initiatorName, string targetName, SessionParameters session, ConnectionParameters connection) { LoginRequestPDU request = new LoginRequestPDU(); request.InitiatorTaskTag = session.GetNextTaskTag(); request.ISID = session.ISID; request.TSIH = 0; // used on the first connection for a new session request.CID = connection.CID; request.CmdSN = session.GetNextCmdSN(false); request.ExpStatSN = 0; // The stage codes are: // 0 - SecurityNegotiation // 1 - LoginOperationalNegotiation // 3 - FullFeaturePhase request.CurrentStage = 0; request.NextStage = 1; request.Transit = true; request.VersionMax = 0; request.VersionMin = 0; request.LoginParameters.Add("InitiatorName", initiatorName); request.LoginParameters.Add("AuthMethod", "None"); if (targetName == null) { request.LoginParameters.Add("SessionType", "Discovery"); } else { // RFC 3720: For any connection within a session whose type is not "Discovery", the first Login Request MUST also include the TargetName key=value pair. request.LoginParameters.Add("SessionType", "Normal"); request.LoginParameters.Add("TargetName", targetName); } return(request); }
internal static void UpdateOperationalParameters(KeyValuePairList <string, string> loginParameters, SessionParameters session, ConnectionParameters connection) { session.InitialR2T = ISCSIClient.OfferedInitialR2T; session.ImmediateData = ISCSIClient.OfferedImmediateData; session.MaxBurstLength = ISCSIClient.OfferedMaxBurstLength; session.FirstBurstLength = ISCSIClient.OfferedFirstBurstLength; session.DefaultTime2Wait = ISCSIClient.OfferedDefaultTime2Wait; session.DefaultTime2Retain = ISCSIClient.OfferedDefaultTime2Retain; session.MaxOutstandingR2T = ISCSIClient.OfferedMaxOutstandingR2T; session.DataPDUInOrder = ISCSIClient.OfferedDataPDUInOrder; session.DataSequenceInOrder = ISCSIClient.OfferedDataSequenceInOrder; session.ErrorRecoveryLevel = ISCSIClient.OfferedErrorRecoveryLevel; string value = loginParameters.ValueOf("MaxRecvDataSegmentLength"); if (value != null) { connection.TargetMaxRecvDataSegmentLength = Convert.ToInt32(value); } value = loginParameters.ValueOf("InitialR2T"); if (value != null) { session.InitialR2T = (value == "Yes") ? true : false; } value = loginParameters.ValueOf("ImmediateData"); if (value != null) { session.ImmediateData = (value == "Yes") ? true : false; } value = loginParameters.ValueOf("MaxBurstLength"); if (value != null) { session.MaxBurstLength = Convert.ToInt32(value); } value = loginParameters.ValueOf("FirstBurstLength"); if (value != null) { session.FirstBurstLength = Convert.ToInt32(value); } value = loginParameters.ValueOf("DefaultTime2Wait"); if (value != null) { session.DefaultTime2Wait = Convert.ToInt32(value); } value = loginParameters.ValueOf("DefaultTime2Retain"); if (value != null) { session.DefaultTime2Retain = Convert.ToInt32(value); } value = loginParameters.ValueOf("MaxOutstandingR2T"); if (value != null) { session.MaxOutstandingR2T = Convert.ToInt32(value); } value = loginParameters.ValueOf("DataPDUInOrder"); if (value != null) { session.DataPDUInOrder = (value == "Yes") ? true : false; } value = loginParameters.ValueOf("DataSequenceInOrder"); if (value != null) { session.DataSequenceInOrder = (value == "Yes") ? true : false; } value = loginParameters.ValueOf("ErrorRecoveryLevel"); if (value != null) { session.ErrorRecoveryLevel = Convert.ToInt32(value); } }