Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

389 lines
7.9 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. gateway.c
  5. Abstract:
  6. Declaration of a gateway class that manages multiple interrelated
  7. sub-devices on a device.
  8. The IO gateway keeps track of elements queued to a device. The
  9. gateway is only necessary for device/driver pairs that have multiple
  10. independent device queues per physical device. A SCSI port driver,
  11. for example, can queue items on a per-logical-unit basis instead of
  12. per-HBA basis. The advantage of a per-logical-unit queue is that if a
  13. logical-unit becomes busy, requests for different logical units can
  14. be submitted to the adapter while the first logical unit is frozen.
  15. The gateway object is the object that coordinates the communication
  16. to the physical HBA.
  17. ---
  18. ------------- | H |
  19. | LUN 1 Queue | --> | B |
  20. ------------- | A |
  21. | | ----------
  22. ------------- | G | | |
  23. | LUN 2 Queue | --> | a | --> | HBA ----
  24. ------------- | t | | |
  25. | e | ------
  26. ------------- | w |
  27. | LUN 1 Queue | --> | a |
  28. ------------- | y |
  29. ---
  30. The gateway keeps track of whether the HBA is busy or frozen, how
  31. many outstanding requests are on the HBA, and, when the HBA is busy,
  32. the algorithm it uses to clear it's busy state.
  33. Author:
  34. Matthew D Hendel (math) 15-June-2000
  35. Revision History:
  36. --*/
  37. #include "precomp.h"
  38. INLINE
  39. VOID
  40. ASSERT_GATEWAY(
  41. IN PSTOR_IO_GATEWAY Gateway
  42. )
  43. {
  44. #if DBG
  45. ASSERT (Gateway->BusyRoutine != NULL);
  46. ASSERT (Gateway->BusyCount >= 0);
  47. ASSERT (Gateway->PauseCount >= 0);
  48. #endif
  49. }
  50. VOID
  51. StorCreateIoGateway(
  52. IN PSTOR_IO_GATEWAY Gateway,
  53. IN PSTOR_IO_GATEWAY_BUSY_ROUTINE BusyRoutine,
  54. IN PVOID BusyContext
  55. )
  56. /*++
  57. Routine Description:
  58. Create an IO gateway.
  59. Arguments:
  60. Gateway - IO Gateway to create.
  61. BusyAlgorithm - Description of the algorithm to use and associated
  62. parameters when the gatway is busy.
  63. Return Value:
  64. None.
  65. --*/
  66. {
  67. ASSERT (BusyRoutine != NULL);
  68. RtlZeroMemory (Gateway, sizeof (STOR_IO_GATEWAY));
  69. //
  70. // The initial high and low water marks are somewhat irrelevant since
  71. // we will define these when we get busied.
  72. //
  73. Gateway->HighWaterMark = MAXLONG;
  74. Gateway->LowWaterMark = MAXLONG;
  75. Gateway->BusyRoutine = BusyRoutine;
  76. Gateway->BusyContext = BusyContext;
  77. KeInitializeSpinLock (&Gateway->Lock);
  78. }
  79. BOOLEAN
  80. StorSubmitIoGatewayItem(
  81. IN PSTOR_IO_GATEWAY Gateway
  82. )
  83. /*++
  84. Routine Description:
  85. Attempt to submit an item to the gateway.
  86. Arguments:
  87. Gateway - Gateway to submit the item to.
  88. Return Value:
  89. TRUE - If the item can be submitted to the underlying hardware.
  90. FALSE - If the underlying hardware is currently busy with other
  91. requests and the request should be held until the hardware is
  92. ready to process more requets.
  93. --*/
  94. {
  95. BOOLEAN Ready;
  96. KLOCK_QUEUE_HANDLE LockHandle;
  97. //
  98. // PERF NOTE: This is the only adapter-wide lock aquisition done
  99. // for an IO. Therefore, we can suppose it is the hottest lock
  100. // in raidport (this remains to be seen from performance data).
  101. // We should seriously investigate a way to either eliminate this
  102. // lock or to turn it into a series of interlocked operations.
  103. // Do not do any significant processing while this lock is held.
  104. //
  105. KeAcquireInStackQueuedSpinLockAtDpcLevel (&Gateway->Lock, &LockHandle);
  106. //
  107. // If the gateway is busy or paused, do not submit it.
  108. //
  109. if (Gateway->BusyCount > 0 ||
  110. Gateway->PauseCount > 0 ||
  111. Gateway->Outstanding >= Gateway->HighWaterMark) {
  112. Ready = FALSE;
  113. } else {
  114. Gateway->Outstanding++;
  115. if (Gateway->Outstanding >= Gateway->HighWaterMark) {
  116. Gateway->BusyCount = TRUE;
  117. }
  118. Ready = TRUE;
  119. }
  120. KeReleaseInStackQueuedSpinLockFromDpcLevel (&LockHandle);
  121. return Ready;
  122. }
  123. BOOLEAN
  124. StorIsIoGatewayBusy(
  125. IN PSTOR_IO_GATEWAY Gateway
  126. )
  127. {
  128. return (Gateway->BusyCount >= 1);
  129. }
  130. BOOLEAN
  131. StorRemoveIoGatewayItem(
  132. IN PSTOR_IO_GATEWAY Gateway
  133. )
  134. /*++
  135. Routine Description:
  136. Notify the gateway that an item has been completed.
  137. Arguments:
  138. Gateway - Gateway to submit notification to.
  139. Return Value:
  140. TRUE - If the completion of this item transitions the gateway from a
  141. busy state to a non-busy state. In this case, the unit queues
  142. that submit items to the gateway need to be restarted.
  143. FALSE - If this completion did not change the busy state of the
  144. gateway.
  145. --*/
  146. {
  147. BOOLEAN Restart;
  148. KLOCK_QUEUE_HANDLE LockHandle;
  149. //
  150. // PERF NOTE: This is the only adapter-wide lock used by the system
  151. // in the IO path. See perf note in RaidAdapterGatewaySubmitItem.
  152. //
  153. KeAcquireInStackQueuedSpinLockAtDpcLevel (&Gateway->Lock, &LockHandle);
  154. Gateway->Outstanding--;
  155. ASSERT (Gateway->Outstanding >= 0);
  156. if ((Gateway->BusyCount > 0) &&
  157. (Gateway->Outstanding <= Gateway->LowWaterMark)) {
  158. Gateway->BusyCount = FALSE;
  159. Restart = TRUE; // (Gateway->BusyCount == 0) ? TRUE : FALSE;
  160. } else {
  161. Restart = FALSE;
  162. }
  163. //
  164. // There are no more outstanding requests, so clear the event.
  165. //
  166. if (Gateway->EmptyEvent && Gateway->Outstanding == 0) {
  167. KeSetEvent (Gateway->EmptyEvent, IO_NO_INCREMENT, FALSE);
  168. Gateway->EmptyEvent = NULL;
  169. }
  170. KeReleaseInStackQueuedSpinLockFromDpcLevel (&LockHandle);
  171. return Restart;
  172. }
  173. VOID
  174. StorBusyIoGateway(
  175. IN PSTOR_IO_GATEWAY Gateway
  176. )
  177. /*++
  178. Routine Description:
  179. Place the gateway into the busy state. The gateway will stay busy
  180. until the number of requests has drained to a specific level.
  181. Arguments:
  182. Gateway - The gateway to make busy.
  183. Return Value:
  184. None.
  185. --*/
  186. {
  187. //
  188. // The adapter MUST have some outstanding requests if it's claiming
  189. // to be busy.
  190. //
  191. //
  192. // Invoke the supplied busy routine to modify the high/low-water marks.
  193. //
  194. if (Gateway->BusyCount) {
  195. return ;
  196. }
  197. Gateway->BusyRoutine (Gateway->BusyContext,
  198. Gateway->Outstanding - 1,
  199. &Gateway->HighWaterMark,
  200. &Gateway->LowWaterMark);
  201. Gateway->BusyCount = TRUE;
  202. }
  203. LONG
  204. StorPauseIoGateway(
  205. IN PSTOR_IO_GATEWAY Gateway
  206. )
  207. /*++
  208. Routine Description:
  209. Place the gateway into the paused state.
  210. Arguments:
  211. Gateway - Supplies the gateway to pause.
  212. Return Value:
  213. Pause count for the gateway.
  214. --*/
  215. {
  216. return InterlockedIncrement (&Gateway->PauseCount);
  217. }
  218. LONG
  219. StorResumeIoGateway(
  220. IN OUT PSTOR_IO_GATEWAY Gateway
  221. )
  222. /*++
  223. Routine Description:
  224. Resume the gateway.
  225. Arguments:
  226. Gateway - Supplies the gateway to resume.
  227. Return Value:
  228. Current pause count for the gateway.
  229. --*/
  230. {
  231. LONG Count;
  232. Count = InterlockedDecrement (&Gateway->PauseCount);
  233. ASSERT (Count >= 0);
  234. return Count;
  235. }
  236. BOOLEAN
  237. StorIsIoGatewayPaused(
  238. IN PSTOR_IO_GATEWAY Gateway
  239. )
  240. /*++
  241. Routine Description:
  242. Returns TRUE if the gateway is currently paused, else FALSE.
  243. Arguments:
  244. Gateway - Supplies the gateway to check.
  245. Return Value:
  246. None.
  247. --*/
  248. {
  249. ASSERT (Gateway->PauseCount >= 0);
  250. return (Gateway->PauseCount != 0);
  251. }
  252. VOID
  253. StorSetIoGatewayEmptyEvent(
  254. IN PSTOR_IO_GATEWAY Gateway,
  255. IN PKEVENT Event
  256. )
  257. {
  258. KLOCK_QUEUE_HANDLE LockHandle;
  259. //
  260. // BUGBUG: This is bad. Instead, the event should be owned by the gateway,
  261. // we should give it out (and reference count it), so that multiple
  262. // clients can use it. Need to figure out how to do this so we don't
  263. // lock the dispatcher database twice per I/O.
  264. //
  265. KeAcquireInStackQueuedSpinLock (&Gateway->Lock, &LockHandle);
  266. if (Gateway->Outstanding == 0) {
  267. KeSetEvent (Event, IO_NO_INCREMENT, FALSE);
  268. } else {
  269. Gateway->EmptyEvent = Event;
  270. }
  271. KeReleaseInStackQueuedSpinLock (&LockHandle);
  272. }