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.

1621 lines
46 KiB

  1. #include "mpio.h"
  2. VOID
  3. MPIOTimer(
  4. IN PDEVICE_OBJECT DeviceObject,
  5. IN PVOID Context
  6. )
  7. {
  8. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)Context;
  9. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  10. PFLTR_ENTRY fltrEntry;
  11. ULONG tickDiff;
  12. ULONG numberDevices;
  13. PMPIO_REQUEST_INFO requestInfo;
  14. PREAL_DEV_INFO deviceInfo;
  15. PDEVICE_OBJECT currentAdapter;
  16. ULONG i;
  17. ULONG j;
  18. PDEVICE_OBJECT controlObject = diskExtension->ControlObject;
  19. PDEVICE_EXTENSION devExt = controlObject->DeviceExtension;
  20. PCONTROL_EXTENSION controlExtension = devExt->TypeExtension;
  21. PLIST_ENTRY listEntry;
  22. //
  23. // Inc current tickcount.
  24. //
  25. diskExtension->TickCount++;
  26. if ((deviceExtension->State != MPIO_STATE_IN_FO) &&
  27. (deviceExtension->State != MPIO_STATE_WAIT1)) {
  28. //
  29. // Check for any pending work items to start.
  30. //
  31. if (diskExtension->PendingItems) {
  32. PLIST_ENTRY listEntry;
  33. //
  34. // Yank the packet from the pending list...
  35. //
  36. listEntry = ExInterlockedRemoveHeadList(&diskExtension->PendingWorkList,
  37. &diskExtension->WorkListLock);
  38. if (listEntry) {
  39. //
  40. // ...and jam it on the work list.
  41. //
  42. ExInterlockedInsertTailList(&diskExtension->WorkList,
  43. listEntry,
  44. &diskExtension->WorkListLock);
  45. InterlockedDecrement(&diskExtension->PendingItems);
  46. //
  47. // Signal the thread to initiate the F.O.
  48. //
  49. KeSetEvent(&diskExtension->ThreadEvent,
  50. 8,
  51. FALSE);
  52. } else {
  53. MPDebugPrint((0,
  54. "MPIOTimer: PendingItems set, but entry == NULL\n"));
  55. ASSERT(FALSE);
  56. }
  57. }
  58. }
  59. return;
  60. }
  61. BOOLEAN
  62. MPIOFindMatchingDevice(
  63. IN PDEVICE_OBJECT MPDiskObject,
  64. IN PADP_DEVICE_INFO DeviceInfo,
  65. IN PDSM_ENTRY DsmEntry,
  66. IN PVOID DsmId
  67. )
  68. {
  69. PDEVICE_EXTENSION deviceExtension = MPDiskObject->DeviceExtension;
  70. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  71. ULONG i;
  72. //
  73. // Hand off each real pdo and the new one to the DSM to see
  74. // if they are really the same device (accessed via different paths)
  75. //
  76. for (i = 0; i < diskExtension->TargetInfoCount; i++) {
  77. if (DsmEntry->CompareDevices(DsmEntry->DsmContext,
  78. diskExtension->TargetInfo[i].DsmID,
  79. DsmId)) {
  80. //
  81. // Have a match.
  82. //
  83. return TRUE;
  84. }
  85. }
  86. return FALSE;
  87. }
  88. NTSTATUS
  89. MPIOCreateDevice(
  90. IN PDEVICE_OBJECT DeviceObject,
  91. IN PDEVICE_OBJECT FilterObject,
  92. IN PDEVICE_OBJECT PortObject,
  93. IN PADP_DEVICE_INFO DeviceInfo,
  94. IN PDSM_ENTRY DsmEntry,
  95. IN PVOID DsmId,
  96. IN OUT PDEVICE_OBJECT *NewDeviceObject
  97. )
  98. {
  99. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  100. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  101. PDEVICE_OBJECT diskObject;
  102. PDEVICE_EXTENSION newExtension;
  103. PMPDISK_EXTENSION diskExtension;
  104. UNICODE_STRING unicodeDeviceName;
  105. PUNICODE_STRING regString;
  106. PREAL_DEV_INFO targetInfo;
  107. PMPIO_THREAD_CONTEXT threadContext;
  108. WCHAR deviceName[30];
  109. NTSTATUS status;
  110. ULONG i;
  111. ULONG numberDevices = controlExtension->NumberDevices;
  112. //
  113. // Build the new name.
  114. //
  115. swprintf(deviceName,
  116. L"\\Device\\MPathDisk%0d",
  117. numberDevices);
  118. RtlInitUnicodeString(&unicodeDeviceName, deviceName);
  119. //
  120. // Create the device object.
  121. //
  122. status = IoCreateDevice(deviceExtension->DriverObject,
  123. sizeof(DEVICE_EXTENSION),
  124. &unicodeDeviceName,
  125. FILE_DEVICE_MASS_STORAGE,
  126. FILE_DEVICE_SECURE_OPEN,
  127. FALSE,
  128. &diskObject);
  129. if (status == STATUS_SUCCESS) {
  130. MPDebugPrint((0,
  131. "MPIOCreateDevice: New PDO %x\n",
  132. diskObject));
  133. //
  134. // TODO, break this up into some helper functions that
  135. // can be used by both this routine and UpdateDevice
  136. //
  137. //
  138. // Setup the various devObj stuff to be like the real PDO.
  139. //
  140. diskObject->StackSize = DeviceInfo->DeviceObject->StackSize + 1;
  141. diskObject->Flags = DeviceInfo->DeviceObject->Flags;
  142. diskObject->Flags |= DO_DEVICE_INITIALIZING;
  143. diskObject->AlignmentRequirement = DeviceInfo->DeviceObject->AlignmentRequirement;
  144. //
  145. // Allocate the type extension.
  146. //
  147. diskExtension = ExAllocatePool(NonPagedPool, sizeof(MPDISK_EXTENSION));
  148. RtlZeroMemory(diskExtension, sizeof(MPDISK_EXTENSION));
  149. //
  150. // Allocate storage for the device descriptor.
  151. //
  152. diskExtension->DeviceDescriptor = ExAllocatePool(NonPagedPool,
  153. DeviceInfo->DeviceDescriptor->Size);
  154. //
  155. // Set-up the device extension.
  156. //
  157. newExtension = diskObject->DeviceExtension;
  158. newExtension->TypeExtension = diskExtension;
  159. newExtension->DeviceObject = diskObject;
  160. newExtension->Pdo = diskObject;
  161. newExtension->LowerDevice = DeviceObject;
  162. newExtension->DriverObject = deviceExtension->DriverObject;
  163. newExtension->Type = MPIO_MPDISK;
  164. //
  165. // Since there is only one path, set the original state to DEGRADED, as we
  166. // can't fail-over yet.
  167. //
  168. newExtension->State = MPIO_STATE_NORMAL;
  169. newExtension->LastState = MPIO_STATE_NORMAL;
  170. newExtension->CompletionState = MPIO_STATE_NORMAL;
  171. diskExtension->CheckState = TRUE;
  172. //
  173. // Set-up the Lookaside List of context structs.
  174. //
  175. ExInitializeNPagedLookasideList(&newExtension->ContextList,
  176. NULL,
  177. NULL,
  178. 0,
  179. sizeof(MPIO_CONTEXT),
  180. 'oCPM',
  181. 0);
  182. //
  183. // Set-up emergency buffers
  184. //
  185. KeInitializeSpinLock(&newExtension->EmergencySpinLock);
  186. for (i = 0; i < MAX_EMERGENCY_CONTEXT; i++) {
  187. newExtension->EmergencyContext[i] = ExAllocatePool(NonPagedPool,
  188. sizeof(MPIO_CONTEXT));
  189. }
  190. //
  191. // Copy the reg. path from the control object.
  192. //
  193. regString = &deviceExtension->RegistryPath;
  194. newExtension->RegistryPath.Buffer = ExAllocatePool(NonPagedPool,
  195. regString->MaximumLength);
  196. newExtension->RegistryPath.MaximumLength = regString->MaximumLength;
  197. RtlCopyUnicodeString(&newExtension->RegistryPath,
  198. regString);
  199. //
  200. // Save off the important DSM Info.
  201. //
  202. RtlCopyMemory(&diskExtension->DsmInfo,
  203. DsmEntry,
  204. sizeof(DSM_ENTRY));
  205. //
  206. // Prepare this D.O. to handle WMI requests.
  207. //
  208. MPIOSetupWmi(diskObject);
  209. //
  210. // Set-up the new DO's type extension.
  211. //
  212. diskExtension->ControlObject = DeviceObject;
  213. diskExtension->DeviceOrdinal = numberDevices;
  214. //
  215. // Copy the device descriptor. Used for PnP ID stuff.
  216. //
  217. RtlCopyMemory(diskExtension->DeviceDescriptor,
  218. DeviceInfo->DeviceDescriptor,
  219. DeviceInfo->DeviceDescriptor->Size);
  220. //
  221. // Prepare all of the queues.
  222. //
  223. MPIOInitQueue(&diskExtension->ResubmitQueue, 1);
  224. MPIOInitQueue(&diskExtension->FailOverQueue, 2);
  225. //
  226. // Set-up the thread stuff.
  227. //
  228. KeInitializeSpinLock(&diskExtension->SpinLock);
  229. KeInitializeSpinLock(&diskExtension->WorkListLock);
  230. InitializeListHead(&diskExtension->WorkList);
  231. InitializeListHead(&diskExtension->PendingWorkList);
  232. KeInitializeEvent(&diskExtension->ThreadEvent,
  233. NotificationEvent,
  234. FALSE);
  235. threadContext = ExAllocatePool(NonPagedPool, sizeof(MPIO_THREAD_CONTEXT));
  236. threadContext->DeviceObject = diskObject;
  237. threadContext->Event = &diskExtension->ThreadEvent;
  238. status = PsCreateSystemThread(&diskExtension->Handle,
  239. (ACCESS_MASK)0,
  240. NULL,
  241. NULL,
  242. NULL,
  243. MPIORecoveryThread,
  244. threadContext);
  245. if (status != STATUS_SUCCESS) {
  246. diskExtension->Handle = NULL;
  247. }
  248. status = IoInitializeTimer(diskObject,
  249. MPIOTimer,
  250. newExtension);
  251. //
  252. // Add in the info for the first target device.
  253. // Note that the DevFilter and PathId fields are
  254. // set to the Port PDO and Adapter Filter.
  255. // When the DevFilter registers, these get copied over
  256. // to the correct values and DSMInit flag is set.
  257. //
  258. targetInfo = diskExtension->TargetInfo;
  259. targetInfo->AdapterFilter = FilterObject;
  260. targetInfo->PathId = FilterObject;
  261. targetInfo->PortPdo = DeviceInfo->DeviceObject;
  262. targetInfo->PortFdo = PortObject;
  263. targetInfo->DsmID = DsmId;
  264. targetInfo->DevFilter = DeviceInfo->DeviceObject;
  265. targetInfo->DSMInit = FALSE;
  266. diskExtension->DsmIdList.IdList[0] = DsmId;
  267. diskExtension->DsmIdList.Count = 1;
  268. diskExtension->TargetInfoCount = 1;
  269. diskExtension->MaxPaths = 1;
  270. diskExtension->HasName = FALSE;
  271. diskExtension->PdoName.Buffer = ExAllocatePool(NonPagedPool, PDO_NAME_LENGTH);
  272. RtlZeroMemory(diskExtension->PdoName.Buffer, PDO_NAME_LENGTH);
  273. diskExtension->PdoName.MaximumLength = PDO_NAME_LENGTH;
  274. //
  275. // Indicate that this slot is taken.
  276. //
  277. diskExtension->DeviceMap |= 1;
  278. *NewDeviceObject = diskObject;
  279. } else {
  280. MPDebugPrint((0,
  281. "MPIOCreateDevice: Error creating new PDO %x\n",
  282. status));
  283. }
  284. return status;
  285. }
  286. NTSTATUS
  287. MPIOUpdateDevice(
  288. IN PDEVICE_OBJECT DeviceObject,
  289. IN PDEVICE_OBJECT AdapterFilter,
  290. IN PDEVICE_OBJECT PortObject,
  291. IN PADP_DEVICE_INFO DeviceInfo,
  292. IN PVOID DsmId
  293. )
  294. /*++
  295. Routine Description:
  296. This routine updates the PDO extension to include
  297. a newly arrived device.
  298. Arguments:
  299. Return Value:
  300. NTSTATUS
  301. --*/
  302. {
  303. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  304. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  305. PREAL_DEV_INFO devInfo;
  306. ULONG allocatedMap = diskExtension->DeviceMap;
  307. ULONG i;
  308. ULONG j;
  309. ULONG currentState;
  310. ULONG newState;
  311. WCHAR componentName[64];
  312. //
  313. // Find a free spot in the array.
  314. //
  315. for (i = 0; i < MAX_NUMBER_PATHS; i++) {
  316. if (!(allocatedMap & (1 << i))) {
  317. diskExtension->DeviceMap |= (1 << i);
  318. break;
  319. }
  320. }
  321. //
  322. // Indicate that one more path is available.
  323. //
  324. diskExtension->DsmIdList.IdList[diskExtension->DsmIdList.Count] = DsmId;
  325. diskExtension->DsmIdList.Count++;
  326. diskExtension->TargetInfoCount++;
  327. ASSERT(diskExtension->DsmIdList.Count <= MAX_NUMBER_PATHS);
  328. //
  329. // See if we are transitioning from degraded to normal.
  330. //
  331. currentState = deviceExtension->State;
  332. if ((diskExtension->TargetInfoCount == diskExtension->MaxPaths) &&
  333. (currentState == MPIO_STATE_DEGRADED)) {
  334. //
  335. // This indicates that a path that went missing, has returned.
  336. //
  337. diskExtension->PathBackOnLine = TRUE;
  338. }
  339. //
  340. // Update MaxPaths, if necessary. It's the count of the most
  341. // paths we have seen.
  342. //
  343. if (diskExtension->TargetInfoCount > diskExtension->MaxPaths) {
  344. diskExtension->MaxPaths++;
  345. }
  346. //
  347. // Determine the state info.
  348. //
  349. newState = MPIOHandleStateTransition(DeviceObject);
  350. if ((currentState == MPIO_STATE_DEGRADED) && (newState == MPIO_STATE_NORMAL)) {
  351. //
  352. // Did make that tranistion. Fire an event to notify any listeners.
  353. //
  354. MPDebugPrint((0,
  355. "MPIOUpdateDevice: Moving to NORMAL (%x)\n",
  356. DeviceObject));
  357. swprintf(componentName, L"MPIO Disk(%02d)", diskExtension->DeviceOrdinal);
  358. MPIOFireEvent(DeviceObject,
  359. componentName,
  360. L"Moved to STATE_NORMAL",
  361. MPIO_INFORMATION);
  362. }
  363. //
  364. // Get the structure pertaining to the device being updated.
  365. //
  366. devInfo = &diskExtension->TargetInfo[i];
  367. RtlZeroMemory(devInfo, sizeof(REAL_DEV_INFO));
  368. //
  369. // Add the FilterObject as being the PathID for the new device.
  370. //
  371. devInfo->AdapterFilter = AdapterFilter;
  372. devInfo->PathId = AdapterFilter;
  373. //
  374. // Point the DevFilter entry to the Port PDO for now.
  375. // It is set when the device filter registers.
  376. //
  377. devInfo->DevFilter = DeviceInfo->DeviceObject;
  378. //
  379. // Add the Scsiport PDO.
  380. //
  381. devInfo->PortPdo = DeviceInfo->DeviceObject;
  382. devInfo->PortFdo = PortObject;
  383. for (j = 0; j < diskExtension->TargetInfoCount; j++) {
  384. if (diskExtension->TargetInfo[j].DsmID == DsmId) {
  385. MPDebugPrint((0,
  386. "UpdateDevice: Matching DSM IDs\n"));
  387. DbgBreakPoint();
  388. }
  389. }
  390. //
  391. // Add the DSM Id that corresponds to the Scsiport PDO.
  392. //
  393. devInfo->DsmID = DsmId;
  394. devInfo->DSMInit = FALSE;
  395. return STATUS_SUCCESS;
  396. }
  397. NTSTATUS
  398. MPIOPdoPowerNotification(
  399. IN PDEVICE_OBJECT MPDiskObject,
  400. IN PDEVICE_OBJECT FilterObject,
  401. IN PIRP Irp
  402. )
  403. {
  404. return STATUS_SUCCESS;
  405. }
  406. NTSTATUS
  407. MPIOPdoPnPNotification(
  408. IN PDEVICE_OBJECT MPDiskObject,
  409. IN PDEVICE_OBJECT FilterObject,
  410. IN PIRP Irp
  411. )
  412. {
  413. return STATUS_SUCCESS;
  414. }
  415. NTSTATUS
  416. MPIODsmFinalInit(
  417. IN PMPDISK_EXTENSION DiskExtension,
  418. IN PDEVICE_OBJECT DevFilter,
  419. IN PREAL_DEV_INFO TargetInfo
  420. )
  421. /*++
  422. Routine Description:
  423. This routine handles giving the dsm the remaining info. that it
  424. needs (PathId, it's own DSMID, and target object matchup). Also,
  425. determines whether the path is active.
  426. Arguments:
  427. DiskExtension - The type extension for the pseudo-disk
  428. DevFilter - MPDev's object - the target object for I/O
  429. TargetInfo - Collection of DSM related info.
  430. Return Value:
  431. NTSTATUS
  432. --*/
  433. {
  434. PDSM_ENTRY dsm = &DiskExtension->DsmInfo;
  435. ULONGLONG controllerId;
  436. NTSTATUS status;
  437. BOOLEAN active;
  438. //
  439. // Need to give info about this to the DSM
  440. //
  441. TargetInfo->PathId = TargetInfo->AdapterFilter;
  442. status = dsm->SetDeviceInfo(dsm->DsmContext,
  443. DevFilter,
  444. TargetInfo->DsmID,
  445. &TargetInfo->PathId);
  446. if (!NT_SUCCESS(status)) {
  447. //
  448. // LOG
  449. // NOTE: This is really a fatal error, as there is no mapping
  450. // in the DSM for Path, DsmID, and the target D.O.
  451. // Figure out how to go into limp-home mode.
  452. //
  453. } else {
  454. //
  455. // If the DSM updated "pathID" need to encapsulate this and
  456. // the AdapterFilter. Be sure and use
  457. //
  458. if (TargetInfo->PathId != TargetInfo->AdapterFilter) {
  459. MPDebugPrint((2,
  460. "MPIODsmFinalInit: DSM updated PathID (%x) -> (%x)\n",
  461. TargetInfo->AdapterFilter,
  462. TargetInfo->PathId));
  463. }
  464. //
  465. // Have everything needed now, so create a path entry.
  466. //
  467. status = MPIOCreatePathEntry(DiskExtension->ControlObject,
  468. TargetInfo->AdapterFilter,
  469. TargetInfo->PortFdo,
  470. TargetInfo->PathId);
  471. if (NT_SUCCESS(status)) {
  472. //
  473. // See if there is already an ID for this path.
  474. // This routine will create it, if not.
  475. //
  476. TargetInfo->Identifier = MPIOCreateUID(DiskExtension->ControlObject,
  477. TargetInfo->PathId);
  478. if (TargetInfo->Identifier != 0) {
  479. TargetInfo->PathUIDValue = TRUE;
  480. }
  481. } else {
  482. MPDebugPrint((0,
  483. "MPIODsmFinalInit: Couldn't create the path entry (%x)\n",
  484. status));
  485. //
  486. // LOG
  487. //
  488. }
  489. //
  490. // Verify the path before going on.
  491. //
  492. status = dsm->PathVerify(dsm->DsmContext,
  493. TargetInfo->DsmID,
  494. TargetInfo->PathId);
  495. if (status != STATUS_SUCCESS) {
  496. MPDebugPrint((0,
  497. "MPIODsmFinalInit: PathVerify failed. Dsm (%x). TargetInfo (%x)\n",
  498. dsm,
  499. TargetInfo));
  500. DbgBreakPoint();
  501. //
  502. // Can't use this. Tear down this entry.
  503. //
  504. //TODO
  505. //
  506. status = STATUS_SUCCESS;
  507. }
  508. //
  509. // Determine if this path is active.
  510. //
  511. active = dsm->IsPathActive(dsm->DsmContext,
  512. TargetInfo->PathId);
  513. if (active) {
  514. //
  515. // Indicate this.
  516. //
  517. TargetInfo->PathActive = TRUE;
  518. }
  519. //
  520. // Get the controller info for the DSM ID on this device.
  521. //
  522. controllerId = MPIOBuildControllerInfo(DiskExtension->ControlObject,
  523. dsm,
  524. TargetInfo->DsmID);
  525. TargetInfo->ControllerId = controllerId;
  526. MPDebugPrint((1,
  527. "DsmFinalInit: TargetInfo (%x) now fully init'ed\n",
  528. TargetInfo));
  529. TargetInfo->DSMInit = TRUE;
  530. }
  531. return status;
  532. }
  533. NTSTATUS
  534. MPIOPdoRegistration(
  535. IN PDEVICE_OBJECT MPDiskObject,
  536. IN PDEVICE_OBJECT FilterObject,
  537. IN PDEVICE_OBJECT LowerDevice,
  538. IN OUT PMPIO_PDO_INFO PdoInformation
  539. )
  540. /*++
  541. Routine Description:
  542. This routine handles setting up communication and passing of info.
  543. between the device filter and the mpdisk.
  544. Arguments:
  545. MPDiskObject - Pseudo-disk that contains the real device.
  546. FilterObject - MPDev's object
  547. LowerDevice - The real pdo.
  548. PdoInformation - Entry points for the filter to call.
  549. Return Value:
  550. NTSTATUS
  551. --*/
  552. {
  553. PDEVICE_EXTENSION deviceExtension = MPDiskObject->DeviceExtension;
  554. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  555. ULONG i;
  556. NTSTATUS status;
  557. //
  558. // Ensure that the passed in MPDiskObject and LowerDevice
  559. // are correct.
  560. // The DsmIdList is the list of scisport pdo's. This is just
  561. // to ensure that the device id'ed by LowerDevice is in the list
  562. // and to get it's index for use below.
  563. //
  564. for (i = 0; i < diskExtension->TargetInfoCount; i++) {
  565. if (diskExtension->TargetInfo[i].PortPdo == LowerDevice) {
  566. break;
  567. }
  568. }
  569. if (i == diskExtension->TargetInfoCount) {
  570. return STATUS_NO_SUCH_DEVICE;
  571. }
  572. //
  573. // Capture the dev filter's object. This is the target for
  574. // I/O's.
  575. //
  576. diskExtension->TargetInfo[i].DevFilter = FilterObject;
  577. //
  578. // Now indicate that we are ready.
  579. //
  580. MPDiskObject->Flags &= ~DO_DEVICE_INITIALIZING;
  581. //
  582. // Finish setting up the DSM.
  583. //
  584. status = MPIODsmFinalInit(diskExtension,
  585. FilterObject,
  586. &diskExtension->TargetInfo[i]);
  587. ASSERT(status == STATUS_SUCCESS);
  588. //
  589. // Fill in the routines that the dev filter can use for
  590. // power and pnp.
  591. //
  592. PdoInformation->DevicePowerNotify = MPIOPdoPowerNotification;
  593. PdoInformation->DevicePnPNotify = MPIOPdoPnPNotification;
  594. PdoInformation->PdoObject = MPDiskObject;
  595. return STATUS_SUCCESS;
  596. }
  597. NTSTATUS
  598. MPIOPdoDeviceControl(
  599. IN PDEVICE_OBJECT DeviceObject,
  600. IN PIRP Irp
  601. )
  602. {
  603. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  604. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  605. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  606. PMPIO_CONTEXT context = irpStack->Parameters.Others.Argument4;
  607. ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  608. PDEVICE_OBJECT targetObject;
  609. //
  610. // These should just be IOCTL_STORAGE_XXX and IOCTL_SCSI_XXX
  611. //
  612. if ((controlCode == IOCTL_STORAGE_QUERY_PROPERTY) ||
  613. (controlCode == IOCTL_SCSI_GET_ADDRESS) ||
  614. (controlCode == IOCTL_SCSI_GET_ADDRESS) ||
  615. (controlCode == IOCTL_SCSI_PASS_THROUGH) ||
  616. (controlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) ||
  617. (controlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ||
  618. (controlCode == IOCTL_DISK_GET_MEDIA_TYPES)) {
  619. } else {
  620. MPDebugPrint((0,
  621. "PdoDeviceControl: Unhandled IOCTL Code (%x)\n",
  622. controlCode));
  623. }
  624. IoMarkIrpPending(Irp);
  625. //
  626. // Set-up the completion routine.
  627. // TODO: Yank this and setting up of context into single routine.
  628. //
  629. IoSetCompletionRoutine(Irp,
  630. MPPdoGlobalCompletion,
  631. context,
  632. TRUE,
  633. TRUE,
  634. TRUE);
  635. //
  636. // Categorization of these should be unneccesary.
  637. // NOTE: Verify this assertion, and also ensure that the only requests
  638. // coming here are the ones noted above.
  639. //
  640. // Send these to the first device in the multi-path group.
  641. //
  642. targetObject = diskExtension->TargetInfo[0].DevFilter;
  643. //
  644. // Save the real pdo in the context.
  645. //
  646. context->TargetInfo = (diskExtension->TargetInfo);
  647. MPDebugPrint((3,
  648. "MPIOPdoDeviceControl: Context (%x) TargetInfo (%x)\n",
  649. context,
  650. context->TargetInfo));
  651. //
  652. // Set-up our context info.
  653. // NOTE: Validate whether the DSM will need the opportunity to set it's
  654. // completion.
  655. //
  656. context->DsmCompletion.DsmCompletionRoutine = NULL;
  657. context->DsmCompletion.DsmContext = NULL;
  658. //
  659. // Indicate that a request is outstanding to this device.
  660. //
  661. InterlockedIncrement(&diskExtension->TargetInfo[0].Requests);
  662. //
  663. // Send the request to the device filter.
  664. //
  665. IoCallDriver(targetObject, Irp);
  666. return STATUS_PENDING;
  667. }
  668. NTSTATUS
  669. MPIOReadWrite(
  670. IN PDEVICE_OBJECT DeviceObject,
  671. IN PIRP Irp
  672. )
  673. {
  674. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  675. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  676. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  677. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  678. PMPIO_CONTEXT context = irpStack->Parameters.Others.Argument4;
  679. PREAL_DEV_INFO targetInfo = NULL;
  680. PDSM_ENTRY dsm;
  681. NTSTATUS status;
  682. PVOID pathId;
  683. ULONG i;
  684. IoMarkIrpPending(Irp);
  685. //
  686. // Set-up the completion routine.
  687. //
  688. IoSetCompletionRoutine(Irp,
  689. MPPdoGlobalCompletion,
  690. context,
  691. TRUE,
  692. TRUE,
  693. TRUE);
  694. dsm = &diskExtension->DsmInfo;
  695. targetInfo = diskExtension->TargetInfo;
  696. //
  697. // Ensure that the DSM has been fully init'ed.
  698. //
  699. if (targetInfo->DSMInit) {
  700. //
  701. // Call into the DSM to find the path to which the request should be sent.
  702. //
  703. pathId = dsm->GetPath(dsm->DsmContext,
  704. srb,
  705. &diskExtension->DsmIdList,
  706. diskExtension->CurrentPath,
  707. &status);
  708. if (pathId == NULL) {
  709. //
  710. // LOG
  711. // This is fatal. Figure out what to do.
  712. // Attempt a fail-over, though this probably won't fix anything (all the paths
  713. // are dead according to the DSM. TODO
  714. //
  715. // BUGBUG need to CompleteRequest with an error to cause a fail-over.
  716. // Will first have to setup Context.
  717. // and remove the following
  718. //
  719. Irp->IoStatus.Status = status;
  720. Irp->IoStatus.Information = 0;
  721. IoCompleteRequest(Irp, 8);
  722. return status;
  723. } else {
  724. //
  725. // Determine which target info the path is in.
  726. //
  727. targetInfo = MPIOGetTargetInfo(diskExtension,
  728. pathId,
  729. NULL);
  730. }
  731. } else {
  732. pathId = targetInfo->AdapterFilter;
  733. //
  734. // Determine which target info the path is in.
  735. //
  736. targetInfo = MPIOGetTargetInfo(diskExtension,
  737. NULL,
  738. pathId);
  739. }
  740. //
  741. // If this path isn't marked active, this indicates a fail-over.
  742. //
  743. if (targetInfo->PathActive == FALSE) {
  744. //
  745. // LOG - Run the F.O. Handler.
  746. //
  747. }
  748. if (targetInfo->PathFailed) {
  749. MPDebugPrint((0,
  750. "MPIOReadWrite: Got back a failed path. (%x)\n",
  751. targetInfo));
  752. ASSERT(targetInfo->PathFailed == FALSE);
  753. }
  754. //
  755. // Indicate the new path that is active.
  756. //
  757. diskExtension->CurrentPath = targetInfo->PathId;
  758. //
  759. // Save the real pdo in the context.
  760. //
  761. context->TargetInfo = targetInfo;
  762. //
  763. // Get a copy of the original srb.
  764. //
  765. RtlCopyMemory(&context->Srb,
  766. srb,
  767. sizeof(SCSI_REQUEST_BLOCK));
  768. if (targetInfo->DSMInit) {
  769. //
  770. // Now have determined the correct path, allow the DSM
  771. // to set-up it's context and completion.
  772. //
  773. dsm->SetCompletion(dsm->DsmContext,
  774. targetInfo->DsmID,
  775. Irp,
  776. srb,
  777. &context->DsmCompletion);
  778. }
  779. //
  780. // Indicate that a request is outstanding to this device.
  781. //
  782. InterlockedIncrement(&targetInfo->Requests);
  783. //
  784. // Call the device Filter with the request.
  785. //
  786. IoCallDriver(targetInfo->DevFilter, Irp);
  787. return STATUS_PENDING;
  788. }
  789. NTSTATUS
  790. MPIOPdoHandleRequest(
  791. IN PDEVICE_OBJECT DeviceObject,
  792. IN PIRP Irp
  793. )
  794. {
  795. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  796. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  797. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  798. PMPIO_CONTEXT context = irpStack->Parameters.Others.Argument4;
  799. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  800. PREAL_DEV_INFO targetInfo;
  801. PDSM_ENTRY dsm;
  802. NTSTATUS status;
  803. KEVENT event;
  804. UCHAR opCode;
  805. PVOID pathId;
  806. ULONG action;
  807. KIRQL irql;
  808. //
  809. // Categorize the I/O
  810. //
  811. opCode = srb->Cdb[0];
  812. if ((opCode == SCSIOP_READ) ||
  813. (opCode == SCSIOP_WRITE) ||
  814. (opCode == SCSIOP_VERIFY)) {
  815. //
  816. // Call the Read/Write Handler.
  817. //
  818. return MPIOReadWrite(DeviceObject,
  819. Irp);
  820. }
  821. //
  822. // The request is something other than a read/write request.
  823. // Get the DSM information.
  824. //
  825. dsm = &diskExtension->DsmInfo;
  826. targetInfo = diskExtension->TargetInfo;
  827. if (targetInfo->DSMInit == FALSE) {
  828. //
  829. // Not fully initialized yet.
  830. //
  831. context->DsmCompletion.DsmCompletionRoutine = NULL;
  832. context->DsmCompletion.DsmContext = NULL;
  833. //
  834. // Indicate the current path.
  835. //
  836. diskExtension->CurrentPath = targetInfo->PathId;
  837. //
  838. // Save the real pdo in the context.
  839. //
  840. context->TargetInfo = targetInfo;
  841. IoMarkIrpPending(Irp);
  842. //
  843. // Set-up the completion routine.
  844. //
  845. IoSetCompletionRoutine(Irp,
  846. MPPdoGlobalCompletion,
  847. context,
  848. TRUE,
  849. TRUE,
  850. TRUE);
  851. //
  852. // Get a copy of the original srb.
  853. //
  854. RtlCopyMemory(&context->Srb,
  855. srb,
  856. sizeof(SCSI_REQUEST_BLOCK));
  857. //
  858. // Indicate that a request is outstanding to this device.
  859. //
  860. InterlockedIncrement(&targetInfo->Requests);
  861. //
  862. // Issue request to pathId specified.
  863. //
  864. return IoCallDriver(targetInfo->DevFilter, Irp);
  865. }
  866. action = dsm->CategorizeRequest(dsm->DsmContext,
  867. &diskExtension->DsmIdList,
  868. Irp,
  869. srb,
  870. diskExtension->CurrentPath,
  871. &pathId,
  872. &status);
  873. if (action == DSM_PATH_SET) {
  874. IoMarkIrpPending(Irp);
  875. //
  876. // Set-up the completion routine.
  877. //
  878. IoSetCompletionRoutine(Irp,
  879. MPPdoGlobalCompletion,
  880. context,
  881. TRUE,
  882. TRUE,
  883. TRUE);
  884. //
  885. // DSM has set the path to which the request should be sent.
  886. //
  887. // Get the target info corresponding to the pathId returned
  888. // by the DSM.
  889. //
  890. targetInfo = MPIOGetTargetInfo(diskExtension,
  891. pathId,
  892. NULL);
  893. if (targetInfo->PathFailed) {
  894. MPDebugPrint((0,
  895. "MPIOHandleRequest: Got back a failed path. (%x)\n",
  896. targetInfo));
  897. ASSERT(targetInfo->PathFailed == FALSE);
  898. }
  899. //
  900. // Save the real pdo in the context.
  901. //
  902. context->TargetInfo = targetInfo;
  903. //
  904. // Get a copy of the original srb.
  905. //
  906. RtlCopyMemory(&context->Srb,
  907. srb,
  908. sizeof(SCSI_REQUEST_BLOCK));
  909. MPDebugPrint((2,
  910. "Categorize: Context (%x). TargetInfo (%x)\n",
  911. context,
  912. context->TargetInfo));
  913. //
  914. // Allow the DSM to set-up completion info.
  915. // The DSM has the responsibility for the allocation and free
  916. // of it's own context.
  917. //
  918. dsm->SetCompletion(dsm->DsmContext,
  919. targetInfo->DsmID,
  920. Irp,
  921. srb,
  922. &context->DsmCompletion);
  923. //
  924. // Indicate the current path.
  925. //
  926. diskExtension->CurrentPath = targetInfo->PathId;
  927. //
  928. // Indicate that a request is outstanding to this device.
  929. //
  930. InterlockedIncrement(&targetInfo->Requests);
  931. //
  932. // Issue request to pathId specified.
  933. //
  934. status = IoCallDriver(targetInfo->DevFilter, Irp);
  935. } else {
  936. //
  937. // DSM wants to handle it internally.
  938. //
  939. // Init the event. We wait below, and the DSM
  940. // sets it when it's finished handling the request.
  941. //
  942. KeInitializeEvent(&event,
  943. NotificationEvent,
  944. FALSE);
  945. if (action == DSM_BROADCAST) {
  946. //
  947. // Give it to the DSM's Broadcast routine. The request
  948. // will be sent down all paths, and possibly be modified
  949. // from the original OpCode.
  950. //
  951. status = dsm->BroadcastSrb(dsm->DsmContext,
  952. &diskExtension->DsmIdList,
  953. Irp,
  954. srb,
  955. &event);
  956. } else if (action == DSM_WILL_HANDLE) {
  957. //
  958. // Hand the request off to the DSM.
  959. //
  960. status = dsm->SrbDeviceControl(dsm->DsmContext,
  961. &diskExtension->DsmIdList,
  962. Irp,
  963. srb,
  964. &event);
  965. } else {
  966. //
  967. // It's broken (DSM_ERROR).
  968. //
  969. // TODO handle this
  970. // Call InterpretError to see if it's a fail-over.
  971. // Set-up a bogus assert for the time being, until
  972. // this case is actually handled.
  973. //
  974. // Status is set by the DSM. Go ahead and propogate that
  975. // back.
  976. //
  977. ASSERT(action == DSM_BROADCAST);
  978. }
  979. if (status == STATUS_PENDING) {
  980. KeWaitForSingleObject(&event,
  981. Executive,
  982. KernelMode,
  983. FALSE,
  984. NULL);
  985. status = Irp->IoStatus.Status;
  986. } else {
  987. //
  988. // Ensure that the DSM is returning status
  989. // correctly.
  990. //
  991. ASSERT(status == Irp->IoStatus.Status);
  992. }
  993. //
  994. // The calling routine expects these to be completed here.
  995. //
  996. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  997. InterlockedDecrement(&diskExtension->OutstandingRequests);
  998. }
  999. return status;
  1000. }
  1001. NTSTATUS
  1002. MPIOExecuteNone(
  1003. IN PDEVICE_OBJECT DeviceObject,
  1004. IN PIRP Irp
  1005. )
  1006. {
  1007. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1008. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  1009. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1010. PMPIO_CONTEXT context = irpStack->Parameters.Others.Argument4;
  1011. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  1012. NTSTATUS status;
  1013. PREAL_DEV_INFO targetInfo = diskExtension->TargetInfo;
  1014. //
  1015. // If the path UID isn't set, try again.
  1016. //
  1017. if (targetInfo->PathUIDValue == FALSE) {
  1018. targetInfo->Identifier = MPIOCreateUID(diskExtension->ControlObject,
  1019. targetInfo->PathId);
  1020. if (targetInfo->Identifier != 0) {
  1021. targetInfo->PathUIDValue = TRUE;
  1022. }
  1023. }
  1024. //
  1025. // Set-up NULL context info as none of these requires
  1026. // a special completion routine.
  1027. //
  1028. context->DsmCompletion.DsmCompletionRoutine = NULL;
  1029. context->DsmCompletion.DsmContext = NULL;
  1030. switch (srb->Function) {
  1031. //
  1032. // If it's a Claim ore Release, handle it here.
  1033. // TODO: Lock these accesses.
  1034. //
  1035. case SRB_FUNCTION_CLAIM_DEVICE:
  1036. //
  1037. // Determine if a claim has already been made.
  1038. //
  1039. if (diskExtension->IsClaimed) {
  1040. //
  1041. // Already been claimed. Return that the device
  1042. // is busy.
  1043. //
  1044. srb->SrbStatus = SRB_STATUS_BUSY;
  1045. status = STATUS_DEVICE_BUSY;
  1046. } else {
  1047. //
  1048. // Indicate that the claim has been made
  1049. // and return this deviceObject.
  1050. //
  1051. diskExtension->IsClaimed = TRUE;
  1052. srb->DataBuffer = DeviceObject;
  1053. status = STATUS_SUCCESS;
  1054. }
  1055. break;
  1056. case SRB_FUNCTION_RELEASE_DEVICE:
  1057. //
  1058. // This is always successful.
  1059. //
  1060. srb->SrbStatus = SRB_STATUS_SUCCESS;
  1061. status = STATUS_SUCCESS;
  1062. break;
  1063. default:
  1064. //
  1065. // These aren't handled - check to
  1066. // see whether any do end up here.
  1067. // LOG the error.
  1068. //
  1069. srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  1070. status = STATUS_INVALID_DEVICE_REQUEST;
  1071. MPDebugPrint((1,
  1072. "MPIOInternalDevControl: Unhandled Srb Function (%x)\n",
  1073. srb->Function));
  1074. DbgBreakPoint();
  1075. break;
  1076. }
  1077. return status;
  1078. }
  1079. NTSTATUS
  1080. MPIOPdoInternalDeviceControl(
  1081. IN PDEVICE_OBJECT DeviceObject,
  1082. IN PIRP Irp
  1083. )
  1084. {
  1085. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1086. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  1087. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1088. PMPIO_CONTEXT context = irpStack->Parameters.Others.Argument4;
  1089. NTSTATUS status;
  1090. BOOLEAN completeRequest = TRUE;
  1091. //
  1092. // Determine the what the request is.
  1093. // The only requests handled here are EXECUTE_NONE
  1094. //
  1095. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  1096. case IOCTL_SCSI_EXECUTE_NONE:
  1097. //
  1098. // Handle all of the EXECUTE_NONE requests here.
  1099. // This routine won't complete the request, so
  1100. // do it below.
  1101. //
  1102. status = MPIOExecuteNone(DeviceObject,
  1103. Irp);
  1104. break;
  1105. default:
  1106. //
  1107. // This routine will categorise the I/O and execute
  1108. // the appropriate handler.
  1109. //
  1110. status = MPIOPdoHandleRequest(DeviceObject,
  1111. Irp);
  1112. //
  1113. // Don't complete these
  1114. //
  1115. completeRequest = FALSE;
  1116. break;
  1117. }
  1118. if (completeRequest) {
  1119. Irp->IoStatus.Status = status;
  1120. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1121. InterlockedDecrement(&diskExtension->OutstandingRequests);
  1122. }
  1123. return status;
  1124. }
  1125. NTSTATUS
  1126. MPIOPdoUnhandled(
  1127. IN PDEVICE_OBJECT DeviceObject,
  1128. IN PIRP Irp
  1129. )
  1130. {
  1131. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1132. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  1133. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1134. PMPIO_CONTEXT context = irpStack->Parameters.Others.Argument4;
  1135. //
  1136. // See what IRP_MJ the request is.
  1137. //
  1138. MPDebugPrint((1,
  1139. "MPIOPdoUnhandled: Major %x, Minor %x\n",
  1140. irpStack->MajorFunction,
  1141. irpStack->MinorFunction));
  1142. context->DsmCompletion.DsmCompletionRoutine = NULL;
  1143. context->DsmCompletion.DsmContext = NULL;
  1144. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  1145. Irp->IoStatus.Information = 0;
  1146. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1147. InterlockedDecrement(&diskExtension->OutstandingRequests);
  1148. return STATUS_INVALID_DEVICE_REQUEST;
  1149. }
  1150. NTSTATUS
  1151. MPIOPdoPnp(
  1152. IN PDEVICE_OBJECT DeviceObject,
  1153. IN PIRP Irp
  1154. )
  1155. {
  1156. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1157. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  1158. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1159. PMPIO_CONTEXT context = irpStack->Parameters.Others.Argument4;
  1160. NTSTATUS status;
  1161. context->DsmCompletion.DsmCompletionRoutine = NULL;
  1162. context->DsmCompletion.DsmContext = NULL;
  1163. //
  1164. // Determine the MinorFunction and call the appropriate
  1165. // helper function.
  1166. //
  1167. switch (irpStack->MinorFunction) {
  1168. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1169. //
  1170. // Call the Qdr handler.
  1171. //
  1172. status = MPIOPdoQdr(DeviceObject, Irp);
  1173. break;
  1174. case IRP_MN_QUERY_ID:
  1175. //
  1176. // Call the QueryId routine.
  1177. //
  1178. status = MPIOPdoQueryId(DeviceObject, Irp);
  1179. break;
  1180. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  1181. //
  1182. // Adjust the various counters depending upon the
  1183. // Type of Usage Notification.
  1184. //
  1185. // Invalidate the device state
  1186. //
  1187. // complete the request.
  1188. //
  1189. //status = MPIODeviceUsage(DeviceObject,
  1190. // Irp);
  1191. status = STATUS_INVALID_DEVICE_REQUEST;
  1192. break;
  1193. case IRP_MN_QUERY_DEVICE_TEXT:
  1194. //
  1195. // Get the device text or location.
  1196. //
  1197. status = MPIOQueryDeviceText(DeviceObject, Irp);
  1198. break;
  1199. case IRP_MN_QUERY_CAPABILITIES: {
  1200. PDEVICE_CAPABILITIES capabilities;
  1201. capabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
  1202. //
  1203. // Indicate no function driver is really necessary, suppress PnP Pop-ups
  1204. // and the MPDisk's Id
  1205. //
  1206. capabilities->RawDeviceOK = 1;
  1207. capabilities->SilentInstall = 1;
  1208. capabilities->Address = diskExtension->DeviceOrdinal;
  1209. status = STATUS_SUCCESS;
  1210. break;
  1211. }
  1212. case IRP_MN_QUERY_PNP_DEVICE_STATE: {
  1213. PPNP_DEVICE_STATE deviceState = (PPNP_DEVICE_STATE) &(Irp->IoStatus.Information);
  1214. status = STATUS_SUCCESS;
  1215. //
  1216. // TODO: This depends on whether this is in the hibernate/page path.
  1217. // Implement the check, and implement the IRP_MN_DEVICE_USAGE_NOTIFICATION
  1218. //
  1219. *deviceState |= PNP_DEVICE_NOT_DISABLEABLE;
  1220. break;
  1221. }
  1222. case IRP_MN_QUERY_RESOURCES:
  1223. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  1224. //
  1225. // Don't need resources and don't have a boot config.
  1226. // Complete it successfully with a NULL buffer.
  1227. //
  1228. status = STATUS_SUCCESS;
  1229. Irp->IoStatus.Information = (ULONG_PTR)NULL;
  1230. break;
  1231. case IRP_MN_STOP_DEVICE:
  1232. status = STATUS_SUCCESS;
  1233. Irp->IoStatus.Information = (ULONG_PTR) NULL;
  1234. break;
  1235. case IRP_MN_START_DEVICE:
  1236. //
  1237. // Register as a WMI provider.
  1238. //
  1239. IoWMIRegistrationControl(DeviceObject,
  1240. WMIREG_ACTION_REGISTER);
  1241. //
  1242. // Start the per-disk timer.
  1243. //
  1244. IoStartTimer(DeviceObject);
  1245. status = STATUS_SUCCESS;
  1246. break;
  1247. case IRP_MN_QUERY_REMOVE_DEVICE:
  1248. MPDebugPrint((1,
  1249. "MPIOPdoPnp: QueryRemove on (%x)\n",
  1250. DeviceObject));
  1251. status = STATUS_DEVICE_BUSY;
  1252. break;
  1253. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  1254. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1255. case IRP_MN_CANCEL_STOP_DEVICE:
  1256. case IRP_MN_QUERY_STOP_DEVICE:
  1257. case IRP_MN_SURPRISE_REMOVAL:
  1258. case IRP_MN_REMOVE_DEVICE:
  1259. //
  1260. // TODO
  1261. //
  1262. status = STATUS_SUCCESS;
  1263. break;
  1264. //
  1265. // Send these down
  1266. //
  1267. case IRP_MN_READ_CONFIG:
  1268. case IRP_MN_WRITE_CONFIG:
  1269. case IRP_MN_EJECT:
  1270. case IRP_MN_SET_LOCK:
  1271. case IRP_MN_QUERY_BUS_INFORMATION:
  1272. InterlockedDecrement(&diskExtension->OutstandingRequests);
  1273. return MPIOForwardRequest(DeviceObject, Irp);
  1274. break;
  1275. //
  1276. // The following requests are completed without status
  1277. // being updated.
  1278. //
  1279. case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
  1280. status = Irp->IoStatus.Status;
  1281. break;
  1282. case IRP_MN_QUERY_INTERFACE:
  1283. MPDebugPrint((2,
  1284. "MPIOPdoPnP: Query Interface\n"));
  1285. default:
  1286. MPDebugPrint((2,
  1287. "MPIOPdoPnP: Not handled - (%x)\n",
  1288. irpStack->MinorFunction));
  1289. DbgBreakPoint();
  1290. status = Irp->IoStatus.Status;
  1291. break;
  1292. }
  1293. Irp->IoStatus.Status = status;
  1294. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1295. InterlockedDecrement(&diskExtension->OutstandingRequests);
  1296. return status;
  1297. }
  1298. NTSTATUS
  1299. MPIOPdoPowerCompletion(
  1300. IN PDEVICE_OBJECT DeviceObject,
  1301. IN PIRP Irp,
  1302. IN PVOID Context
  1303. )
  1304. {
  1305. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1306. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  1307. if (Irp->PendingReturned) {
  1308. IoMarkIrpPending(Irp);
  1309. }
  1310. PoStartNextPowerIrp(Irp);
  1311. InterlockedDecrement(&diskExtension->OutstandingRequests);
  1312. return STATUS_SUCCESS;
  1313. }
  1314. NTSTATUS
  1315. MPIOPdoPower(
  1316. IN PDEVICE_OBJECT DeviceObject,
  1317. IN PIRP Irp
  1318. )
  1319. {
  1320. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1321. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  1322. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1323. PMPIO_CONTEXT context = irpStack->Parameters.Others.Argument4;
  1324. MPDebugPrint((2,
  1325. "MPIOPdoPower: Got a %x power irp\n",
  1326. irpStack->MinorFunction));
  1327. context->DsmCompletion.DsmCompletionRoutine = NULL;
  1328. context->DsmCompletion.DsmContext = NULL;
  1329. IoSetCompletionRoutine(Irp,
  1330. MPIOPdoPowerCompletion,
  1331. context,
  1332. TRUE,
  1333. TRUE,
  1334. TRUE);
  1335. Irp->IoStatus.Status = STATUS_SUCCESS;
  1336. PoCallDriver(deviceExtension->LowerDevice, Irp);
  1337. return STATUS_PENDING;
  1338. }