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.

1534 lines
42 KiB

  1. /*++
  2. Copyright (C) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. mpath.c
  5. Abstract:
  6. The main multi-path module. Provides fault tolerance across adapter/path failures.
  7. Author:
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. Revision History:
  12. --*/
  13. #include <ntddk.h>
  14. #include "stdarg.h"
  15. #include "stdio.h"
  16. #include "mpio.h"
  17. //
  18. // Entry point decl's.
  19. //
  20. NTSTATUS
  21. DriverEntry(
  22. IN PDRIVER_OBJECT DriverObject,
  23. IN PUNICODE_STRING RegistryPath
  24. );
  25. NTSTATUS
  26. MPIOGlobalDispatch(
  27. IN PDEVICE_OBJECT DeviceObject,
  28. IN PIRP Irp
  29. );
  30. NTSTATUS
  31. MPIOAddDevice(
  32. IN PDRIVER_OBJECT DriverObject,
  33. IN PDEVICE_OBJECT PhysicalDeviceObject
  34. );
  35. NTSTATUS
  36. MPIOCreate(
  37. IN PDEVICE_OBJECT DeviceObject,
  38. IN PIRP Irp
  39. );
  40. NTSTATUS
  41. MPIOClose(
  42. IN PDEVICE_OBJECT DeviceObject,
  43. IN PIRP Irp
  44. );
  45. NTSTATUS
  46. MPIOWmiDispatch(
  47. IN PDEVICE_OBJECT DeviceObject,
  48. IN PIRP Irp
  49. );
  50. NTSTATUS
  51. MPIOUnload(
  52. IN PDRIVER_OBJECT DriverObject
  53. );
  54. typedef
  55. NTSTATUS
  56. (*PMPIO_DISPATCH) (
  57. IN PDEVICE_OBJECT DeviceObject,
  58. IN PIRP Irp,
  59. IN PMPIO_CONTEXT Context
  60. );
  61. // PMPIO_DISPATCH PdoDispatch[IRP_MJ_MAXIMUM_FUNCTION];
  62. PDRIVER_DISPATCH PdoDispatch[IRP_MJ_MAXIMUM_FUNCTION];
  63. PDRIVER_DISPATCH FdoDispatch[IRP_MJ_MAXIMUM_FUNCTION];
  64. NTSTATUS
  65. MPIOPdoDispatch(
  66. IN PDEVICE_OBJECT DeviceObject,
  67. IN PIRP Irp,
  68. IN ULONG State
  69. );
  70. BOOLEAN DoASSERT = TRUE;
  71. NTSTATUS
  72. DriverEntry(
  73. IN PDRIVER_OBJECT DriverObject,
  74. IN PUNICODE_STRING RegistryPath
  75. )
  76. /*++
  77. Routine Description:
  78. This routine is called when the driver loads loads.
  79. Arguments:
  80. DriverObject - Supplies the driver object.
  81. RegistryPath - Supplies the registry path.
  82. Return Value:
  83. NTSTATUS
  84. --*/
  85. {
  86. PDEVICE_OBJECT deviceObject;
  87. PDEVICE_EXTENSION deviceExtension;
  88. NTSTATUS status;
  89. PDEVICE_OBJECT pdo;
  90. ULONG i;
  91. MPDebugPrint((0,
  92. "MPIO: Driver Entry\n"));
  93. if (DontLoad) {
  94. return STATUS_NO_SUCH_DEVICE;
  95. }
  96. //
  97. // Register the entry points for all IRP_MJ's.
  98. //
  99. DriverObject->MajorFunction[IRP_MJ_CREATE] = MPIOCreate;
  100. DriverObject->MajorFunction[IRP_MJ_CLOSE] = MPIOClose;
  101. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MPIOGlobalDispatch;
  102. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MPIOGlobalDispatch;
  103. DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = MPIOGlobalDispatch;
  104. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = MPIOGlobalDispatch;
  105. DriverObject->MajorFunction[IRP_MJ_PNP] = MPIOGlobalDispatch;
  106. DriverObject->MajorFunction[IRP_MJ_POWER] = MPIOGlobalDispatch;
  107. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = MPIOWmiDispatch;
  108. //
  109. // Register the Unload.
  110. //
  111. DriverObject->DriverUnload = MPIOUnload;
  112. ObReferenceObject(DriverObject);
  113. pdo = NULL;
  114. //
  115. // Notify PnP that this 'device' was found.
  116. // Indicate no resources, no bus location, and lie that
  117. // resources were reported (as we need none).
  118. //
  119. status = IoReportDetectedDevice(DriverObject,
  120. InterfaceTypeUndefined,
  121. -1,
  122. -1,
  123. NULL,
  124. NULL,
  125. TRUE,
  126. &pdo);
  127. if (!NT_SUCCESS(status)) {
  128. MPDebugPrint((0,
  129. "Multipath DriverEntry: IoReportDetectedDevice returned (%x)\n",
  130. status));
  131. ObDereferenceObject(DriverObject);
  132. return status;
  133. }
  134. //
  135. // Create the fdo. Not really an AddDevice routine
  136. // but name it as such.
  137. //
  138. status = MPIOAddDevice(DriverObject,
  139. pdo);
  140. if (!NT_SUCCESS(status)) {
  141. MPDebugPrint((0,
  142. "MPIO DriverEntry: AddDevice failed (%x)\n",
  143. status));
  144. ObDereferenceObject(DriverObject);
  145. return status;
  146. }
  147. //
  148. // Get deviceObject (fdo) and deviceExtension.
  149. //
  150. deviceObject = IoGetAttachedDeviceReference(pdo);
  151. ObDereferenceObject(deviceObject);
  152. deviceExtension = deviceObject->DeviceExtension;
  153. //
  154. // Setup the device extension.
  155. //
  156. deviceExtension->Pdo = pdo;
  157. deviceExtension->RegistryPath.Buffer = ExAllocatePool(NonPagedPool,
  158. RegistryPath->MaximumLength);
  159. deviceExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
  160. RtlCopyUnicodeString(&deviceExtension->RegistryPath,
  161. RegistryPath);
  162. //
  163. // Setup the Pdo's dispatch routines.
  164. //
  165. for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
  166. PdoDispatch[i] = MPIOPdoUnhandled;
  167. }
  168. PdoDispatch[IRP_MJ_DEVICE_CONTROL] = MPIOPdoDeviceControl;
  169. PdoDispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MPIOPdoInternalDeviceControl;
  170. PdoDispatch[IRP_MJ_PNP] = MPIOPdoPnp;
  171. PdoDispatch[IRP_MJ_POWER] = MPIOPdoPower;
  172. MPathDebug = 1;
  173. return status;
  174. }
  175. NTSTATUS
  176. MPIOAddDevice(
  177. IN PDRIVER_OBJECT DriverObject,
  178. IN PDEVICE_OBJECT PhysicalDeviceObject
  179. )
  180. /*++
  181. Routine Description:
  182. This routine creates and initializes a new FDO for the corresponding
  183. PDO.
  184. Arguments:
  185. DriverObject - Supplies the driver object for mpath control.
  186. PhysicalDeviceObject - Supplies the physical device object.
  187. Return Value:
  188. NTSTATUS
  189. --*/
  190. {
  191. PDEVICE_EXTENSION deviceExtension;
  192. PCONTROL_EXTENSION controlExtension;
  193. UNICODE_STRING deviceName;
  194. UNICODE_STRING dosName;
  195. PDEVICE_OBJECT deviceObject;
  196. NTSTATUS status;
  197. RtlInitUnicodeString(&deviceName, DD_MULTIPATH_CONTROL_DEVICE_NAME);
  198. //
  199. // Create the fdo.
  200. //
  201. status = IoCreateDevice(DriverObject,
  202. sizeof(DEVICE_EXTENSION),
  203. &deviceName,
  204. FILE_DEVICE_CONTROLLER,
  205. FILE_DEVICE_SECURE_OPEN,
  206. FALSE,
  207. &deviceObject);
  208. if (!NT_SUCCESS(status)) {
  209. return status;
  210. }
  211. controlExtension = ExAllocatePool(NonPagedPool, sizeof(CONTROL_EXTENSION));
  212. if (controlExtension == NULL) {
  213. IoDeleteDevice(deviceObject);
  214. return STATUS_INSUFFICIENT_RESOURCES;
  215. }
  216. RtlZeroMemory(controlExtension, sizeof(CONTROL_EXTENSION));
  217. //
  218. // Create the symbolic link.
  219. //
  220. RtlInitUnicodeString(&dosName, DD_MULTIPATH_CONTROL_DOS_NAME);
  221. IoCreateSymbolicLink( &dosName, &deviceName);
  222. //
  223. // Save off devObj and build the device extension.
  224. //
  225. deviceExtension = deviceObject->DeviceExtension;
  226. deviceExtension->Type = MPIO_CONTROL;
  227. deviceExtension->DeviceObject = deviceObject;
  228. deviceExtension->DriverObject = DriverObject;
  229. //
  230. // Attach to the pdo.
  231. //
  232. deviceExtension->LowerDevice = IoAttachDeviceToDeviceStack(deviceObject,
  233. PhysicalDeviceObject);
  234. if (deviceExtension->LowerDevice == NULL) {
  235. IoDeleteSymbolicLink(&dosName);
  236. IoDeleteDevice(deviceObject);
  237. return STATUS_NO_SUCH_DEVICE;
  238. }
  239. deviceExtension->Pdo = PhysicalDeviceObject;
  240. deviceExtension->TypeExtension = controlExtension;
  241. //
  242. // Initialize the 'control' portion of the device extension.
  243. //
  244. KeInitializeSpinLock(&controlExtension->SpinLock);
  245. InitializeListHead(&controlExtension->FilterList);
  246. InitializeListHead(&controlExtension->DeviceList);
  247. InitializeListHead(&controlExtension->DsmList);
  248. InitializeListHead(&controlExtension->IdList);
  249. InitializeListHead(&controlExtension->ControllerList);
  250. InitializeListHead(&controlExtension->FailPacketList);
  251. //
  252. // Set-up the WMILIB Context.
  253. //
  254. MPIOSetupWmi(deviceObject);
  255. //
  256. // Register as a WMI provider.
  257. //
  258. IoWMIRegistrationControl(deviceObject,
  259. WMIREG_ACTION_REGISTER);
  260. //
  261. // Indicate that this device is ready.
  262. //
  263. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  264. return status;
  265. }
  266. NTSTATUS
  267. MPIOCreate(
  268. IN PDEVICE_OBJECT DeviceObject,
  269. IN PIRP Irp
  270. )
  271. /*++
  272. Routine Description:
  273. This routine is the dispatch for IRP_MJ_CREATE.
  274. Arguments:
  275. DeviceObject - Supplies the device object.
  276. Irp - Supplies the IO request block.
  277. Return Value:
  278. NTSTATUS
  279. --*/
  280. {
  281. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  282. NTSTATUS status;
  283. Irp->IoStatus.Status = STATUS_SUCCESS;
  284. Irp->IoStatus.Information = 0;
  285. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  286. return STATUS_SUCCESS;
  287. }
  288. NTSTATUS
  289. MPIOClose(
  290. IN PDEVICE_OBJECT DeviceObject,
  291. IN PIRP Irp
  292. )
  293. /*++
  294. Routine Description:
  295. This routine is the dispatch for IRP_MJ_CLOSE
  296. Arguments:
  297. DeviceObject - Supplies the device object.
  298. Irp - Supplies the IO request block.
  299. Return Value:
  300. NTSTATUS
  301. --*/
  302. {
  303. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  304. NTSTATUS status;
  305. Irp->IoStatus.Status = STATUS_SUCCESS;
  306. Irp->IoStatus.Information = 0;
  307. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  308. return STATUS_SUCCESS;
  309. }
  310. NTSTATUS
  311. MPIOUnload(
  312. IN PDRIVER_OBJECT DriverObject
  313. )
  314. /*++
  315. Routine Description:
  316. This routine unloads.
  317. Arguments:
  318. DriverObject - Supplies the driver object.
  319. Return Value:
  320. None.
  321. --*/
  322. {
  323. //
  324. // TODO: Release all allocations.
  325. // TODO: Ensure pdo's/DSMs have been torndown.
  326. //
  327. ObDereferenceObject(DriverObject);
  328. return STATUS_SUCCESS;
  329. }
  330. NTSTATUS
  331. MPPdoGlobalCompletion(
  332. IN PDEVICE_OBJECT DeviceObject,
  333. IN PIRP Irp,
  334. IN PVOID Context
  335. )
  336. /*++
  337. Routine Description:
  338. All requests to the pdo's have this as the completion. It handles calling out to
  339. the function-specific completions and deals with errors.
  340. Arguments:
  341. Return Value:
  342. NTSTATUS
  343. --*/
  344. {
  345. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  346. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  347. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  348. PDSM_ENTRY dsm = &diskExtension->DsmInfo;
  349. PMPIO_CONTEXT context = Context;
  350. PSCSI_REQUEST_BLOCK srb = NULL;
  351. PMPIO_COMPLETION_ROUTINE specificCompletion;
  352. PKDEVICE_QUEUE_ENTRY entry;
  353. PREAL_DEV_INFO targetInfo;
  354. PREAL_DEV_INFO newTargetInfo;
  355. PDEVICE_OBJECT targetObject;
  356. NTSTATUS status;
  357. NTSTATUS status2;
  358. PVOID dsmId;
  359. PVOID dsmContext;
  360. DSM_COMPLETION_ROUTINE dsmCompletion;
  361. ULONG errorMask = 0;
  362. ULONG completionState = context->CurrentState;
  363. ULONG state;
  364. ULONG state2;
  365. LONG outstandingRequests;
  366. LONG deviceRequests;
  367. BOOLEAN fatal = FALSE;
  368. BOOLEAN retry = FALSE;
  369. BOOLEAN needsRemoval = FALSE;
  370. BOOLEAN currentRequestHandled;
  371. if (Irp->PendingReturned) {
  372. IoMarkIrpPending(Irp);
  373. }
  374. //
  375. // Get the targetInfo. This describes the device.
  376. //
  377. targetInfo = context->TargetInfo;
  378. //
  379. // Get the number of requests on THIS device (vs. the entire disk).
  380. //
  381. deviceRequests = InterlockedDecrement(&targetInfo->Requests);
  382. //
  383. // One less request below us.
  384. //
  385. outstandingRequests = InterlockedDecrement(&diskExtension->OutstandingRequests);
  386. ASSERT(diskExtension->OutstandingRequests >= 0);
  387. if ((outstandingRequests == 0) && (deviceRequests != 0)) {
  388. //
  389. // If there are no requests for the disk, then there shouldn't be any of this
  390. // deviceInfo.
  391. //
  392. if (DoASSERT) {
  393. MPDebugPrint((0,
  394. "GlobalCompletion: DeviceRequests (%x)\n",
  395. deviceRequests));
  396. ASSERT(deviceRequests == 0);
  397. }
  398. }
  399. //
  400. // Get the config. spinlock.
  401. //
  402. KeAcquireSpinLockAtDpcLevel(&diskExtension->SpinLock);
  403. //
  404. // See whether there is a remove pending on this targetInfo.
  405. //
  406. if (targetInfo->NeedsRemoval) {
  407. needsRemoval = TRUE;
  408. }
  409. KeReleaseSpinLockFromDpcLevel(&diskExtension->SpinLock);
  410. //
  411. // For scsi requests, need to ensure that frozen queues
  412. // get released.
  413. //
  414. if (irpStack->MajorFunction == IRP_MJ_SCSI) {
  415. //
  416. // Get the srb.
  417. //
  418. srb = irpStack->Parameters.Scsi.Srb;
  419. //
  420. // Handle any frozen queue stuff.
  421. //
  422. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  423. //
  424. // Get the target object for this request.
  425. // NOTE: This assumes that the Function-Specific handler
  426. // has set this up correctly.
  427. //
  428. targetObject = targetInfo->PortPdo;
  429. MPLibReleaseQueue(targetObject);
  430. }
  431. }
  432. //
  433. // Extract the DSM-Specific stuff from the context.
  434. //
  435. dsmId = targetInfo->DsmID;
  436. dsmContext = context->DsmCompletion.DsmContext;
  437. dsmCompletion = context->DsmCompletion.DsmCompletionRoutine;
  438. //
  439. //
  440. // Determine the current state.
  441. //
  442. state = deviceExtension->State;
  443. if ((deviceExtension->CompletionState == MPIO_STATE_NORMAL) ||
  444. (deviceExtension->CompletionState == MPIO_STATE_DEGRADED)) {
  445. deviceExtension->CompletionState = state;
  446. }
  447. //
  448. // Indicate that this request hasn't been dealt with yet.
  449. //
  450. currentRequestHandled = FALSE;
  451. //
  452. // This call will update state information, but the request coming in
  453. // needs to be first handled with the current state.
  454. //
  455. state2 = MPIOHandleStateTransition(DeviceObject);
  456. runState:
  457. if ((state != MPIO_STATE_NORMAL) && (state != MPIO_STATE_DEGRADED)) {
  458. switch (state) {
  459. case MPIO_STATE_IN_FO:
  460. //
  461. // The fail-over is being executed. Put on resubmit Queue. (unless
  462. // status == success.
  463. //
  464. status2 = MPIOQueueRequest(DeviceObject,
  465. Irp,
  466. Context,
  467. &diskExtension->ResubmitQueue);
  468. state = MPIOHandleStateTransition(DeviceObject);
  469. if (state != MPIO_STATE_IN_FO) {
  470. MPDebugPrint((0,
  471. "GlobalCompletion: Going from IN_FO to (%x)\n",
  472. state));
  473. //
  474. // See if we've gone into WAIT2 directly.
  475. //
  476. if (state == MPIO_STATE_WAIT2) {
  477. //
  478. // Get the targetInfo corresponding to the path set-up in the
  479. // fail-over handler. Whatever was in the completion context is
  480. // probably not valid.
  481. // NOTE: This assumes that no-one is updating the CurrentPath
  482. // in the diskExtension. Probably not a good assumption.
  483. // TODO: Validate.
  484. //
  485. targetInfo = MPIOGetTargetInfo(diskExtension,
  486. diskExtension->CurrentPath,
  487. NULL);
  488. //
  489. // Submit the queued requests. These Resubmit requests all go
  490. // down "newPath". TODO: Indicate this behaviour in dsm.h
  491. //
  492. status = MPIOIssueQueuedRequests(targetInfo,
  493. &diskExtension->ResubmitQueue,
  494. MPIO_STATE_WAIT2,
  495. &diskExtension->OutstandingRequests);
  496. } else {
  497. //
  498. // Went into WAIT1.
  499. //
  500. currentRequestHandled = TRUE;
  501. goto runState;
  502. }
  503. }
  504. if (needsRemoval && (deviceRequests == 0)) {
  505. MPDebugPrint((0,
  506. "MPIOGlobalCompletion (IN_FO): Removing %x\n",
  507. targetInfo));
  508. //
  509. // This routine will queue a work item to handle the device removal.
  510. //
  511. MPIOHandleRemoveAsync(DeviceObject,
  512. targetInfo);
  513. }
  514. return STATUS_MORE_PROCESSING_REQUIRED;
  515. break;
  516. case MPIO_STATE_WAIT1: {
  517. //
  518. // This indicates that the fail-over was successful, but there
  519. // are still outstanding requests (on the failed path).
  520. // Status should be flushed, or some error condition, though
  521. // conceivable, a successful completion could have occurred.
  522. // One less request below us.
  523. //
  524. if (currentRequestHandled == FALSE) {
  525. //
  526. // Enqueue this request on the Resubmit Queue.
  527. //
  528. status2 = MPIOQueueRequest(DeviceObject,
  529. Irp,
  530. Context,
  531. &diskExtension->ResubmitQueue);
  532. if (needsRemoval && (deviceRequests == 0)) {
  533. MPDebugPrint((0,
  534. "MPIOGlobalCompletion (WAIT1): Removing %x\n",
  535. targetInfo));
  536. //
  537. // This routine will queue a work item to handle the device removal.
  538. //
  539. MPIOHandleRemoveAsync(DeviceObject,
  540. targetInfo);
  541. }
  542. }
  543. //
  544. // See if the has caused a move into a different state.
  545. //
  546. state = MPIOHandleStateTransition(DeviceObject);
  547. if (state != MPIO_STATE_WAIT1) {
  548. MPDebugPrint((0,
  549. "GlobalCompletion: Going from WAIT1 to (%x)\n",
  550. state));
  551. //
  552. // See if we've gone into WAIT2 directly.
  553. //
  554. if (state == MPIO_STATE_WAIT2) {
  555. //
  556. // Get the targetInfo corresponding to the path set-up in the
  557. // fail-over handler. Whatever was in the completion context is
  558. // probably not valid.
  559. // NOTE: This assumes that no-one is updating the CurrentPath
  560. // in the diskExtension. Probably not a good assumption.
  561. // TODO: Validate.
  562. //
  563. targetInfo = MPIOGetTargetInfo(diskExtension,
  564. diskExtension->CurrentPath,
  565. NULL);
  566. //
  567. // Submit the queued requests. These Resubmit requests all go
  568. // down "newPath". TODO: Indicate this behaviour in dsm.h
  569. //
  570. status = MPIOIssueQueuedRequests(targetInfo,
  571. &diskExtension->ResubmitQueue,
  572. MPIO_STATE_WAIT2,
  573. &diskExtension->OutstandingRequests);
  574. } else {
  575. currentRequestHandled = TRUE;
  576. goto runState;
  577. }
  578. }
  579. return STATUS_MORE_PROCESSING_REQUIRED;
  580. break;
  581. }
  582. case MPIO_STATE_WAIT2: {
  583. //
  584. // Dec the # of resubmit requests when zero, we go into WAIT3.
  585. // New requests on FOQ.
  586. //
  587. outstandingRequests = InterlockedDecrement(&diskExtension->ResubmitRequests);
  588. ASSERT(diskExtension->ResubmitRequests >= 0);
  589. state = MPIOHandleStateTransition(DeviceObject);
  590. if (state != MPIO_STATE_WAIT2) {
  591. MPDebugPrint((0,
  592. "GlobalCompletion: Going from WAIT2 to (%x)\n",
  593. state));
  594. if (state == MPIO_STATE_WAIT3) {
  595. //
  596. // Get the targetInfo corresponding to CurrentPath.
  597. //
  598. targetInfo = MPIOGetTargetInfo(diskExtension,
  599. diskExtension->CurrentPath,
  600. NULL);
  601. //
  602. // Process the Fail-Over queue.
  603. //
  604. status2 = MPIOIssueQueuedRequests(targetInfo,
  605. &diskExtension->FailOverQueue,
  606. MPIO_STATE_WAIT3,
  607. &diskExtension->OutstandingRequests);
  608. }
  609. }
  610. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  611. MPDebugPrint((0,
  612. "MPIOCompletion: !Success while in WAIT2. Irp (%x) Status (%x)\n",
  613. Irp,
  614. Irp->IoStatus.Status));
  615. }
  616. //
  617. // Now, handle the request normally.
  618. //
  619. break;
  620. }
  621. case MPIO_STATE_WAIT3: {
  622. //
  623. // Dec the # of fail-over requests. When zero, we go into DEGRADED.
  624. //
  625. outstandingRequests = InterlockedDecrement(&diskExtension->FailOverRequests);
  626. ASSERT(diskExtension->FailOverRequests >= 0);
  627. state = MPIOHandleStateTransition(DeviceObject);
  628. //
  629. // Continue down and handle the request normally.
  630. //
  631. break;
  632. }
  633. default:
  634. //
  635. // Invalid state.
  636. //
  637. MPDebugPrint((0,
  638. "MPIOCompletion: Unknown State (%x)\n",
  639. state));
  640. DbgBreakPoint();
  641. break;
  642. }
  643. } else {
  644. if (needsRemoval && (deviceRequests == 0)) {
  645. MPDebugPrint((0,
  646. "MPIOGlobalCompletion (WAIT1): Removing %x\n",
  647. targetInfo));
  648. //
  649. // This routine will queue a work item to handle the device removal.
  650. //
  651. MPIOHandleRemoveAsync(DeviceObject,
  652. targetInfo);
  653. }
  654. }
  655. status = Irp->IoStatus.Status;
  656. if (!NT_SUCCESS(status)) {
  657. fatal = FALSE;
  658. retry = FALSE;
  659. if (irpStack->MajorFunction == IRP_MJ_SCSI) {
  660. //
  661. // Invoke the DSM's InterpretError with preset fatal and retry
  662. // values.
  663. //
  664. errorMask = dsm->InterpretError(dsm->DsmContext,
  665. dsmId,
  666. srb,
  667. &status,
  668. &retry);
  669. if (errorMask & DSM_FATAL_ERROR) {
  670. fatal = TRUE;
  671. }
  672. }
  673. }
  674. if (fatal) {
  675. // if ((deviceExtension->LastState == MPIO_STATE_NORMAL) ||
  676. // (deviceExtension->LastState == MPIO_STATE_DEGRADED)) {
  677. diskExtension->FailOver = TRUE;
  678. state = MPIOHandleStateTransition(DeviceObject);
  679. // }
  680. //
  681. // Put the request on the resubmit queue.
  682. // This routine will also clean up the request and
  683. // prepare it for resubmission.
  684. //
  685. // BUGBUG: If we queue this, and the FailOver is unsuccessful, the request
  686. // will remain in the queue.
  687. //
  688. status2 = MPIOQueueRequest(DeviceObject,
  689. Irp,
  690. Context,
  691. &diskExtension->ResubmitQueue);
  692. MPDebugPrint((1,
  693. "MPIOCompletion: Irp (%x) Srb (%x) on resubmit queue of (%x). Status (%x)\n",
  694. Irp,
  695. srb,
  696. DeviceObject,
  697. status));
  698. //
  699. // Call the Fail-over Handler.
  700. //
  701. status2 = MPIOFailOverHandler(DeviceObject,
  702. errorMask,
  703. targetInfo);
  704. //
  705. // If the fail-over was successful or pending, don't let Io get rid of this
  706. // request.
  707. // If it wasn't successful, pass the original status back.
  708. //
  709. if ((status2 == STATUS_SUCCESS) ||
  710. (status2 == STATUS_PENDING)) {
  711. status = STATUS_MORE_PROCESSING_REQUIRED;
  712. } else {
  713. ASSERT(FALSE);
  714. }
  715. return status;
  716. } else if (retry) {
  717. //
  718. // If the DSM has requested a retry, clean-up the request and call PdoDispatch.
  719. //
  720. if (irpStack->MajorFunction == IRP_MJ_SCSI) {
  721. //
  722. // Need to rebuild the Srb.
  723. //
  724. RtlCopyMemory(irpStack->Parameters.Scsi.Srb,
  725. &context->Srb,
  726. sizeof(SCSI_REQUEST_BLOCK));
  727. }
  728. //
  729. // Re-do status and information.
  730. //
  731. Irp->IoStatus.Status = 0;
  732. Irp->IoStatus.Information = 0;
  733. //
  734. // Rebuild port's stack location.
  735. //
  736. IoCopyCurrentIrpStackLocationToNext(Irp);
  737. //
  738. // Resend.
  739. //
  740. status2 = MPIOPdoDispatch(DeviceObject,
  741. Irp,
  742. deviceExtension->State);
  743. if (status2 == STATUS_PENDING) {
  744. status = STATUS_MORE_PROCESSING_REQUIRED;
  745. } else {
  746. status = status2;
  747. }
  748. return status;
  749. }
  750. //
  751. // If the DSM specified a completion routine, invoke it now.
  752. //
  753. if (dsmCompletion) {
  754. dsmCompletion(dsmId,
  755. Irp,
  756. srb,
  757. dsmContext);
  758. }
  759. //
  760. // Free the context structure.
  761. //
  762. MPIOFreeContext(deviceExtension,
  763. Context);
  764. return status;
  765. }
  766. NTSTATUS
  767. MPIOPdoDispatch(
  768. IN PDEVICE_OBJECT DeviceObject,
  769. IN PIRP Irp,
  770. IN ULONG State
  771. )
  772. {
  773. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  774. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  775. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  776. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  777. ULONG sortKey = deviceExtension->SequenceNumber++;
  778. PMPIO_CONTEXT context;
  779. NTSTATUS status = STATUS_PENDING;
  780. KIRQL irql;
  781. UCHAR opCode = 0;
  782. ASSERT(deviceExtension->Type == MPIO_MPDISK);
  783. KeAcquireSpinLock(&diskExtension->SpinLock, &irql);
  784. //
  785. // Allocate the request context.
  786. //
  787. context = MPIOAllocateContext(deviceExtension);
  788. RtlZeroMemory(context, sizeof(MPIO_CONTEXT));
  789. //
  790. // Indicate this I/O's sequence number. Used in tracking
  791. // requests during fail-over and also as a key into the device queue.
  792. //
  793. context->CurrentState = State;
  794. context->OriginalState = State;
  795. context->Irp = Irp;
  796. context->Allocated = TRUE;
  797. //
  798. // Clone the irpstack location.
  799. //
  800. IoCopyCurrentIrpStackLocationToNext(Irp);
  801. //
  802. // Set the context in our stack.
  803. //
  804. irpStack->Parameters.Others.Argument4 = (PVOID)context;
  805. switch (State) {
  806. case MPIO_STATE_IN_FO:
  807. case MPIO_STATE_WAIT1: {
  808. //
  809. // As no requests will be submitted, release the lock now.
  810. //
  811. KeReleaseSpinLock(&diskExtension->SpinLock, irql);
  812. //
  813. // If in FO, or WAIT1 simply queue to the
  814. // Fail-Over Queue. Once the Fail-Over is complete and the
  815. // resubmit queue has been handled, the F.O.Q. will be dealt
  816. // with.
  817. //
  818. status = MPIOQueueRequest(DeviceObject,
  819. Irp,
  820. context,
  821. &diskExtension->FailOverQueue);
  822. //
  823. // This routine will only return success or insufficient resources.
  824. //
  825. if (status == STATUS_INSUFFICIENT_RESOURCES) {
  826. MPDebugPrint((1,
  827. "MPIOQueueRequest returned (%x). State (%x)\n",
  828. status,
  829. State));
  830. Irp->IoStatus.Status = status;
  831. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  832. return status;
  833. }
  834. //
  835. // Set pending.
  836. //
  837. IoMarkIrpPending(Irp);
  838. //
  839. // Return pending.
  840. //
  841. status = STATUS_PENDING;
  842. break;
  843. }
  844. case MPIO_STATE_WAIT2: {
  845. //
  846. // As no requests will be submitted, release the lock now.
  847. //
  848. KeReleaseSpinLock(&diskExtension->SpinLock, irql);
  849. //
  850. // The resubmit queue is being handled. These (like IN_FO and WAIT1)
  851. // go onto the Fail-Over queue.
  852. // This is seperated from the above States merely for administrative
  853. // reasons. (Unless it gets changed...)
  854. //
  855. status = MPIOQueueRequest(DeviceObject,
  856. Irp,
  857. context,
  858. &diskExtension->FailOverQueue);
  859. //
  860. // This routine will only return success or insufficient resources.
  861. //
  862. if (status == STATUS_INSUFFICIENT_RESOURCES) {
  863. MPDebugPrint((1,
  864. "MPIOQueueRequest returned (%x). State (%x)\n",
  865. status,
  866. State));
  867. Irp->IoStatus.Status = status;
  868. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  869. return status;
  870. }
  871. //
  872. // Set pending.
  873. //
  874. IoMarkIrpPending(Irp);
  875. //
  876. // Return pending.
  877. //
  878. status = STATUS_PENDING;
  879. break;
  880. }
  881. case MPIO_STATE_WAIT3: {
  882. //
  883. // Draining the Fail-Over queue. Complete these requests
  884. // with busy, if they are Srb's (build sense data, so that they
  885. // are retried). Otherwise, just return BUSY and hope for the best.
  886. // BUGBUG: Revisit handling of non-Srb requests. Maybe put these
  887. // on the F.O.Q...
  888. //
  889. MPDebugPrint((0,
  890. "PdoDispatch: Setting Irp(%x) Srb (%x) BUSY\n",
  891. Irp,
  892. srb));
  893. //
  894. // As no requests will be submitted, release the lock now.
  895. //
  896. KeReleaseSpinLock(&diskExtension->SpinLock, irql);
  897. if (irpStack->MajorFunction == IRP_MJ_SCSI) {
  898. RtlCopyMemory(&context->Srb,
  899. srb,
  900. sizeof(SCSI_REQUEST_BLOCK));
  901. //
  902. // This will build the appropriate sense data that indicates
  903. // to the class driver that the device is busy.
  904. //
  905. MPIOSetRequestBusy(srb);
  906. }
  907. //
  908. // All requests will be completed as BUSY.
  909. //
  910. status = STATUS_DEVICE_BUSY;
  911. Irp->IoStatus.Status = status;
  912. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  913. break;
  914. }
  915. case MPIO_STATE_NORMAL:
  916. case MPIO_STATE_DEGRADED: {
  917. //
  918. // All failure queues are empty and the new
  919. // path is functioning (DEGRADED) or all is working
  920. // fine (NORMAL).
  921. // Submit these requests normally.
  922. //
  923. // Indicate another request has been submitted.
  924. //
  925. InterlockedIncrement(&diskExtension->OutstandingRequests);
  926. //
  927. // Now it's safe to release the lock as the config. code checks
  928. // for outstanding requests.
  929. //
  930. KeReleaseSpinLock(&diskExtension->SpinLock, irql);
  931. //
  932. // Call FunctionSpecific handler.
  933. // The function-specific handler will set-up it's private
  934. // completion routine, along with the DSM information.
  935. //
  936. status = PdoDispatch[irpStack->MajorFunction](DeviceObject,
  937. Irp);
  938. break;
  939. }
  940. default:
  941. //
  942. // As no requests will be submitted, release the lock now.
  943. //
  944. KeReleaseSpinLock(&diskExtension->SpinLock, irql);
  945. //
  946. // TODO: Here only for test. Remove it.
  947. //
  948. MPDebugPrint((0,
  949. "MPIOPdoDispatch: Unknown State (%x)\n",
  950. State));
  951. DbgBreakPoint();
  952. break;
  953. }
  954. return status;
  955. }
  956. NTSTATUS
  957. MPIOFdoDispatch(
  958. IN PDEVICE_OBJECT DeviceObject,
  959. IN PIRP Irp,
  960. IN ULONG State
  961. )
  962. {
  963. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  964. NTSTATUS status;
  965. //
  966. // State is less important for the FDO: Perhaps of no importance.
  967. // Maybe:
  968. // Set Sequence #
  969. // Set completion.
  970. // Call FunctionSpecific Handler.
  971. //
  972. switch (irpStack->MajorFunction) {
  973. case IRP_MJ_PNP:
  974. status = MPIOFdoPnP(DeviceObject,
  975. Irp);
  976. break;
  977. case IRP_MJ_POWER:
  978. status = MPIOFdoPower(DeviceObject,
  979. Irp);
  980. break;
  981. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  982. status = MPIOFdoInternalDeviceControl(DeviceObject,
  983. Irp);
  984. break;
  985. case IRP_MJ_SYSTEM_CONTROL:
  986. status = MPIOFdoWmi(DeviceObject,
  987. Irp);
  988. break;
  989. case IRP_MJ_DEVICE_CONTROL:
  990. case IRP_MJ_SHUTDOWN:
  991. case IRP_MJ_FLUSH_BUFFERS:
  992. default:
  993. status = STATUS_INVALID_DEVICE_REQUEST;
  994. Irp->IoStatus.Status = status;
  995. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  996. break;
  997. }
  998. return status;
  999. }
  1000. NTSTATUS
  1001. MPIOWmiDispatch(
  1002. IN PDEVICE_OBJECT DeviceObject,
  1003. IN PIRP Irp
  1004. )
  1005. {
  1006. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1007. NTSTATUS status;
  1008. //
  1009. // Determine whether this is for the FDO or one of the PDOs.
  1010. //
  1011. if (deviceExtension->Type == MPIO_MPDISK) {
  1012. //
  1013. // Call the Pdo-specific handler
  1014. //
  1015. status = MPIOPdoWmi(DeviceObject,
  1016. Irp);
  1017. } else {
  1018. //
  1019. // Call the Fdo-specific handler (MPIO Control).
  1020. //
  1021. status = MPIOFdoDispatch(DeviceObject,
  1022. Irp,
  1023. deviceExtension->State);
  1024. }
  1025. return status;
  1026. }
  1027. NTSTATUS
  1028. MPIOGlobalDispatch(
  1029. IN PDEVICE_OBJECT DeviceObject,
  1030. IN PIRP Irp
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. This routine is the global dispatch routine for all requests.
  1035. Arguments:
  1036. DeviceObject - Supplies the device object.
  1037. Irp - Supplies the IO request block.
  1038. Return Value:
  1039. NTSTATUS
  1040. --*/
  1041. {
  1042. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1043. NTSTATUS status;
  1044. //
  1045. // Determine whether this is for the FDO or one of the PDOs.
  1046. //
  1047. if (deviceExtension->Type == MPIO_MPDISK) {
  1048. //
  1049. // Call the Pdo-specific handler (MPDISK). The routines under this will do
  1050. // everything needed, so just return the status.
  1051. //
  1052. status = MPIOPdoDispatch(DeviceObject,
  1053. Irp,
  1054. deviceExtension->State);
  1055. } else {
  1056. //
  1057. // Call the Fdo-specific handler (MPIO Control).
  1058. //
  1059. status = MPIOFdoDispatch(DeviceObject,
  1060. Irp,
  1061. deviceExtension->State);
  1062. }
  1063. return status;
  1064. }
  1065. //
  1066. // Routines exported to the DSMs
  1067. //
  1068. VOID
  1069. DsmSendDeviceIoControlSynchronous(
  1070. IN ULONG IoControlCode,
  1071. IN PDEVICE_OBJECT TargetDeviceObject,
  1072. IN PVOID InputBuffer OPTIONAL,
  1073. IN PVOID OutputBuffer OPTIONAL,
  1074. IN ULONG InputBufferLength,
  1075. IN ULONG OutputBufferLength,
  1076. IN BOOLEAN InternalDeviceIoControl,
  1077. OUT PIO_STATUS_BLOCK IoStatus
  1078. )
  1079. {
  1080. MPLIBSendDeviceIoControlSynchronous(IoControlCode,
  1081. TargetDeviceObject,
  1082. InputBuffer,
  1083. OutputBuffer,
  1084. InputBufferLength,
  1085. OutputBufferLength,
  1086. InternalDeviceIoControl,
  1087. IoStatus);
  1088. }
  1089. PDSM_IDS
  1090. DsmGetAssociatedDevice(
  1091. IN PVOID MPIOContext,
  1092. IN PDEVICE_OBJECT PortFdo,
  1093. IN UCHAR DeviceType
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. If the DSM needs to acquire information from other devices (such as a controller), this
  1098. routine can be used to get a list of the PDO's associated with PortFdo.
  1099. Arguments:
  1100. PortFdo - Port driver FDO passed to InquireDriver.
  1101. DeviceType - Indicates the SCSI DeviceType to return.
  1102. Return Value:
  1103. Pointer to a DSM_ID structure, where IdList entries are PDEVICE_OBJECT. It is the
  1104. reponsibility of the DSM to free the buffer.
  1105. --*/
  1106. {
  1107. PDEVICE_OBJECT deviceObject = MPIOContext;
  1108. PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
  1109. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  1110. PADP_ASSOCIATED_DEVICES filterDevices;
  1111. PDSM_IDS deviceList;
  1112. ULONG numberMatched = 0;
  1113. ULONG i;
  1114. ULONG j;
  1115. ULONG length;
  1116. PFLTR_ENTRY fltrEntry;
  1117. PLIST_ENTRY entry;
  1118. for (entry = controlExtension->FilterList.Flink;
  1119. entry != &controlExtension->FilterList;
  1120. entry = entry->Flink) {
  1121. fltrEntry = CONTAINING_RECORD(entry, FLTR_ENTRY, ListEntry);
  1122. if (fltrEntry->PortFdo == PortFdo) {
  1123. //
  1124. // Get the current list from the fdo filter.
  1125. //
  1126. filterDevices = fltrEntry->FltrGetDeviceList(fltrEntry->FilterObject);
  1127. if (filterDevices) {
  1128. for (i = 0; i < filterDevices->NumberDevices; i++) {
  1129. if (filterDevices->DeviceInfo[i].DeviceType == DeviceType) {
  1130. numberMatched++;
  1131. }
  1132. }
  1133. //
  1134. // Allocate the dsm list.
  1135. //
  1136. length = sizeof(DSM_IDS) + (sizeof(PDEVICE_OBJECT) * (numberMatched - 1));
  1137. deviceList = ExAllocatePool(NonPagedPool, length);
  1138. deviceList->Count = numberMatched;
  1139. for (j = 0, i = 0; i < filterDevices->NumberDevices; i++) {
  1140. if (filterDevices->DeviceInfo[i].DeviceType == DeviceType) {
  1141. deviceList->IdList[j] = filterDevices->DeviceInfo[i].DeviceObject;
  1142. j++;
  1143. }
  1144. }
  1145. } else {
  1146. deviceList = NULL;
  1147. }
  1148. ExFreePool(filterDevices);
  1149. return deviceList;
  1150. }
  1151. }
  1152. return NULL;
  1153. }
  1154. NTSTATUS
  1155. DsmReleaseQueue(
  1156. IN PDEVICE_OBJECT ChildDevice
  1157. )
  1158. {
  1159. return MPLibReleaseQueue(ChildDevice);
  1160. }
  1161. NTSTATUS
  1162. DsmSendTUR(
  1163. IN PDEVICE_OBJECT TargetDevice
  1164. )
  1165. {
  1166. return MPLibSendTUR(TargetDevice);
  1167. }
  1168. NTSTATUS
  1169. DsmSendPassThroughDirect(
  1170. IN PDEVICE_OBJECT DeviceObject,
  1171. IN PSCSI_PASS_THROUGH_DIRECT ScsiPassThrough,
  1172. IN ULONG InputBufferLength,
  1173. IN ULONG OutputBufferLength
  1174. )
  1175. {
  1176. return MPLibSendPassThroughDirect(DeviceObject,
  1177. ScsiPassThrough,
  1178. InputBufferLength,
  1179. OutputBufferLength);
  1180. }
  1181. NTSTATUS
  1182. DsmGetDescriptor(
  1183. IN PDEVICE_OBJECT DeviceObject,
  1184. IN PSTORAGE_PROPERTY_ID PropertyId,
  1185. OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor
  1186. )
  1187. {
  1188. return MPLIBGetDescriptor(DeviceObject,
  1189. PropertyId,
  1190. Descriptor);
  1191. }
  1192. VOID
  1193. DsmNotification(
  1194. IN PVOID MPIOContext,
  1195. IN DSM_NOTIFICATION_TYPE Type,
  1196. IN PVOID AdditionalParameter
  1197. )
  1198. {
  1199. return;
  1200. }
  1201. NTSTATUS
  1202. DsmWriteEvent(
  1203. IN PVOID MPIOContext,
  1204. IN PWCHAR ComponentName,
  1205. IN PWCHAR EventDescription,
  1206. IN ULONG Severity
  1207. )
  1208. {
  1209. NTSTATUS status;
  1210. PDEVICE_OBJECT deviceObject = MPIOContext;
  1211. status = MPIOFireEvent(deviceObject,
  1212. ComponentName,
  1213. EventDescription,
  1214. Severity);
  1215. return status;
  1216. }
  1217. VOID
  1218. DsmDebugPrint(
  1219. ULONG DebugPrintLevel,
  1220. PCCHAR DebugMessage,
  1221. ...
  1222. )
  1223. {
  1224. MPathDebugPrint(DebugPrintLevel,
  1225. DebugMessage);
  1226. }