Bladeren bron

Added support for MaxOutstandingR2T > 1

Tal Aloni 8 jaren geleden
bovenliggende
commit
a5edd24298

+ 7 - 3
ISCSI/ISCSI.Server/ConnectionParameters.cs

@@ -16,11 +16,15 @@ namespace ISCSI.Server
     {
     {
         public SCSICommandPDU Command;
         public SCSICommandPDU Command;
         public uint NextR2TSN;
         public uint NextR2TSN;
+        public uint NextOffset;
+        public uint TotalR2Ts; // Numbers of R2Ts that will be sent during this transfer
 
 
-        public TransferEntry(SCSICommandPDU command, uint nextR2TSN)
+        public TransferEntry(SCSICommandPDU command, uint nextR2TSN, uint nextOffset, uint totalR2Ts)
         {
         {
             Command = command;
             Command = command;
             NextR2TSN = nextR2TSN;
             NextR2TSN = nextR2TSN;
+            NextOffset = nextOffset;
+            TotalR2Ts = totalR2Ts;
         }
         }
     }
     }
 
 
@@ -60,9 +64,9 @@ namespace ISCSI.Server
             m_textSequences.Remove(initiatorTaskTag);
             m_textSequences.Remove(initiatorTaskTag);
         }
         }
 
 
-        public TransferEntry AddTransfer(uint transferTag, SCSICommandPDU command, uint nextR2TSN)
+        public TransferEntry AddTransfer(uint transferTag, SCSICommandPDU command, uint nextR2TSN, uint nextOffset, uint totalR2Ts)
         {
         {
-            TransferEntry entry = new TransferEntry(command, nextR2TSN);
+            TransferEntry entry = new TransferEntry(command, nextR2TSN, nextOffset, totalR2Ts);
             n_transfers.Add(transferTag, entry);
             n_transfers.Add(transferTag, entry);
             return entry;
             return entry;
         }
         }

+ 1 - 1
ISCSI/ISCSI.Server/ISCSIServer.Parameters.cs

@@ -27,7 +27,7 @@ namespace ISCSI.Server
             public static int FirstBurstLength = DefaultParameters.Session.FirstBurstLength;
             public static int FirstBurstLength = DefaultParameters.Session.FirstBurstLength;
             public static int DefaultTime2Wait = 0;
             public static int DefaultTime2Wait = 0;
             public static int DefaultTime2Retain = 20;
             public static int DefaultTime2Retain = 20;
-            public static int MaxOutstandingR2T = 1; // implementation limit
+            public static int MaxOutstandingR2T = 16;
             public static bool DataPDUInOrder = true; // implementation limit
             public static bool DataPDUInOrder = true; // implementation limit
             public static bool DataSequenceInOrder = true; // implementation limit
             public static bool DataSequenceInOrder = true; // implementation limit
             public static int ErrorRecoveryLevel = 0; // implementation limit
             public static int ErrorRecoveryLevel = 0; // implementation limit

+ 32 - 20
ISCSI/ISCSI.Server/TargetResponseHelper.cs

@@ -32,18 +32,25 @@ namespace ISCSI.Server
                 // Create buffer for next segments (we only execute the command after receiving all of its data)
                 // Create buffer for next segments (we only execute the command after receiving all of its data)
                 Array.Resize<byte>(ref command.Data, (int)command.ExpectedDataTransferLength);
                 Array.Resize<byte>(ref command.Data, (int)command.ExpectedDataTransferLength);
                 
                 
-                // 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);
+                // Send R2Ts:
+                uint bytesLeft = command.ExpectedDataTransferLength - command.DataSegmentLength;
+                uint nextOffset = command.DataSegmentLength;
+                int totalR2Ts = (int)Math.Ceiling((double)bytesLeft / connection.TargetMaxRecvDataSegmentLength);
+                int outgoingR2Ts = Math.Min(session.MaxOutstandingR2T, totalR2Ts);
 
 
-                connection.AddTransfer(transferTag, command, 1);
+                for (uint index = 0; index < outgoingR2Ts; index++)
+                {
+                    ReadyToTransferPDU response = new ReadyToTransferPDU();
+                    response.InitiatorTaskTag = command.InitiatorTaskTag;
+                    response.R2TSN = index; // R2Ts are sequenced per command and must start with 0 for each new command;
+                    response.TargetTransferTag = transferTag;
+                    response.BufferOffset = nextOffset;
+                    response.DesiredDataTransferLength = Math.Min((uint)connection.TargetMaxRecvDataSegmentLength, command.ExpectedDataTransferLength - response.BufferOffset);
+                    responseList.Add(response);
+                    nextOffset += (uint)connection.TargetMaxRecvDataSegmentLength;
+                }
+                connection.AddTransfer(transferTag, command, (uint)outgoingR2Ts, nextOffset, (uint)totalR2Ts);
                 session.CommandsInTransfer.Add(command.CmdSN);
                 session.CommandsInTransfer.Add(command.CmdSN);
-
-                responseList.Add(response);
                 return responseList;
                 return responseList;
             }
             }
 
 
@@ -107,16 +114,21 @@ namespace ISCSI.Server
                 // An R2T is considered outstanding until the last data PDU is transferred.
                 // An R2T is considered outstanding until the last data PDU is transferred.
                 if (request.Final)
                 if (request.Final)
                 {
                 {
-                    // Send R2T
-                    ReadyToTransferPDU response = new ReadyToTransferPDU();
-                    response.InitiatorTaskTag = request.InitiatorTaskTag;
-                    response.TargetTransferTag = request.TargetTransferTag;
-                    response.R2TSN = transfer.NextR2TSN;
-                    response.BufferOffset = offset + request.DataSegmentLength; // where we left off
-                    response.DesiredDataTransferLength = Math.Min((uint)connection.TargetMaxRecvDataSegmentLength, totalLength - response.BufferOffset);
-                    responseList.Add(response);
-                    
-                    transfer.NextR2TSN++;
+                    // We already sent as many R2T as we could, we will only send R2T if any remained.
+                    if (transfer.NextR2TSN < transfer.TotalR2Ts)
+                    {
+                        // Send R2T
+                        ReadyToTransferPDU response = new ReadyToTransferPDU();
+                        response.InitiatorTaskTag = request.InitiatorTaskTag;
+                        response.TargetTransferTag = request.TargetTransferTag;
+                        response.R2TSN = transfer.NextR2TSN;
+                        response.BufferOffset = transfer.NextOffset + request.DataSegmentLength; // where we left off
+                        response.DesiredDataTransferLength = Math.Min((uint)connection.TargetMaxRecvDataSegmentLength, totalLength - response.BufferOffset);
+                        responseList.Add(response);
+
+                        transfer.NextR2TSN++;
+                        transfer.NextOffset += (uint)connection.TargetMaxRecvDataSegmentLength;
+                    }
                 }
                 }
                 return responseList;
                 return responseList;
             }
             }