Source code of Windows XP (NT5)
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.

306 lines
8.7 KiB

  1. #include "mpio.h"
  2. NTSTATUS
  3. MPIOInitiateFailOver(
  4. IN PDEVICE_OBJECT DeviceObject,
  5. IN PVOID FailingPath,
  6. IN ULONG ErrorMask
  7. )
  8. {
  9. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  10. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  11. PDSM_ENTRY dsm = &diskExtension->DsmInfo;
  12. PREAL_DEV_INFO targetInfo;
  13. PVOID newPath = NULL;
  14. NTSTATUS status;
  15. WCHAR buffer[64];
  16. MPDebugPrint((0,
  17. "InitiateFailOver: Invalidating %x\n",
  18. FailingPath));
  19. //
  20. // Initiate the fail-over.
  21. //
  22. status = dsm->InvalidatePath(dsm->DsmContext,
  23. ErrorMask,
  24. FailingPath,
  25. &newPath);
  26. MPDebugPrint((0,
  27. "InitiateFailOver: New Path (%x)\n",
  28. newPath));
  29. //
  30. // TODO - Put in real Path identiifiers.
  31. //
  32. swprintf(buffer,L"Path (%x) Failed Over to (%x)", FailingPath, newPath);
  33. MPIOFireEvent(DeviceObject,
  34. L"MPIO WrkerThrd",
  35. buffer,
  36. MPIO_WARNING);
  37. //
  38. // If successful, go into DEGRADED
  39. //
  40. if ((status == STATUS_SUCCESS) && newPath) {
  41. //
  42. // Ensure that newPath actually is found in one of the TargetInfo
  43. // structures that make up this mpdisk.
  44. //
  45. targetInfo = MPIOGetTargetInfo(diskExtension,
  46. newPath,
  47. NULL);
  48. if (targetInfo == NULL) {
  49. MPDebugPrint((0,
  50. "MPIOInitiateFailOver: No match for path (%x)\n",
  51. newPath));
  52. DbgBreakPoint();
  53. return STATUS_NO_SUCH_DEVICE;
  54. }
  55. ASSERT(newPath == targetInfo->PathId);
  56. //
  57. // Verify that this path/device combo. is ready.
  58. //
  59. status = dsm->PathVerify(dsm->DsmContext,
  60. targetInfo->DsmID,
  61. targetInfo->PathId);
  62. if (!NT_SUCCESS(status)) {
  63. MPDebugPrint((0,
  64. "MPIOInitiateFailOver: PathVerify failed (%x)\n",
  65. status));
  66. //
  67. // Log.
  68. //
  69. return status;
  70. }
  71. //
  72. // Ensure the new path is active.
  73. // Invalidate path should have done everything to assure that
  74. // the new device(s) are ready.
  75. //
  76. targetInfo->PathActive = dsm->IsPathActive(dsm->DsmContext,
  77. newPath);
  78. ASSERT(targetInfo->PathActive);
  79. //
  80. // Set CurrentPath to this new one.
  81. //
  82. diskExtension->CurrentPath = newPath;
  83. //
  84. // Update all that are using this path, that it has changed.
  85. //
  86. MPIOSetNewPath(diskExtension->ControlObject,
  87. newPath);
  88. } else {
  89. if (newPath == NULL) {
  90. MPDebugPrint((0,
  91. "MPIOInitiateFailOver: DSM returned NULL path\n"));
  92. }
  93. if (status != STATUS_SUCCESS) {
  94. //
  95. // LOG
  96. //
  97. MPDebugPrint((0,
  98. "MPIOInitiateFailOver: DSM returned (%x)\n",
  99. status));
  100. }
  101. //
  102. // Set the path to NULL. The callback will key off this and the bad status.
  103. //
  104. diskExtension->CurrentPath = NULL;
  105. DbgBreakPoint();
  106. }
  107. return status;
  108. }
  109. VOID
  110. MPIORecoveryThread(
  111. IN PVOID Context
  112. )
  113. /*++
  114. Routine Description:
  115. This routine is the thread proc that is started upon creation of an mpdisk.
  116. When signaled, it will initiate the fail-over, insure that the new path is
  117. ready, then call-back the mpdisk to indicate success or failure of the operation.
  118. Arguments:
  119. Context - Info needed to handle the fail-over.
  120. Return Value:
  121. None.
  122. --*/
  123. {
  124. PMPIO_THREAD_CONTEXT context = Context;
  125. PDEVICE_OBJECT deviceObject = context->DeviceObject;
  126. PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
  127. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  128. PKEVENT event = context->Event;
  129. PVOID failingPath;
  130. MPIO_CALLBACK RequestComplete;
  131. PMPIO_REQUEST_INFO requestInfo;
  132. PLIST_ENTRY entry;
  133. NTSTATUS status;
  134. ULONG i;
  135. KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
  136. while (TRUE) {
  137. //
  138. // Wait on the event.
  139. //
  140. KeWaitForSingleObject(event,
  141. Executive,
  142. KernelMode,
  143. FALSE,
  144. NULL);
  145. KeClearEvent(event);
  146. //
  147. // Yank the packet.
  148. //
  149. entry = ExInterlockedRemoveHeadList(&diskExtension->WorkList,
  150. &diskExtension->WorkListLock);
  151. ASSERT(entry);
  152. //
  153. // Get the actual work item.
  154. //
  155. requestInfo = CONTAINING_RECORD(entry, MPIO_REQUEST_INFO, ListEntry);
  156. //
  157. // Get the call-back proc.
  158. //
  159. RequestComplete = requestInfo->RequestComplete;
  160. //
  161. // Determine the operation.
  162. //
  163. if (requestInfo->Operation == INITIATE_FAILOVER) {
  164. //
  165. // Get the device that indicated the failure.
  166. //
  167. failingPath = requestInfo->OperationSpecificInfo;
  168. //
  169. // Asking for a fail-over. Call the handler.
  170. //
  171. status = MPIOInitiateFailOver(deviceObject,
  172. failingPath,
  173. requestInfo->ErrorMask);
  174. } else if (requestInfo->Operation == SHUTDOWN) {
  175. //
  176. // Being signaled to die.
  177. //
  178. ExFreePool(requestInfo);
  179. goto terminateThread;
  180. } else if (requestInfo->Operation == FORCE_RESCAN) {
  181. PFLTR_ENTRY fltrEntry;
  182. fltrEntry = (PFLTR_ENTRY)(requestInfo->OperationSpecificInfo);
  183. MPIOForceRescan(fltrEntry->FilterObject);
  184. //
  185. // Indicate that the rescan is complete.
  186. //
  187. fltrEntry->Flags &= ~FLTR_FLAGS_RESCANNING;
  188. } else if (requestInfo->Operation == PATH_REMOVAL) {
  189. PDSM_ENTRY dsm = &diskExtension->DsmInfo;
  190. MPDebugPrint((0,
  191. "RecoveryThread: Removing Path (%x)\n",
  192. requestInfo->OperationSpecificInfo));
  193. //
  194. // Call the dsm to clean up. All of the devices have been
  195. // removed, and any pending actions have been completed, so
  196. // it's safe to do this now.
  197. //
  198. dsm->RemovePath(dsm->DsmContext,
  199. requestInfo->OperationSpecificInfo);
  200. } else if (requestInfo->Operation == DEVICE_REMOVAL) {
  201. PMPIO_DEVICE_REMOVAL deviceRemoval = requestInfo->OperationSpecificInfo;
  202. MPDebugPrint((0,
  203. "RecoveryThread: Removing Device (%x) DsmID (%x)\n",
  204. deviceRemoval->TargetInfo,
  205. deviceRemoval->TargetInfo->DsmID));
  206. //
  207. // Invoke the remove routine.
  208. //
  209. status = MPIORemoveDeviceAsync(deviceRemoval->DeviceObject,
  210. deviceRemoval->TargetInfo);
  211. //
  212. // Free this allocation.
  213. //
  214. ExFreePool(deviceRemoval);
  215. } else {
  216. MPDebugPrint((0,
  217. "MPIORecoveryThread: Invalid operation (%x) in (%x)\n",
  218. requestInfo->Operation,
  219. requestInfo));
  220. ASSERT(FALSE);
  221. }
  222. if (RequestComplete) {
  223. //
  224. // Invoke the call-back routine to indicate
  225. // completion.
  226. //
  227. RequestComplete(deviceObject,
  228. requestInfo->Operation,
  229. status);
  230. if (requestInfo->Operation == INITIATE_FAILOVER) {
  231. //
  232. // Force a rescan on the disks adapters.
  233. //
  234. for (i = 0; i < diskExtension->TargetInfoCount; i++ ) {
  235. MPIOForceRescan(diskExtension->TargetInfo[i].DevFilter);
  236. }
  237. }
  238. }
  239. //
  240. // Dispose of the work item.
  241. //
  242. ExFreePool(requestInfo);
  243. }
  244. terminateThread:
  245. PsTerminateSystemThread(STATUS_SUCCESS);
  246. }