ISCSISession.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /* Copyright (C) 2012-2016 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Text;
  10. namespace ISCSI.Server
  11. {
  12. internal class ISCSISession
  13. {
  14. public int MaxConnections = DefaultParameters.Session.MaxConnections;
  15. public bool InitialR2T = DefaultParameters.Session.InitialR2T;
  16. public bool ImmediateData = DefaultParameters.Session.ImmediateData;
  17. public int MaxBurstLength = DefaultParameters.Session.MaxBurstLength;
  18. public int FirstBurstLength = DefaultParameters.Session.FirstBurstLength;
  19. public int DefaultTime2Wait = DefaultParameters.Session.DefaultTime2Wait;
  20. public int DefaultTime2Retain = DefaultParameters.Session.DefaultTime2Retain;
  21. public int MaxOutstandingR2T = DefaultParameters.Session.MaxOutstandingR2T;
  22. public bool DataPDUInOrder = DefaultParameters.Session.DataPDUInOrder;
  23. public bool DataSequenceInOrder = DefaultParameters.Session.DataSequenceInOrder;
  24. public int ErrorRecoveryLevel = DefaultParameters.Session.ErrorRecoveryLevel;
  25. public uint CommandQueueSize = ISCSIServer.DefaultCommandQueueSize;
  26. public ulong ISID; // Initiator Session ID
  27. public ushort TSIH; // Target Session Identifying Handle
  28. public bool IsDiscovery; // Indicate whether this is a discovery session
  29. public bool IsFullFeaturePhase; // Indicate whether login has been completed
  30. public bool CommandNumberingStarted;
  31. public uint ExpCmdSN;
  32. public ISCSITarget Target; // Across all connections within a session, an initiator sees one and the same target.
  33. public List<uint> CommandsInTransfer = new List<uint>();
  34. public List<SCSICommandPDU> DelayedCommands = new List<SCSICommandPDU>();
  35. /// <summary>
  36. /// Target Transfer Tag:
  37. /// There are no protocol specific requirements with regard to the value of these tags,
  38. /// but it is assumed that together with the LUN, they will enable the target to associate data with an R2T.
  39. /// </summary>
  40. private uint m_nextTransferTag = 0;
  41. private object m_transferTagLock = new object();
  42. public uint GetNextTransferTag()
  43. {
  44. lock (m_transferTagLock)
  45. {
  46. uint transferTag = m_nextTransferTag;
  47. m_nextTransferTag++;
  48. return transferTag;
  49. }
  50. }
  51. public bool IsPrecedingCommandPending(uint cmdSN)
  52. {
  53. foreach (uint entry in CommandsInTransfer)
  54. {
  55. if (IsFirstCmdSNPreceding(entry, cmdSN))
  56. {
  57. return true;
  58. }
  59. }
  60. return false;
  61. }
  62. public List<SCSICommandPDU> GetDelayedCommandsReadyForExecution()
  63. {
  64. List<SCSICommandPDU> result = new List<SCSICommandPDU>();
  65. if (CommandsInTransfer.Count == 0)
  66. {
  67. result.AddRange(DelayedCommands);
  68. DelayedCommands.Clear();
  69. return result;
  70. }
  71. // We find the earliest CmdSN of the commands in transfer
  72. uint earliestCmdSN = CommandsInTransfer[0];
  73. for(int index = 1; index < CommandsInTransfer.Count; index++)
  74. {
  75. if (IsFirstCmdSNPreceding(CommandsInTransfer[index], earliestCmdSN))
  76. {
  77. earliestCmdSN = CommandsInTransfer[index];
  78. }
  79. }
  80. // Any command that is preceding minCmdSN should be executed
  81. for(int index = 0; index < DelayedCommands.Count; index++)
  82. {
  83. SCSICommandPDU delayedCommand = DelayedCommands[index];
  84. if (IsFirstCmdSNPreceding(delayedCommand.CmdSN, earliestCmdSN))
  85. {
  86. result.Add(delayedCommand);
  87. DelayedCommands.RemoveAt(index);
  88. index--;
  89. }
  90. }
  91. return result;
  92. }
  93. /// <summary>
  94. /// Returns true if cmdSN1 should be executed before cmdSN2
  95. /// </summary>
  96. public static bool IsFirstCmdSNPreceding(uint cmdSN1, uint cmdSN2)
  97. {
  98. // The iSCSI protocol is designed to avoid having old, retried command instances appear in a valid command window after a command sequence number wrap around.
  99. const uint commandWindow = 2 ^ 31 - 1;
  100. if (cmdSN2 >= commandWindow)
  101. {
  102. if ((cmdSN1 > cmdSN2 - commandWindow) && (cmdSN1 < cmdSN2))
  103. {
  104. return true;
  105. }
  106. }
  107. else
  108. {
  109. if ((cmdSN1 > cmdSN2 - commandWindow) || (cmdSN1 < cmdSN2))
  110. {
  111. return true;
  112. }
  113. }
  114. return false;
  115. }
  116. }
  117. }