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.

828 lines
19 KiB

  1. /*++
  2. Copyright (C) 1999 Microsoft Corporation
  3. Module Name:
  4. mpdev.c
  5. Abstract:
  6. This driver acts as a lower-filter over the device pdo's and provides the support necessary for multipathing.
  7. It's main function is keep mpctl.sys (main multipath module) informed of system state.
  8. Author:
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include <ntddk.h>
  15. #include <stdio.h>
  16. #include <stdarg.h>
  17. #include "mpdevf.h"
  18. #include "scsi.h"
  19. #include "mplib.h"
  20. typedef struct _DEVICE_EXTENSION {
  21. //
  22. // Backpointer to our device object.
  23. //
  24. PDEVICE_OBJECT DeviceObject;
  25. //
  26. // Pointer to the lower object.
  27. //
  28. PDEVICE_OBJECT TargetDevice;
  29. //
  30. // The PDisk device object information.
  31. //
  32. MPIO_PDO_INFO PdoInfo;
  33. //
  34. // MpCtl's Control device Object.
  35. //
  36. PDEVICE_OBJECT ControlDevice;
  37. //
  38. // State flags of this (and the lower device).
  39. //
  40. ULONG DeviceState;
  41. //
  42. // General purpose event.
  43. //
  44. KEVENT Event;
  45. //
  46. // Counters for IOs
  47. //
  48. ULONG NumberReads;
  49. ULONG NumberWrites;
  50. BOOLEAN FailureSimulation;
  51. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
  52. //
  53. // Entry point decls
  54. //
  55. NTSTATUS
  56. MpDevDefaultDispatch(
  57. IN PDEVICE_OBJECT DeviceObject,
  58. IN PIRP Irp
  59. );
  60. NTSTATUS
  61. MpDevInternalDeviceControl(
  62. IN PDEVICE_OBJECT DeviceObject,
  63. IN PIRP Irp
  64. );
  65. NTSTATUS
  66. MpDevDeviceControl(
  67. IN PDEVICE_OBJECT DeviceObject,
  68. IN PIRP Irp
  69. );
  70. NTSTATUS
  71. MpDevPnPDispatch(
  72. IN PDEVICE_OBJECT DeviceObject,
  73. IN PIRP Irp
  74. );
  75. NTSTATUS
  76. MpDevPowerDispatch(
  77. IN PDEVICE_OBJECT DeviceObject,
  78. IN PIRP Irp
  79. );
  80. NTSTATUS
  81. MpDevAddDevice(
  82. IN PDRIVER_OBJECT DriverObject,
  83. IN PDEVICE_OBJECT PhysicalDeviceObject
  84. );
  85. NTSTATUS
  86. MpDevUnload(
  87. IN PDRIVER_OBJECT DriverObject
  88. );
  89. //
  90. // Internal function decls
  91. //
  92. NTSTATUS
  93. MpDevStartDevice(
  94. IN PDEVICE_OBJECT DeviceObject,
  95. IN PIRP Irp
  96. );
  97. //
  98. // The code.
  99. //
  100. NTSTATUS
  101. DriverEntry(
  102. IN PDRIVER_OBJECT DriverObject,
  103. IN PUNICODE_STRING RegistryPath
  104. )
  105. /*++
  106. Routine Description:
  107. This routine is called when the driver loads loads.
  108. Arguments:
  109. DriverObject - Supplies the driver object.
  110. RegistryPath - Supplies the registry path.
  111. Return Value:
  112. NTSTATUS
  113. --*/
  114. {
  115. ULONG i;
  116. MPDebugPrint((0,
  117. "MpDev: DriverEntry\n"));
  118. //
  119. // Setup forwarder for ALL Irp functions.
  120. //
  121. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  122. DriverObject->MajorFunction[i] = MpDevDefaultDispatch;
  123. }
  124. //
  125. // Specify those that we are interested in.
  126. //
  127. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MpDevInternalDeviceControl;
  128. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MpDevDeviceControl;
  129. DriverObject->MajorFunction[IRP_MJ_PNP] = MpDevPnPDispatch;
  130. DriverObject->MajorFunction[IRP_MJ_POWER] = MpDevPowerDispatch;
  131. DriverObject->DriverUnload = MpDevUnload;
  132. DriverObject->DriverExtension->AddDevice = MpDevAddDevice;
  133. return STATUS_SUCCESS;
  134. }
  135. NTSTATUS
  136. MpDevDefaultDispatch(
  137. IN PDEVICE_OBJECT DeviceObject,
  138. IN PIRP Irp
  139. )
  140. /*++
  141. Routine Description:
  142. This routine sends the Irp to the next driver in line
  143. when the Irp is not processed by this driver.
  144. Arguments:
  145. DeviceObject
  146. Irp
  147. Return Value:
  148. NTSTATUS
  149. --*/
  150. {
  151. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  152. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  153. IoSkipCurrentIrpStackLocation(Irp);
  154. return IoCallDriver(deviceExtension->TargetDevice, Irp);
  155. }
  156. NTSTATUS
  157. MpDevClaimDevice(
  158. IN PDEVICE_OBJECT DeviceObject,
  159. IN BOOLEAN Claim
  160. )
  161. /*++
  162. Routine Description:
  163. This is used to claim the underlying port pdo, so that only the mpdisk will be used
  164. by the class drivers.
  165. Arguments:
  166. DeviceObject - Supplies the scsiport device object.
  167. Claim - Indica0tes whether the device should be claimed or released.
  168. Return Value:
  169. Returns a status indicating success or failure of the operation.
  170. --*/
  171. {
  172. IO_STATUS_BLOCK ioStatus;
  173. PIRP irp;
  174. PIO_STACK_LOCATION irpStack;
  175. KEVENT event;
  176. NTSTATUS status;
  177. SCSI_REQUEST_BLOCK srb;
  178. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  179. //
  180. // Set the event object to the unsignaled state.
  181. // It will be used to signal request completion
  182. //
  183. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  184. //
  185. // Build synchronous request with no transfer.
  186. //
  187. irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
  188. DeviceObject,
  189. NULL,
  190. 0,
  191. NULL,
  192. 0,
  193. TRUE,
  194. &event,
  195. &ioStatus);
  196. if (irp == NULL) {
  197. return STATUS_INSUFFICIENT_RESOURCES;
  198. }
  199. irpStack = IoGetNextIrpStackLocation(irp);
  200. //
  201. // Save SRB address in next stack for port driver.
  202. //
  203. irpStack->Parameters.Scsi.Srb = &srb;
  204. //
  205. // Setup the SRB.
  206. //
  207. srb.Length = SCSI_REQUEST_BLOCK_SIZE;
  208. srb.Function = Claim ? SRB_FUNCTION_CLAIM_DEVICE : SRB_FUNCTION_RELEASE_DEVICE;
  209. srb.OriginalRequest = irp;
  210. //
  211. // Call the port driver with the request and wait for it to complete.
  212. //
  213. status = IoCallDriver(DeviceObject, irp);
  214. if (status == STATUS_PENDING) {
  215. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  216. status = ioStatus.Status;
  217. }
  218. return status;
  219. }
  220. NTSTATUS
  221. MpDevInternalDeviceControl(
  222. IN PDEVICE_OBJECT DeviceObject,
  223. IN PIRP Irp
  224. )
  225. /*++
  226. Routine Description:
  227. This routine handles IRM_MJ_INTERNAL_DEVICE_CONTROL and IRP_MJ_SCSI requests.
  228. It's main function is to simulate failed devices or adapters, based on IOCTLs
  229. sent from test applications.
  230. Arguments:
  231. DeviceObject - Supplies the device object.
  232. Irp - Supplies the IO request packet.
  233. Return Value:
  234. NTSTATUS
  235. --*/
  236. {
  237. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  238. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  239. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  240. return MpDevDefaultDispatch(DeviceObject, Irp);
  241. }
  242. NTSTATUS
  243. MpDevDeviceControl(
  244. IN PDEVICE_OBJECT DeviceObject,
  245. IN PIRP Irp
  246. )
  247. /*++
  248. Routine Description:
  249. This device control routine handles only the interactions between this driver and mpctl.
  250. The rest are passed down to scsiport.
  251. Arguments:
  252. DeviceObject - Supplies the device object.
  253. Irp - Supplies the IO request packet.
  254. Return Value:
  255. NTSTATUS
  256. --*/
  257. {
  258. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  259. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  260. NTSTATUS status;
  261. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  262. default:
  263. return MpDevDefaultDispatch(DeviceObject, Irp);
  264. }
  265. return status;
  266. }
  267. NTSTATUS
  268. MpDevPowerDispatch(
  269. IN PDEVICE_OBJECT DeviceObject,
  270. IN PIRP Irp
  271. )
  272. /*++
  273. Routine Description:
  274. Dispatch routine for Power Irps.
  275. Arguments:
  276. DeviceObject - Supplies the device object.
  277. Irp - Supplies the I/O request packet.
  278. Return Value:
  279. NTSTATUS
  280. --*/
  281. {
  282. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  283. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  284. //
  285. // TODO: Snoop these, and if the device is changing state notify mpctl.sys
  286. //
  287. PoStartNextPowerIrp(Irp);
  288. IoSkipCurrentIrpStackLocation(Irp);
  289. return PoCallDriver(deviceExtension->TargetDevice, Irp);
  290. }
  291. NTSTATUS
  292. MpDevPnPDispatch(
  293. IN PDEVICE_OBJECT DeviceObject,
  294. IN PIRP Irp
  295. )
  296. /*++
  297. Routine Description:
  298. Dispatch routine for PNP Irps.
  299. Arguments:
  300. DeviceObject - Supplies the device object.
  301. Irp - Supplies the I/O request packet.
  302. Return Value:
  303. NTSTATUS
  304. --*/
  305. {
  306. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  307. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  308. NTSTATUS status;
  309. KeClearEvent(&deviceExtension->Event);
  310. MPDebugPrint((2,
  311. "MpDevPnPDispatch: Minor Function (%x) for (%x)\n",
  312. irpStack->MinorFunction,
  313. DeviceObject));
  314. //
  315. // TODO: signal the associated pdisk of all power and pnp events.
  316. //
  317. switch (irpStack->MinorFunction) {
  318. case IRP_MN_QUERY_REMOVE_DEVICE:
  319. MPDebugPrint((2,
  320. "MPDevPnP: QueryRemove (%x)\n",
  321. DeviceObject));
  322. status = STATUS_DEVICE_BUSY;
  323. Irp->IoStatus.Status = status;
  324. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  325. return status;
  326. case IRP_MN_STOP_DEVICE:
  327. MPDebugPrint((2,
  328. "MpDevPnP: StopDevice (%x)\n",
  329. DeviceObject));
  330. break;
  331. case IRP_MN_REMOVE_DEVICE:
  332. case IRP_MN_SURPRISE_REMOVAL:
  333. MPDebugPrint((2,
  334. "MpDevPnP: RemoveDevice (%x)\n",
  335. DeviceObject));
  336. //status = STATUS_SUCCESS;
  337. //Irp->IoStatus.Status = status;
  338. //IoCompleteRequest(Irp, IO_NO_INCREMENT);
  339. //return status;
  340. break;
  341. case IRP_MN_START_DEVICE:
  342. return MpDevStartDevice(DeviceObject, Irp);
  343. case IRP_MN_QUERY_CAPABILITIES:
  344. case IRP_MN_QUERY_ID:
  345. default:
  346. return MpDevDefaultDispatch(DeviceObject, Irp);
  347. }
  348. return MpDevDefaultDispatch(DeviceObject, Irp);
  349. }
  350. NTSTATUS
  351. MpDevAddDevice(
  352. IN PDRIVER_OBJECT DriverObject,
  353. IN PDEVICE_OBJECT PhysicalDeviceObject
  354. )
  355. /*++
  356. Routine Description:
  357. Creates and initializes a new filter device object for the
  358. corresponding PDO. Then it attaches the device object to the device
  359. stack of the drivers for the device.
  360. Arguments:
  361. DriverObject
  362. PhysicalDeviceObject - Physical Device Object from the underlying layered driver
  363. Return Value:
  364. NTSTATUS
  365. --*/
  366. {
  367. PDEVICE_OBJECT deviceObject;
  368. PDEVICE_OBJECT controlDeviceObject;
  369. PDEVICE_EXTENSION deviceExtension;
  370. IO_STATUS_BLOCK ioStatus;
  371. UNICODE_STRING unicodeName;
  372. PFILE_OBJECT fileObject;
  373. WCHAR dosDeviceName[40];
  374. MPIO_REG_INFO ctlRegInfo;
  375. NTSTATUS status;
  376. PIRP irp;
  377. PDEVICE_OBJECT attachedDevice;
  378. //
  379. // Build the mpctl name.
  380. //
  381. swprintf(dosDeviceName, L"\\DosDevices\\MPathControl");
  382. RtlInitUnicodeString(&unicodeName, dosDeviceName);
  383. //
  384. // Get mpctl's deviceObject.
  385. //
  386. status = IoGetDeviceObjectPointer(&unicodeName,
  387. FILE_READ_ATTRIBUTES,
  388. &fileObject,
  389. &controlDeviceObject);
  390. if (NT_SUCCESS(status)) {
  391. MPIO_PDO_QUERY pdoQuery;
  392. pdoQuery.DeviceObject = PhysicalDeviceObject;
  393. //
  394. // Call mpctl to determine whether PhysicalDeviceObject is
  395. // one of it's children or a 'real' scsiport pdo.
  396. //
  397. MPLIBSendDeviceIoControlSynchronous(IOCTL_MPDEV_QUERY_PDO,
  398. controlDeviceObject,
  399. &pdoQuery,
  400. NULL,
  401. sizeof(MPIO_PDO_QUERY),
  402. 0,
  403. TRUE,
  404. &ioStatus);
  405. status = ioStatus.Status;
  406. MPDebugPrint((2,
  407. "MPDevAddDevice: Query on (%x). Status (%x)\n",
  408. PhysicalDeviceObject,
  409. status));
  410. #if 0
  411. if (status == STATUS_SUCCESS) {
  412. //
  413. // This indicates that PhysicalDeviceObject is really an MPDisk.
  414. // Don't want to load on this.
  415. //
  416. status = STATUS_NO_SUCH_DEVICE;
  417. } else {
  418. //
  419. // This indicates that PhysicalDeviceObject is a real one.
  420. //
  421. status = STATUS_SUCCESS;
  422. }
  423. #endif
  424. }
  425. if (!NT_SUCCESS(status)) {
  426. //
  427. // This indicates that PhysicalDeviceObject is really an MPDisk object or
  428. // that getting the control object failed.
  429. //
  430. return status;
  431. }
  432. if (DontLoad) {
  433. return STATUS_NO_SUCH_DEVICE;
  434. }
  435. status = IoCreateDevice(DriverObject,
  436. sizeof(DEVICE_EXTENSION),
  437. NULL,
  438. FILE_DEVICE_DISK,
  439. FILE_DEVICE_SECURE_OPEN,
  440. FALSE,
  441. &deviceObject);
  442. if (!NT_SUCCESS(status)) {
  443. MPDebugPrint((0,
  444. "MpDevAddDevice: Couldn't create device object (%x)\n",
  445. status));
  446. return status;
  447. }
  448. //
  449. // Start building the deviceExtension and attach to the lower device.
  450. //
  451. deviceExtension = deviceObject->DeviceExtension;
  452. deviceExtension->DeviceObject = deviceObject;
  453. deviceExtension->TargetDevice = IoAttachDeviceToDeviceStack(deviceObject,
  454. PhysicalDeviceObject);
  455. if (deviceExtension->TargetDevice == NULL) {
  456. MPDebugPrint((0,
  457. "MpDevAddDevice: Couldn't attach to device stack\n"));
  458. IoDeleteDevice(deviceObject);
  459. return STATUS_NO_SUCH_DEVICE;
  460. }
  461. //
  462. // Build IOCTL_MPDEV_REGISTER. This gives the port pdo to
  463. // mpctl to match up with one of it's children.
  464. // Mpctl then returns the PdoRegistration routine
  465. //
  466. ctlRegInfo.FilterObject = deviceObject;
  467. ctlRegInfo.LowerDevice = deviceExtension->TargetDevice;
  468. MPLIBSendDeviceIoControlSynchronous(IOCTL_MPDEV_REGISTER,
  469. controlDeviceObject,
  470. &ctlRegInfo,
  471. &ctlRegInfo,
  472. sizeof(MPIO_REG_INFO),
  473. sizeof(MPIO_REG_INFO),
  474. TRUE,
  475. &ioStatus);
  476. status = ioStatus.Status;
  477. //
  478. // Save off mpctls deviceObject.
  479. //
  480. deviceExtension->ControlDevice = controlDeviceObject;
  481. //
  482. // Update the flags by ORing in all of the set flags below.
  483. //
  484. deviceObject->Flags |= deviceExtension->TargetDevice->Flags & (DO_DIRECT_IO |
  485. DO_BUFFERED_IO |
  486. DO_POWER_PAGABLE |
  487. DO_POWER_INRUSH);
  488. //
  489. // Sync up other devObj stuff.
  490. //
  491. deviceObject->DeviceType = deviceExtension->TargetDevice->DeviceType;
  492. deviceObject->Characteristics = deviceExtension->TargetDevice->Characteristics;
  493. if (status == STATUS_SUCCESS) {
  494. //
  495. // Register with the MPDisk PDO. It will give back some notification
  496. // functions and update it's own internal structures to match
  497. // this filter with it's knowledge of scsiport's children.
  498. //
  499. status = ctlRegInfo.DevicePdoRegister(ctlRegInfo.MPDiskObject,
  500. deviceObject,
  501. PhysicalDeviceObject,
  502. &deviceExtension->PdoInfo);
  503. MPDebugPrint((2,
  504. "MpDevAddDevice: Status of PdoRegister (%x)\n",
  505. status));
  506. if (status == STATUS_SUCCESS) {
  507. status = MpDevClaimDevice(deviceExtension->TargetDevice,
  508. TRUE);
  509. if (status == STATUS_SUCCESS) {
  510. MPDebugPrint((2,
  511. "MpDevAddDevice: Claim of (%x) successful.\n",
  512. deviceExtension->TargetDevice));
  513. } else {
  514. MPDebugPrint((1,
  515. "MpDevAddDevice: Claim of (%x) not successful. Status (%x)\n",
  516. deviceExtension->TargetDevice,
  517. status));
  518. }
  519. }
  520. }
  521. //
  522. // Indicate that we are ready.
  523. //
  524. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  525. MPDebugPrint((2,
  526. "MPDevAddDevice: Returning (%x) on D.O. (%x)\n",
  527. status,
  528. PhysicalDeviceObject));
  529. return status;
  530. }
  531. NTSTATUS
  532. MpDevUnload(
  533. IN PDRIVER_OBJECT DriverObject
  534. )
  535. {
  536. return STATUS_SUCCESS;
  537. }
  538. NTSTATUS
  539. MpDevSyncCompletion(
  540. IN PDEVICE_OBJECT DeviceObject,
  541. IN PIRP Irp,
  542. IN PVOID Context
  543. )
  544. /*++
  545. Routine Description:
  546. Completion routine for sync forwarding of Irps.
  547. Arguments:
  548. DeviceObject
  549. Irp
  550. Context
  551. Return Value:
  552. STATUS_MORE_PROCESSING_REQUIRED
  553. --*/
  554. {
  555. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)Context;
  556. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  557. NTSTATUS status;
  558. UNREFERENCED_PARAMETER(DeviceObject);
  559. //
  560. // Set the event on which the dispatch handler is waiting.
  561. //
  562. KeSetEvent(&deviceExtension->Event,
  563. 0,
  564. FALSE);
  565. return STATUS_MORE_PROCESSING_REQUIRED;
  566. }
  567. NTSTATUS
  568. MpDevStartDevice(
  569. IN PDEVICE_OBJECT DeviceObject,
  570. IN PIRP Irp
  571. )
  572. /*++
  573. Routine Description:
  574. Handles Start requests by sending the start down to scsiport. The completion will signal
  575. the event and then device object flags and characteristics are updated.
  576. Arguments:
  577. DeviceObject - Supplies the device object.
  578. Irp - Supplies the I/O request packet.
  579. Return Value:
  580. Status of the operations.
  581. --*/
  582. {
  583. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  584. NTSTATUS status;
  585. //
  586. // Setup initial status.
  587. //
  588. Irp->IoStatus.Status = STATUS_SUCCESS;
  589. //
  590. // Clone the stack location.
  591. //
  592. IoCopyCurrentIrpStackLocationToNext(Irp);
  593. //
  594. // Setup the completion routine. It will set the event that we wait on below.
  595. //
  596. IoSetCompletionRoutine(Irp,
  597. MpDevSyncCompletion,
  598. deviceExtension,
  599. TRUE,
  600. TRUE,
  601. TRUE);
  602. KeInitializeEvent(&deviceExtension->Event,
  603. NotificationEvent,
  604. FALSE);
  605. //
  606. // Call port with the request.
  607. //
  608. status = IoCallDriver(deviceExtension->TargetDevice, Irp);
  609. if (status == STATUS_PENDING) {
  610. KeWaitForSingleObject(&deviceExtension->Event,
  611. Executive,
  612. KernelMode,
  613. FALSE,
  614. NULL);
  615. status = Irp->IoStatus.Status;
  616. }
  617. if (NT_SUCCESS(status)) {
  618. //
  619. // Sync up our stuff with scsiport's.
  620. //
  621. DeviceObject->Flags |= deviceExtension->TargetDevice->Flags;
  622. DeviceObject->Characteristics |= deviceExtension->TargetDevice->Characteristics;
  623. }
  624. Irp->IoStatus.Status = status;
  625. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  626. return status;
  627. }