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

6771 lines
194 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. disk.c
  5. Abstract:
  6. SCSI disk class driver
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. --*/
  12. #include "disk.h"
  13. //
  14. // Now instantiate the GUIDs
  15. //
  16. #include "initguid.h"
  17. #include "ntddstor.h"
  18. #include "ntddvol.h"
  19. #include "ioevent.h"
  20. NTSTATUS
  21. DiskDetermineMediaTypes(
  22. IN PDEVICE_OBJECT Fdo,
  23. IN PIRP Irp,
  24. IN UCHAR MediumType,
  25. IN UCHAR DensityCode,
  26. IN BOOLEAN MediaPresent,
  27. IN BOOLEAN IsWritable
  28. );
  29. PPARTITION_INFORMATION_EX
  30. DiskPdoFindPartitionEntry(
  31. IN PPHYSICAL_DEVICE_EXTENSION Pdo,
  32. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
  33. );
  34. PPARTITION_INFORMATION_EX
  35. DiskFindAdjacentPartition(
  36. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
  37. IN PPARTITION_INFORMATION_EX BasePartition
  38. );
  39. PPARTITION_INFORMATION_EX
  40. DiskFindContainingPartition(
  41. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
  42. IN PPARTITION_INFORMATION_EX BasePartition,
  43. IN BOOLEAN SearchTopToBottom
  44. );
  45. NTSTATUS
  46. DiskIoctlCreateDisk(
  47. IN PDEVICE_OBJECT DeviceObject,
  48. IN PIRP Irp
  49. );
  50. NTSTATUS
  51. DiskIoctlGetDriveLayout(
  52. IN PDEVICE_OBJECT DeviceObject,
  53. IN PIRP Irp
  54. );
  55. NTSTATUS
  56. DiskIoctlGetDriveLayoutEx(
  57. IN PDEVICE_OBJECT DeviceObject,
  58. IN PIRP Irp
  59. );
  60. NTSTATUS
  61. DiskIoctlSetDriveLayout(
  62. IN PDEVICE_OBJECT DeviceObject,
  63. IN PIRP Irp
  64. );
  65. NTSTATUS
  66. DiskIoctlSetDriveLayoutEx(
  67. IN PDEVICE_OBJECT DeviceObject,
  68. IN PIRP Irp
  69. );
  70. NTSTATUS
  71. DiskIoctlGetPartitionInfo(
  72. IN PDEVICE_OBJECT DeviceObject,
  73. IN PIRP Irp
  74. );
  75. NTSTATUS
  76. DiskIoctlGetPartitionInfoEx(
  77. IN PDEVICE_OBJECT DeviceObject,
  78. IN PIRP Irp
  79. );
  80. NTSTATUS
  81. DiskIoctlGetLengthInfo(
  82. IN PDEVICE_OBJECT DeviceObject,
  83. IN PIRP Irp
  84. );
  85. NTSTATUS
  86. DiskIoctlSetPartitionInfo(
  87. IN PDEVICE_OBJECT DeviceObject,
  88. IN PIRP Irp
  89. );
  90. NTSTATUS
  91. DiskIoctlSetPartitionInfoEx(
  92. IN PDEVICE_OBJECT DeviceObject,
  93. IN PIRP Irp
  94. );
  95. NTSTATUS
  96. DiskIoctlSetPartitionInfoEx(
  97. IN PDEVICE_OBJECT DeviceObject,
  98. IN PIRP Irp
  99. );
  100. NTSTATUS
  101. DiskIoctlGetDriveGeometryEx(
  102. IN PDEVICE_OBJECT DeviceObject,
  103. IN PIRP Irp
  104. );
  105. #ifdef ALLOC_PRAGMA
  106. #pragma alloc_text(INIT, DriverEntry)
  107. #pragma alloc_text(PAGE, DiskUnload)
  108. #pragma alloc_text(PAGE, DiskCreateFdo)
  109. #pragma alloc_text(PAGE, DiskDetermineMediaTypes)
  110. #pragma alloc_text(PAGE, DiskShutdownFlush)
  111. #pragma alloc_text(PAGE, DiskFlushDispatch)
  112. #pragma alloc_text(PAGE, DiskModeSelect)
  113. #pragma alloc_text(PAGE, DisableWriteCache)
  114. #pragma alloc_text(PAGE, DiskIoctlVerify)
  115. #pragma alloc_text(PAGE, DiskSetSpecialHacks)
  116. #pragma alloc_text(PAGE, DiskQueryPnpCapabilities)
  117. #pragma alloc_text(PAGE, DiskGetCacheInformation)
  118. #pragma alloc_text(PAGE, DiskSetCacheInformation)
  119. #pragma alloc_text(PAGE, DiskLogCacheInformation)
  120. #pragma alloc_text(PAGE, DiskSetInfoExceptionInformation)
  121. #pragma alloc_text(PAGE, DiskGetInfoExceptionInformation)
  122. #pragma alloc_text(PAGE, DiskPdoFindPartitionEntry)
  123. #pragma alloc_text(PAGE, DiskFindAdjacentPartition)
  124. #pragma alloc_text(PAGE, DiskFindContainingPartition)
  125. #pragma alloc_text(PAGE, DiskIoctlCreateDisk)
  126. #pragma alloc_text(PAGE, DiskIoctlGetDriveLayout)
  127. #pragma alloc_text(PAGE, DiskIoctlGetDriveLayoutEx)
  128. #pragma alloc_text(PAGE, DiskIoctlSetDriveLayout)
  129. #pragma alloc_text(PAGE, DiskIoctlSetDriveLayoutEx)
  130. #pragma alloc_text(PAGE, DiskIoctlGetPartitionInfo)
  131. #pragma alloc_text(PAGE, DiskIoctlGetPartitionInfoEx)
  132. #pragma alloc_text(PAGE, DiskIoctlGetLengthInfo)
  133. #pragma alloc_text(PAGE, DiskIoctlSetPartitionInfo)
  134. #pragma alloc_text(PAGE, DiskIoctlSetPartitionInfoEx)
  135. #pragma alloc_text(PAGE, DiskIoctlGetDriveGeometryEx)
  136. #endif
  137. extern ULONG DiskDisableGpt;
  138. const GUID GUID_NULL = { 0 };
  139. #define DiskCompareGuid(_First,_Second) \
  140. (memcmp ((_First),(_Second), sizeof (GUID)))
  141. //
  142. // This macro is used to work around a bug in the definition of
  143. // DISK_CACHE_RETENTION_PRIORITY. The value KeepReadData should be
  144. // assigned 0xf rather than 0x2. Since the interface was already published
  145. // when this was discovered the disk driver has been modified to translate
  146. // between the interface value and the correct scsi value.
  147. //
  148. // 0x2 is turned into 0xf
  149. // 0xf is turned into 0x2 - this ensures that future SCSI defintions can be
  150. // accomodated.
  151. //
  152. #define TRANSLATE_RETENTION_PRIORITY(_x)\
  153. ((_x) == 0xf ? 0x2 : \
  154. ((_x) == 0x2 ? 0xf : _x) \
  155. )
  156. #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN CTL_CODE(IOCTL_VOLUME_BASE, 0, METHOD_BUFFERED, FILE_READ_ACCESS)
  157. NTSTATUS
  158. DriverEntry(
  159. IN PDRIVER_OBJECT DriverObject,
  160. IN PUNICODE_STRING RegistryPath
  161. )
  162. /*++
  163. Routine Description:
  164. This routine initializes the SCSI hard disk class driver.
  165. Arguments:
  166. DriverObject - Pointer to driver object created by system.
  167. RegistryPath - Pointer to the name of the services node for this driver.
  168. Return Value:
  169. The function value is the final status from the initialization operation.
  170. --*/
  171. {
  172. CLASS_INIT_DATA InitializationData = { 0 };
  173. CLASS_QUERY_WMI_REGINFO_EX_LIST classQueryWmiRegInfoExList = { 0 };
  174. GUID guidQueryRegInfoEx = GUID_CLASSPNP_QUERY_REGINFOEX;
  175. NTSTATUS status;
  176. #if defined(_X86_)
  177. //
  178. // Read the information NtDetect squirreled away about the disks in this
  179. // system.
  180. //
  181. DiskSaveDetectInfo(DriverObject);
  182. #endif
  183. InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
  184. //
  185. // Setup sizes and entry points for functional device objects
  186. //
  187. InitializationData.FdoData.DeviceExtensionSize = FUNCTIONAL_EXTENSION_SIZE;
  188. InitializationData.FdoData.DeviceType = FILE_DEVICE_DISK;
  189. InitializationData.FdoData.DeviceCharacteristics = FILE_DEVICE_SECURE_OPEN;
  190. InitializationData.FdoData.ClassInitDevice = DiskInitFdo;
  191. InitializationData.FdoData.ClassStartDevice = DiskStartFdo;
  192. InitializationData.FdoData.ClassStopDevice = DiskStopDevice;
  193. InitializationData.FdoData.ClassRemoveDevice = DiskRemoveDevice;
  194. InitializationData.FdoData.ClassPowerDevice = ClassSpinDownPowerHandler;
  195. InitializationData.FdoData.ClassError = DiskFdoProcessError;
  196. InitializationData.FdoData.ClassReadWriteVerification = DiskReadWriteVerification;
  197. InitializationData.FdoData.ClassDeviceControl = DiskDeviceControl;
  198. InitializationData.FdoData.ClassShutdownFlush = DiskShutdownFlush;
  199. InitializationData.FdoData.ClassCreateClose = NULL;
  200. //
  201. // Setup sizes and entry points for physical device objects
  202. //
  203. InitializationData.PdoData.DeviceExtensionSize = PHYSICAL_EXTENSION_SIZE;
  204. InitializationData.PdoData.DeviceType = FILE_DEVICE_DISK;
  205. InitializationData.PdoData.DeviceCharacteristics = FILE_DEVICE_SECURE_OPEN;
  206. InitializationData.PdoData.ClassInitDevice = DiskInitPdo;
  207. InitializationData.PdoData.ClassStartDevice = DiskStartPdo;
  208. InitializationData.PdoData.ClassStopDevice = DiskStopDevice;
  209. InitializationData.PdoData.ClassRemoveDevice = DiskRemoveDevice;
  210. //
  211. // Use default power routine for PDOs
  212. //
  213. InitializationData.PdoData.ClassPowerDevice = NULL;
  214. InitializationData.PdoData.ClassError = NULL;
  215. InitializationData.PdoData.ClassReadWriteVerification = DiskReadWriteVerification;
  216. InitializationData.PdoData.ClassDeviceControl = DiskDeviceControl;
  217. InitializationData.PdoData.ClassShutdownFlush = DiskShutdownFlush;
  218. InitializationData.PdoData.ClassCreateClose = NULL;
  219. InitializationData.PdoData.ClassQueryPnpCapabilities = DiskQueryPnpCapabilities;
  220. InitializationData.ClassAddDevice = DiskAddDevice;
  221. InitializationData.ClassEnumerateDevice = DiskEnumerateDevice;
  222. InitializationData.ClassQueryId = DiskQueryId;
  223. InitializationData.FdoData.ClassWmiInfo.GuidCount = 7;
  224. InitializationData.FdoData.ClassWmiInfo.GuidRegInfo = DiskWmiFdoGuidList;
  225. InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiRegInfo = DiskFdoQueryWmiRegInfo;
  226. InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiDataBlock = DiskFdoQueryWmiDataBlock;
  227. InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataBlock = DiskFdoSetWmiDataBlock;
  228. InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataItem = DiskFdoSetWmiDataItem;
  229. InitializationData.FdoData.ClassWmiInfo.ClassExecuteWmiMethod = DiskFdoExecuteWmiMethod;
  230. InitializationData.FdoData.ClassWmiInfo.ClassWmiFunctionControl = DiskWmiFunctionControl;
  231. #if 0
  232. //
  233. // Enable this to add WMI support for PDOs
  234. InitializationData.PdoData.ClassWmiInfo.GuidCount = 1;
  235. InitializationData.PdoData.ClassWmiInfo.GuidRegInfo = DiskWmiPdoGuidList;
  236. InitializationData.PdoData.ClassWmiInfo.ClassQueryWmiRegInfo = DiskPdoQueryWmiRegInfo;
  237. InitializationData.PdoData.ClassWmiInfo.ClassQueryWmiDataBlock = DiskPdoQueryWmiDataBlock;
  238. InitializationData.PdoData.ClassWmiInfo.ClassSetWmiDataBlock = DiskPdoSetWmiDataBlock;
  239. InitializationData.PdoData.ClassWmiInfo.ClassSetWmiDataItem = DiskPdoSetWmiDataItem;
  240. InitializationData.PdoData.ClassWmiInfo.ClassExecuteWmiMethod = DiskPdoExecuteWmiMethod;
  241. InitializationData.PdoData.ClassWmiInfo.ClassWmiFunctionControl = DiskWmiFunctionControl;
  242. #endif
  243. InitializationData.ClassUnload = DiskUnload;
  244. //
  245. // Initialize regregistration data structures
  246. //
  247. DiskInitializeReregistration();
  248. //
  249. // Call the class init routine
  250. //
  251. status = ClassInitialize(DriverObject, RegistryPath, &InitializationData);
  252. #if defined(_X86_)
  253. if(NT_SUCCESS(status)) {
  254. IoRegisterBootDriverReinitialization(DriverObject,
  255. DiskDriverReinitialization,
  256. NULL);
  257. }
  258. #endif
  259. //
  260. // Call class init Ex routine to register a
  261. // PCLASS_QUERY_WMI_REGINFO_EX routine
  262. //
  263. classQueryWmiRegInfoExList.Size = sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST);
  264. classQueryWmiRegInfoExList.ClassFdoQueryWmiRegInfoEx = DiskFdoQueryWmiRegInfoEx;
  265. ClassInitializeEx(DriverObject,
  266. &guidQueryRegInfoEx,
  267. &classQueryWmiRegInfoExList);
  268. return status;
  269. } // end DriverEntry()
  270. VOID
  271. DiskUnload(
  272. IN PDRIVER_OBJECT DriverObject
  273. )
  274. {
  275. PAGED_CODE();
  276. #if defined(_X86_)
  277. DiskCleanupDetectInfo(DriverObject);
  278. #endif
  279. return;
  280. }
  281. NTSTATUS
  282. DiskCreateFdo(
  283. IN PDRIVER_OBJECT DriverObject,
  284. IN PDEVICE_OBJECT PhysicalDeviceObject,
  285. IN PULONG DeviceCount,
  286. IN BOOLEAN DasdAccessOnly
  287. )
  288. /*++
  289. Routine Description:
  290. This routine creates an object for the functional device
  291. Arguments:
  292. DriverObject - Pointer to driver object created by system.
  293. PhysicalDeviceObject - Lower level driver we should attach to
  294. DeviceCount - Number of previously installed devices.
  295. DasdAccessOnly - indicates whether or not a file system is allowed to mount
  296. on this device object. Used to avoid double-mounting of
  297. file systems on super-floppies (which can unfortunately be
  298. fixed disks). If set the i/o system will only allow rawfs
  299. to be mounted.
  300. Return Value:
  301. NTSTATUS
  302. --*/
  303. {
  304. PUCHAR deviceName = NULL;
  305. HANDLE handle = NULL;
  306. PDEVICE_OBJECT lowerDevice = NULL;
  307. PDEVICE_OBJECT deviceObject = NULL;
  308. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  309. NTSTATUS status;
  310. PAGED_CODE();
  311. *DeviceCount = 0;
  312. //
  313. // Set up an object directory to contain the objects for this
  314. // device and all its partitions.
  315. //
  316. do {
  317. WCHAR dirBuffer[64] = { 0 };
  318. UNICODE_STRING dirName;
  319. OBJECT_ATTRIBUTES objectAttribs;
  320. _snwprintf(dirBuffer, sizeof(dirBuffer) / sizeof(dirBuffer[0]) - 1, L"\\Device\\Harddisk%d", *DeviceCount);
  321. RtlInitUnicodeString(&dirName, dirBuffer);
  322. InitializeObjectAttributes(&objectAttribs,
  323. &dirName,
  324. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  325. NULL,
  326. NULL);
  327. status = ZwCreateDirectoryObject(&handle,
  328. DIRECTORY_ALL_ACCESS,
  329. &objectAttribs);
  330. (*DeviceCount)++;
  331. } while((status == STATUS_OBJECT_NAME_COLLISION) ||
  332. (status == STATUS_OBJECT_NAME_EXISTS));
  333. if (!NT_SUCCESS(status)) {
  334. DebugPrint((1, "DiskCreateFdo: Could not create directory - %lx\n",
  335. status));
  336. return(status);
  337. }
  338. //
  339. // When this loop exits the count is inflated by one - fix that.
  340. //
  341. (*DeviceCount)--;
  342. //
  343. // Claim the device.
  344. //
  345. lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
  346. status = ClassClaimDevice(lowerDevice, FALSE);
  347. if (!NT_SUCCESS(status)) {
  348. ZwMakeTemporaryObject(handle);
  349. ZwClose(handle);
  350. ObDereferenceObject(lowerDevice);
  351. return status;
  352. }
  353. //
  354. // Create a device object for this device. Each physical disk will
  355. // have at least one device object. The required device object
  356. // describes the entire device. Its directory path is
  357. // \Device\HarddiskN\Partition0, where N = device number.
  358. //
  359. status = DiskGenerateDeviceName(TRUE,
  360. *DeviceCount,
  361. 0,
  362. NULL,
  363. NULL,
  364. &deviceName);
  365. if(!NT_SUCCESS(status)) {
  366. DebugPrint((1, "DiskCreateFdo - couldn't create name %lx\n",
  367. status));
  368. goto DiskCreateFdoExit;
  369. }
  370. status = ClassCreateDeviceObject(DriverObject,
  371. deviceName,
  372. PhysicalDeviceObject,
  373. TRUE,
  374. &deviceObject);
  375. if (!NT_SUCCESS(status)) {
  376. DebugPrint((1,
  377. "DiskCreateFdo: Can not create device object %s\n",
  378. deviceName));
  379. goto DiskCreateFdoExit;
  380. }
  381. //
  382. // Indicate that IRPs should include MDLs for data transfers.
  383. //
  384. SET_FLAG(deviceObject->Flags, DO_DIRECT_IO);
  385. fdoExtension = deviceObject->DeviceExtension;
  386. if(DasdAccessOnly) {
  387. //
  388. // Inidicate that only RAW should be allowed to mount on the root
  389. // partition object. This ensures that a file system can't doubly
  390. // mount on a super-floppy by mounting once on P0 and once on P1.
  391. //
  392. SET_FLAG(deviceObject->Vpb->Flags, VPB_RAW_MOUNT);
  393. }
  394. //
  395. // Initialize lock count to zero. The lock count is used to
  396. // disable the ejection mechanism on devices that support
  397. // removable media. Only the lock count in the physical
  398. // device extension is used.
  399. //
  400. fdoExtension->LockCount = 0;
  401. //
  402. // Save system disk number.
  403. //
  404. fdoExtension->DeviceNumber = *DeviceCount;
  405. //
  406. // Set the alignment requirements for the device based on the
  407. // host adapter requirements
  408. //
  409. if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
  410. deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
  411. }
  412. //
  413. // Finally, attach to the pdo
  414. //
  415. fdoExtension->LowerPdo = PhysicalDeviceObject;
  416. fdoExtension->CommonExtension.LowerDeviceObject =
  417. IoAttachDeviceToDeviceStack(
  418. deviceObject,
  419. PhysicalDeviceObject);
  420. if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
  421. //
  422. // Uh - oh, we couldn't attach
  423. // cleanup and return
  424. //
  425. status = STATUS_UNSUCCESSFUL;
  426. goto DiskCreateFdoExit;
  427. }
  428. {
  429. PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
  430. //
  431. // Initialize the partitioning lock as it may be used in the remove
  432. // code.
  433. //
  434. KeInitializeEvent(&(diskData->PartitioningEvent),
  435. SynchronizationEvent,
  436. TRUE);
  437. }
  438. //
  439. // Clear the init flag.
  440. //
  441. CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING);
  442. //
  443. // Store a handle to the device object directory for this disk
  444. //
  445. fdoExtension->DeviceDirectory = handle;
  446. ObDereferenceObject(lowerDevice);
  447. return STATUS_SUCCESS;
  448. DiskCreateFdoExit:
  449. if (deviceObject != NULL)
  450. {
  451. IoDeleteDevice(deviceObject);
  452. }
  453. if (deviceName != NULL)
  454. {
  455. ExFreePool(deviceName);
  456. }
  457. ObDereferenceObject(lowerDevice);
  458. ZwMakeTemporaryObject(handle);
  459. ZwClose(handle);
  460. return status;
  461. }
  462. NTSTATUS
  463. DiskReadWriteVerification(
  464. IN PDEVICE_OBJECT DeviceObject,
  465. IN PIRP Irp
  466. )
  467. /*++
  468. Routine Description:
  469. I/O System entry for read and write requests to SCSI disks.
  470. Arguments:
  471. DeviceObject - Pointer to driver object created by system.
  472. Irp - IRP involved.
  473. Return Value:
  474. NT Status
  475. --*/
  476. {
  477. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  478. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  479. ULONG residualBytes;
  480. NTSTATUS status = STATUS_SUCCESS;
  481. //
  482. // Make sure that the request is within the bounds of the partition and
  483. // that the number of bytes to transfer is a multiple of the sector size
  484. //
  485. residualBytes = irpSp->Parameters.Read.Length & (commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector - 1);
  486. if ((irpSp->Parameters.Read.ByteOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
  487. (irpSp->Parameters.Read.ByteOffset.QuadPart < 0) ||
  488. (residualBytes != 0))
  489. {
  490. status = STATUS_INVALID_PARAMETER;
  491. }
  492. else
  493. {
  494. ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - irpSp->Parameters.Read.ByteOffset.QuadPart;
  495. if ((ULONGLONG)irpSp->Parameters.Read.Length > bytesRemaining)
  496. {
  497. status = STATUS_INVALID_PARAMETER;
  498. }
  499. }
  500. if (!NT_SUCCESS(status))
  501. {
  502. //
  503. // This error may be caused by the fact that the drive is not ready.
  504. //
  505. status = ((PDISK_DATA) commonExtension->DriverData)->ReadyStatus;
  506. if (!NT_SUCCESS(status)) {
  507. //
  508. // Flag this as a user errror so that a popup is generated.
  509. //
  510. DebugPrint((1, "DiskReadWriteVerification: ReadyStatus is %lx\n",
  511. status));
  512. IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
  513. //
  514. // status will keep the current error
  515. //
  516. ASSERT( status != STATUS_INSUFFICIENT_RESOURCES );
  517. } else if((commonExtension->IsFdo == TRUE) && (residualBytes == 0)) {
  518. //
  519. // This failed because we think the physical disk is too small.
  520. // Send it down to the drive and let the hardware decide for
  521. // itself.
  522. //
  523. status = STATUS_SUCCESS;
  524. } else {
  525. //
  526. // Note fastfat depends on this parameter to determine when to
  527. // remount due to a sector size change.
  528. //
  529. status = STATUS_INVALID_PARAMETER;
  530. }
  531. }
  532. Irp->IoStatus.Status = status;
  533. return status;
  534. } // end DiskReadWrite()
  535. NTSTATUS
  536. DiskDetermineMediaTypes(
  537. IN PDEVICE_OBJECT Fdo,
  538. IN PIRP Irp,
  539. IN UCHAR MediumType,
  540. IN UCHAR DensityCode,
  541. IN BOOLEAN MediaPresent,
  542. IN BOOLEAN IsWritable
  543. )
  544. /*++
  545. Routine Description:
  546. Determines number of types based on the physical device, validates the user buffer
  547. and builds the MEDIA_TYPE information.
  548. Arguments:
  549. DeviceObject - Pointer to functional device object created by system.
  550. Irp - IOCTL_STORAGE_GET_MEDIA_TYPES_EX Irp.
  551. MediumType - byte returned in mode data header.
  552. DensityCode - byte returned in mode data block descriptor.
  553. NumberOfTypes - pointer to be updated based on actual device.
  554. Return Value:
  555. Status is returned.
  556. --*/
  557. {
  558. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  559. PPHYSICAL_DEVICE_EXTENSION pdoExtension = Fdo->DeviceExtension;
  560. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  561. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  562. PGET_MEDIA_TYPES mediaTypes = Irp->AssociatedIrp.SystemBuffer;
  563. PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
  564. BOOLEAN deviceMatched = FALSE;
  565. PAGED_CODE();
  566. //
  567. // this should be checked prior to calling into this routine
  568. // as we use the buffer as mediaTypes
  569. //
  570. ASSERT(irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
  571. sizeof(GET_MEDIA_TYPES));
  572. //
  573. // Determine if this device is removable or fixed.
  574. //
  575. if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
  576. //
  577. // Fixed disk.
  578. //
  579. mediaTypes->DeviceType = FILE_DEVICE_DISK;
  580. mediaTypes->MediaInfoCount = 1;
  581. mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
  582. mediaInfo->DeviceSpecific.DiskInfo.MediaType = FixedMedia;
  583. mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
  584. mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
  585. mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
  586. mediaInfo->DeviceSpecific.DiskInfo.NumberMediaSides = 1;
  587. mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE);
  588. if (!IsWritable) {
  589. SET_FLAG(mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics,
  590. MEDIA_WRITE_PROTECTED);
  591. }
  592. } else {
  593. PUCHAR vendorId = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->VendorIdOffset;
  594. PUCHAR productId = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductIdOffset;
  595. PUCHAR productRevision = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductRevisionOffset;
  596. DISK_MEDIA_TYPES_LIST const *mediaListEntry;
  597. ULONG currentMedia;
  598. ULONG i;
  599. ULONG j;
  600. ULONG sizeNeeded;
  601. DebugPrint((1,
  602. "DiskDetermineMediaTypes: Vendor %s, Product %s\n",
  603. vendorId,
  604. productId));
  605. //
  606. // Run through the list until we find the entry with a NULL Vendor Id.
  607. //
  608. for (i = 0; DiskMediaTypes[i].VendorId != NULL; i++) {
  609. mediaListEntry = &DiskMediaTypes[i];
  610. if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) {
  611. continue;
  612. }
  613. if ((mediaListEntry->ProductId != NULL) &&
  614. strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) {
  615. continue;
  616. }
  617. if ((mediaListEntry->Revision != NULL) &&
  618. strncmp(mediaListEntry->Revision, productRevision, strlen(mediaListEntry->Revision))) {
  619. continue;
  620. }
  621. deviceMatched = TRUE;
  622. mediaTypes->DeviceType = FILE_DEVICE_DISK;
  623. mediaTypes->MediaInfoCount = mediaListEntry->NumberOfTypes;
  624. //
  625. // Ensure that buffer is large enough.
  626. //
  627. sizeNeeded = FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) +
  628. (mediaListEntry->NumberOfTypes *
  629. sizeof(DEVICE_MEDIA_INFO)
  630. );
  631. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  632. sizeNeeded) {
  633. //
  634. // Buffer too small
  635. //
  636. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  637. return STATUS_BUFFER_TOO_SMALL;
  638. }
  639. for (j = 0; j < mediaListEntry->NumberOfTypes; j++) {
  640. mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
  641. mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
  642. mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
  643. mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
  644. mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = mediaListEntry->NumberOfSides;
  645. //
  646. // Set the type.
  647. //
  648. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = mediaListEntry->MediaTypes[j];
  649. if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == MO_5_WO) {
  650. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_WRITE_ONCE;
  651. } else {
  652. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
  653. }
  654. //
  655. // Status will either be success, if media is present, or no media.
  656. // It would be optimal to base from density code and medium type, but not all devices
  657. // have values for these fields.
  658. //
  659. if (MediaPresent) {
  660. //
  661. // The usage of MediumType and DensityCode is device specific, so this may need
  662. // to be extended to further key off of product/vendor ids.
  663. // Currently, the MO units are the only devices that return this information.
  664. //
  665. if (MediumType == 2) {
  666. currentMedia = MO_5_WO;
  667. } else if (MediumType == 3) {
  668. currentMedia = MO_5_RW;
  669. if (DensityCode == 0x87) {
  670. //
  671. // Indicate that the pinnacle 4.6 G media
  672. // is present. Other density codes will default to normal
  673. // RW MO media.
  674. //
  675. currentMedia = PINNACLE_APEX_5_RW;
  676. }
  677. } else {
  678. currentMedia = 0;
  679. }
  680. if (currentMedia) {
  681. if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == (STORAGE_MEDIA_TYPE)currentMedia) {
  682. SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
  683. }
  684. } else {
  685. SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
  686. }
  687. }
  688. if (!IsWritable) {
  689. SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED);
  690. }
  691. //
  692. // Advance to next entry.
  693. //
  694. mediaInfo++;
  695. }
  696. }
  697. if (!deviceMatched) {
  698. DebugPrint((1,
  699. "DiskDetermineMediaTypes: Unknown device. Vendor: %s Product: %s Revision: %s\n",
  700. vendorId,
  701. productId,
  702. productRevision));
  703. //
  704. // Build an entry for unknown.
  705. //
  706. mediaTypes->DeviceType = FILE_DEVICE_DISK;
  707. mediaTypes->MediaInfoCount = 1;
  708. mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
  709. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia;
  710. mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
  711. mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
  712. mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
  713. mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
  714. mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
  715. if (MediaPresent) {
  716. SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
  717. }
  718. if (!IsWritable) {
  719. SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED);
  720. }
  721. }
  722. }
  723. Irp->IoStatus.Information =
  724. FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) +
  725. (mediaTypes->MediaInfoCount * sizeof(DEVICE_MEDIA_INFO));
  726. return STATUS_SUCCESS;
  727. }
  728. NTSTATUS
  729. DiskDeviceControl(
  730. PDEVICE_OBJECT DeviceObject,
  731. PIRP Irp
  732. )
  733. /*++
  734. Routine Description:
  735. I/O system entry for device controls to SCSI disks.
  736. Arguments:
  737. Fdo - Pointer to functional device object created by system.
  738. Irp - IRP involved.
  739. Return Value:
  740. Status is returned.
  741. --*/
  742. #define SendToFdo(Dev, Irp, Rval) { \
  743. PCOMMON_DEVICE_EXTENSION ce = Dev->DeviceExtension; \
  744. ASSERT_PDO(Dev); \
  745. IoCopyCurrentIrpStackLocationToNext(Irp); \
  746. Rval = IoCallDriver(ce->LowerDeviceObject, Irp); \
  747. }
  748. {
  749. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  750. PPHYSICAL_DEVICE_EXTENSION pdoExtension = DeviceObject->DeviceExtension;
  751. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  752. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  753. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  754. PSCSI_REQUEST_BLOCK srb;
  755. PCDB cdb;
  756. PMODE_PARAMETER_HEADER modeData;
  757. PIRP irp2;
  758. ULONG length;
  759. NTSTATUS status;
  760. KEVENT event;
  761. IO_STATUS_BLOCK ioStatus = { 0 };
  762. BOOLEAN b = FALSE;
  763. srb = ExAllocatePoolWithTag(NonPagedPool,
  764. SCSI_REQUEST_BLOCK_SIZE,
  765. DISK_TAG_SRB);
  766. Irp->IoStatus.Information = 0;
  767. if (srb == NULL) {
  768. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  769. ClassReleaseRemoveLock(DeviceObject, Irp);
  770. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  771. return(STATUS_INSUFFICIENT_RESOURCES);
  772. }
  773. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  774. cdb = (PCDB)srb->Cdb;
  775. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  776. case IOCTL_DISK_GET_CACHE_INFORMATION:
  777. b = TRUE;
  778. case IOCTL_DISK_SET_CACHE_INFORMATION: {
  779. BOOLEAN getCaching = b;
  780. PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer;
  781. if(!commonExtension->IsFdo) {
  782. ClassReleaseRemoveLock(DeviceObject, Irp);
  783. ExFreePool(srb);
  784. SendToFdo(DeviceObject, Irp, status);
  785. return status;
  786. }
  787. //
  788. // Validate the request.
  789. //
  790. if((getCaching) &&
  791. (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  792. sizeof(DISK_CACHE_INFORMATION))
  793. ) {
  794. status = STATUS_BUFFER_TOO_SMALL;
  795. break;
  796. }
  797. if ((!getCaching) &&
  798. (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  799. sizeof(DISK_CACHE_INFORMATION))
  800. ) {
  801. status = STATUS_INFO_LENGTH_MISMATCH;
  802. break;
  803. }
  804. ASSERT(Irp->AssociatedIrp.SystemBuffer != NULL);
  805. if (getCaching) {
  806. status = DiskGetCacheInformation(fdoExtension, cacheInfo);
  807. if (NT_SUCCESS(status)) {
  808. Irp->IoStatus.Information = sizeof(DISK_CACHE_INFORMATION);
  809. }
  810. } else {
  811. status = DiskSetCacheInformation(fdoExtension, cacheInfo);
  812. //
  813. // Save away the user-defined override in our extension and the registry
  814. //
  815. if (cacheInfo->WriteCacheEnabled)
  816. {
  817. diskData->WriteCacheOverride = DiskWriteCacheEnable;
  818. }
  819. else
  820. {
  821. diskData->WriteCacheOverride = DiskWriteCacheDisable;
  822. }
  823. ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey, DiskDeviceUserWriteCacheSetting, diskData->WriteCacheOverride);
  824. DiskLogCacheInformation(fdoExtension, cacheInfo, status);
  825. }
  826. break;
  827. }
  828. case IOCTL_DISK_GET_CACHE_SETTING: {
  829. if (!commonExtension->IsFdo) {
  830. ClassReleaseRemoveLock(DeviceObject, Irp);
  831. ExFreePool(srb);
  832. SendToFdo(DeviceObject, Irp, status);
  833. return status;
  834. }
  835. status = DiskIoctlGetCacheSetting(fdoExtension, Irp);
  836. break;
  837. }
  838. case IOCTL_DISK_SET_CACHE_SETTING: {
  839. if (!commonExtension->IsFdo)
  840. {
  841. ClassReleaseRemoveLock(DeviceObject, Irp);
  842. ExFreePool(srb);
  843. SendToFdo(DeviceObject, Irp, status);
  844. return status;
  845. }
  846. status = DiskIoctlSetCacheSetting(fdoExtension, Irp);
  847. break;
  848. }
  849. case SMART_GET_VERSION: {
  850. PUCHAR buffer;
  851. PSRB_IO_CONTROL srbControl;
  852. PGETVERSIONINPARAMS versionParams;
  853. if(!commonExtension->IsFdo) {
  854. ClassReleaseRemoveLock(DeviceObject, Irp);
  855. ExFreePool(srb);
  856. SendToFdo(DeviceObject, Irp, status);
  857. return status;
  858. }
  859. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  860. sizeof(GETVERSIONINPARAMS)) {
  861. status = STATUS_BUFFER_TOO_SMALL;
  862. break;
  863. }
  864. srbControl = ExAllocatePoolWithTag(NonPagedPool,
  865. sizeof(SRB_IO_CONTROL) +
  866. sizeof(GETVERSIONINPARAMS),
  867. DISK_TAG_SMART);
  868. if (!srbControl) {
  869. status = STATUS_INSUFFICIENT_RESOURCES;
  870. break;
  871. }
  872. RtlZeroMemory(srbControl,
  873. sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS)
  874. );
  875. //
  876. // fill in srbControl fields
  877. //
  878. srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
  879. RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
  880. srbControl->Timeout = fdoExtension->TimeOutValue;
  881. srbControl->Length = sizeof(GETVERSIONINPARAMS);
  882. srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
  883. //
  884. // Point to the 'buffer' portion of the SRB_CONTROL
  885. //
  886. buffer = (PUCHAR)srbControl;
  887. (ULONG_PTR)buffer += srbControl->HeaderLength;
  888. //
  889. // Ensure correct target is set in the cmd parameters.
  890. //
  891. versionParams = (PGETVERSIONINPARAMS)buffer;
  892. versionParams->bIDEDeviceMap = diskData->ScsiAddress.TargetId;
  893. ClassSendDeviceIoControlSynchronous(
  894. IOCTL_SCSI_MINIPORT,
  895. commonExtension->LowerDeviceObject,
  896. srbControl,
  897. sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
  898. sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
  899. FALSE,
  900. &ioStatus);
  901. status = ioStatus.Status;
  902. //
  903. // If successful, copy the data received into the output buffer.
  904. // This should only fail in the event that the IDE driver is older
  905. // than this driver.
  906. //
  907. if (NT_SUCCESS(status)) {
  908. buffer = (PUCHAR)srbControl;
  909. (ULONG_PTR)buffer += srbControl->HeaderLength;
  910. RtlMoveMemory (Irp->AssociatedIrp.SystemBuffer, buffer,
  911. sizeof(GETVERSIONINPARAMS));
  912. Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
  913. }
  914. ExFreePool(srbControl);
  915. break;
  916. }
  917. case SMART_RCV_DRIVE_DATA: {
  918. PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
  919. ULONG controlCode = 0;
  920. PSRB_IO_CONTROL srbControl;
  921. PUCHAR buffer;
  922. if(!commonExtension->IsFdo) {
  923. ClassReleaseRemoveLock(DeviceObject, Irp);
  924. ExFreePool(srb);
  925. SendToFdo(DeviceObject, Irp, status);
  926. return status;
  927. }
  928. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  929. (sizeof(SENDCMDINPARAMS) - 1)) {
  930. status = STATUS_INVALID_PARAMETER;
  931. break;
  932. } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  933. (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
  934. status = STATUS_BUFFER_TOO_SMALL;
  935. break;
  936. }
  937. //
  938. // Create notification event object to be used to signal the
  939. // request completion.
  940. //
  941. KeInitializeEvent(&event, NotificationEvent, FALSE);
  942. //
  943. // use controlCode as a sort of 'STATUS_SUCCESS' to see if it's
  944. // a valid request type
  945. //
  946. if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
  947. length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
  948. controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
  949. } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
  950. switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
  951. case READ_ATTRIBUTES:
  952. controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
  953. length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
  954. break;
  955. case READ_THRESHOLDS:
  956. controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
  957. length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
  958. break;
  959. }
  960. }
  961. if (controlCode == 0) {
  962. status = STATUS_INVALID_PARAMETER;
  963. break;
  964. }
  965. srbControl = ExAllocatePoolWithTag(NonPagedPool,
  966. sizeof(SRB_IO_CONTROL) + length,
  967. DISK_TAG_SMART);
  968. if (!srbControl) {
  969. status = STATUS_INSUFFICIENT_RESOURCES;
  970. break;
  971. }
  972. //
  973. // fill in srbControl fields
  974. //
  975. srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
  976. RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
  977. srbControl->Timeout = fdoExtension->TimeOutValue;
  978. srbControl->Length = length;
  979. srbControl->ControlCode = controlCode;
  980. //
  981. // Point to the 'buffer' portion of the SRB_CONTROL
  982. //
  983. buffer = (PUCHAR)srbControl;
  984. (ULONG_PTR)buffer += srbControl->HeaderLength;
  985. //
  986. // Ensure correct target is set in the cmd parameters.
  987. //
  988. cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
  989. //
  990. // Copy the IOCTL parameters to the srb control buffer area.
  991. //
  992. RtlMoveMemory(buffer,
  993. Irp->AssociatedIrp.SystemBuffer,
  994. sizeof(SENDCMDINPARAMS) - 1);
  995. irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
  996. commonExtension->LowerDeviceObject,
  997. srbControl,
  998. sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
  999. srbControl,
  1000. sizeof(SRB_IO_CONTROL) + length,
  1001. FALSE,
  1002. &event,
  1003. &ioStatus);
  1004. if (irp2 == NULL) {
  1005. status = STATUS_INSUFFICIENT_RESOURCES;
  1006. ExFreePool(srbControl);
  1007. break;
  1008. }
  1009. //
  1010. // Call the port driver with the request and wait for it to complete.
  1011. //
  1012. status = IoCallDriver(commonExtension->LowerDeviceObject, irp2);
  1013. if (status == STATUS_PENDING) {
  1014. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1015. status = ioStatus.Status;
  1016. }
  1017. //
  1018. // Copy the data received into the output buffer. Since the status buffer
  1019. // contains error information also, always perform this copy. IO will will
  1020. // either pass this back to the app, or zero it, in case of error.
  1021. //
  1022. buffer = (PUCHAR)srbControl;
  1023. (ULONG_PTR)buffer += srbControl->HeaderLength;
  1024. if (NT_SUCCESS(status)) {
  1025. RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length - 1);
  1026. Irp->IoStatus.Information = length - 1;
  1027. } else {
  1028. RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
  1029. Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
  1030. }
  1031. ExFreePool(srbControl);
  1032. break;
  1033. }
  1034. case SMART_SEND_DRIVE_COMMAND: {
  1035. PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
  1036. PSRB_IO_CONTROL srbControl;
  1037. ULONG controlCode = 0;
  1038. PUCHAR buffer;
  1039. if(!commonExtension->IsFdo) {
  1040. ClassReleaseRemoveLock(DeviceObject, Irp);
  1041. ExFreePool(srb);
  1042. SendToFdo(DeviceObject, Irp, status);
  1043. return status;
  1044. }
  1045. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1046. (sizeof(SENDCMDINPARAMS) - 1)) {
  1047. status = STATUS_INVALID_PARAMETER;
  1048. break;
  1049. } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1050. (sizeof(SENDCMDOUTPARAMS) - 1)) {
  1051. status = STATUS_BUFFER_TOO_SMALL;
  1052. break;
  1053. }
  1054. //
  1055. // Create notification event object to be used to signal the
  1056. // request completion.
  1057. //
  1058. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1059. length = 0;
  1060. if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
  1061. switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
  1062. case ENABLE_SMART:
  1063. controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
  1064. break;
  1065. case DISABLE_SMART:
  1066. controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
  1067. break;
  1068. case RETURN_SMART_STATUS:
  1069. //
  1070. // Ensure bBuffer is at least 2 bytes (to hold the values of
  1071. // cylinderLow and cylinderHigh).
  1072. //
  1073. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1074. (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
  1075. /*
  1076. * Don't set controlCode; that'll cause us to break out below.
  1077. */
  1078. status = STATUS_BUFFER_TOO_SMALL;
  1079. break;
  1080. }
  1081. controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
  1082. length = sizeof(IDEREGS);
  1083. break;
  1084. case ENABLE_DISABLE_AUTOSAVE:
  1085. controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
  1086. break;
  1087. case SAVE_ATTRIBUTE_VALUES:
  1088. controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
  1089. break;
  1090. case EXECUTE_OFFLINE_DIAGS:
  1091. //
  1092. // Validate that this is an ok self test command
  1093. //
  1094. if (DiskIsValidSmartSelfTest(cmdInParameters->irDriveRegs.bSectorNumberReg))
  1095. {
  1096. controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
  1097. }
  1098. break;
  1099. case ENABLE_DISABLE_AUTO_OFFLINE:
  1100. controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE;
  1101. break;
  1102. default:
  1103. status = STATUS_INVALID_PARAMETER;
  1104. break;
  1105. }
  1106. }
  1107. else {
  1108. status = STATUS_INVALID_PARAMETER;
  1109. }
  1110. if (controlCode == 0) {
  1111. break;
  1112. }
  1113. length += max(sizeof(SENDCMDOUTPARAMS), sizeof(SENDCMDINPARAMS));
  1114. srbControl = ExAllocatePoolWithTag(NonPagedPool,
  1115. sizeof(SRB_IO_CONTROL) + length,
  1116. DISK_TAG_SMART);
  1117. if (!srbControl) {
  1118. status = STATUS_INSUFFICIENT_RESOURCES;
  1119. break;
  1120. }
  1121. //
  1122. // fill in srbControl fields
  1123. //
  1124. srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
  1125. RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
  1126. srbControl->Timeout = fdoExtension->TimeOutValue;
  1127. srbControl->Length = length;
  1128. srbControl->ControlCode = controlCode;
  1129. //
  1130. // Point to the 'buffer' portion of the SRB_CONTROL
  1131. //
  1132. buffer = (PUCHAR)srbControl;
  1133. (ULONG_PTR)buffer += srbControl->HeaderLength;
  1134. //
  1135. // Ensure correct target is set in the cmd parameters.
  1136. //
  1137. cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
  1138. //
  1139. // Copy the IOCTL parameters to the srb control buffer area.
  1140. //
  1141. RtlMoveMemory(buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
  1142. irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
  1143. commonExtension->LowerDeviceObject,
  1144. srbControl,
  1145. sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
  1146. srbControl,
  1147. sizeof(SRB_IO_CONTROL) + length,
  1148. FALSE,
  1149. &event,
  1150. &ioStatus);
  1151. if (irp2 == NULL) {
  1152. status = STATUS_INSUFFICIENT_RESOURCES;
  1153. ExFreePool(srbControl);
  1154. break;
  1155. }
  1156. //
  1157. // Call the port driver with the request and wait for it to complete.
  1158. //
  1159. status = IoCallDriver(commonExtension->LowerDeviceObject, irp2);
  1160. if (status == STATUS_PENDING) {
  1161. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1162. status = ioStatus.Status;
  1163. }
  1164. //
  1165. // Copy the data received into the output buffer. Since the status buffer
  1166. // contains error information also, always perform this copy. IO will will
  1167. // either pass this back to the app, or zero it, in case of error.
  1168. //
  1169. buffer = (PUCHAR)srbControl;
  1170. (ULONG_PTR)buffer += srbControl->HeaderLength;
  1171. //
  1172. // Update the return buffer size based on the sub-command.
  1173. //
  1174. if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
  1175. length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
  1176. } else {
  1177. length = sizeof(SENDCMDOUTPARAMS) - 1;
  1178. }
  1179. RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length);
  1180. Irp->IoStatus.Information = length;
  1181. ExFreePool(srbControl);
  1182. break;
  1183. }
  1184. case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {
  1185. PMODE_PARAMETER_BLOCK blockDescriptor;
  1186. ULONG modeLength;
  1187. ULONG retries = 4;
  1188. UCHAR densityCode = 0;
  1189. BOOLEAN writable = TRUE;
  1190. BOOLEAN mediaPresent = FALSE;
  1191. DebugPrint((3,
  1192. "Disk.DiskDeviceControl: GetMediaTypes\n"));
  1193. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1194. sizeof(GET_MEDIA_TYPES)) {
  1195. status = STATUS_BUFFER_TOO_SMALL;
  1196. break;
  1197. }
  1198. if(!commonExtension->IsFdo) {
  1199. ClassReleaseRemoveLock(DeviceObject, Irp);
  1200. ExFreePool(srb);
  1201. SendToFdo(DeviceObject, Irp, status);
  1202. return status;
  1203. }
  1204. //
  1205. // Send a TUR to determine if media is present.
  1206. //
  1207. srb->CdbLength = 6;
  1208. cdb = (PCDB)srb->Cdb;
  1209. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  1210. //
  1211. // Set timeout value.
  1212. //
  1213. srb->TimeOutValue = fdoExtension->TimeOutValue;
  1214. status = ClassSendSrbSynchronous(DeviceObject,
  1215. srb,
  1216. NULL,
  1217. 0,
  1218. FALSE);
  1219. if (NT_SUCCESS(status)) {
  1220. mediaPresent = TRUE;
  1221. }
  1222. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  1223. //
  1224. // Allocate memory for mode header and block descriptor.
  1225. //
  1226. modeLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
  1227. modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1228. modeLength,
  1229. DISK_TAG_MODE_DATA);
  1230. if (modeData == NULL) {
  1231. status = STATUS_INSUFFICIENT_RESOURCES;
  1232. break;
  1233. }
  1234. RtlZeroMemory(modeData, modeLength);
  1235. //
  1236. // Build the MODE SENSE CDB.
  1237. //
  1238. srb->CdbLength = 6;
  1239. cdb = (PCDB)srb->Cdb;
  1240. //
  1241. // Set timeout value from device extension.
  1242. //
  1243. srb->TimeOutValue = fdoExtension->TimeOutValue;
  1244. //
  1245. // Page code of 0 will return header and block descriptor only.
  1246. //
  1247. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  1248. cdb->MODE_SENSE.PageCode = 0;
  1249. cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
  1250. Retry:
  1251. status = ClassSendSrbSynchronous(DeviceObject,
  1252. srb,
  1253. modeData,
  1254. modeLength,
  1255. FALSE);
  1256. if (status == STATUS_VERIFY_REQUIRED) {
  1257. if (retries--) {
  1258. //
  1259. // Retry request.
  1260. //
  1261. goto Retry;
  1262. }
  1263. } else if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  1264. status = STATUS_SUCCESS;
  1265. }
  1266. if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) {
  1267. //
  1268. // Get the block descriptor.
  1269. //
  1270. if (modeData->BlockDescriptorLength != 0)
  1271. {
  1272. blockDescriptor = (PMODE_PARAMETER_BLOCK)modeData;
  1273. (ULONG_PTR)blockDescriptor += sizeof(MODE_PARAMETER_HEADER);
  1274. densityCode = blockDescriptor->DensityCode;
  1275. }
  1276. if (TEST_FLAG(modeData->DeviceSpecificParameter,
  1277. MODE_DSP_WRITE_PROTECT)) {
  1278. writable = FALSE;
  1279. }
  1280. status = DiskDetermineMediaTypes(DeviceObject,
  1281. Irp,
  1282. modeData->MediumType,
  1283. densityCode,
  1284. mediaPresent,
  1285. writable);
  1286. //
  1287. // If the buffer was too small, DetermineMediaTypes updated the status and information and the request will fail.
  1288. //
  1289. } else {
  1290. DebugPrint((1,
  1291. "DiskDeviceControl: Mode sense for header/bd failed. %lx\n",
  1292. status));
  1293. }
  1294. ExFreePool(modeData);
  1295. break;
  1296. }
  1297. case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
  1298. DebugPrint((2, "IOCTL_DISK_GET_DRIVE_GEOMETRY to device %p through irp %p\n",
  1299. DeviceObject, Irp));
  1300. DebugPrint((2, "Device is a%s.\n",
  1301. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1302. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1303. sizeof(DISK_GEOMETRY)) {
  1304. status = STATUS_BUFFER_TOO_SMALL;
  1305. break;
  1306. }
  1307. if(!commonExtension->IsFdo) {
  1308. //
  1309. // Pdo should issue this request to the lower device object
  1310. //
  1311. ClassReleaseRemoveLock(DeviceObject, Irp);
  1312. ExFreePool(srb);
  1313. SendToFdo(DeviceObject, Irp, status);
  1314. return status;
  1315. }
  1316. if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
  1317. //
  1318. // Issue ReadCapacity to update device extension
  1319. // with information for current media.
  1320. //
  1321. status = DiskReadDriveCapacity(
  1322. commonExtension->PartitionZeroExtension->DeviceObject);
  1323. //
  1324. // Note whether the drive is ready.
  1325. //
  1326. diskData->ReadyStatus = status;
  1327. if (!NT_SUCCESS(status)) {
  1328. break;
  1329. }
  1330. }
  1331. //
  1332. // Copy drive geometry information from device extension.
  1333. //
  1334. RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
  1335. &(fdoExtension->DiskGeometry),
  1336. sizeof(DISK_GEOMETRY));
  1337. status = STATUS_SUCCESS;
  1338. Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
  1339. break;
  1340. }
  1341. case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: {
  1342. DebugPrint((1, "IOCTL_DISK_GET_DRIVE_GEOMETRY_EX to device %p through irp %p\n",
  1343. DeviceObject, Irp));
  1344. DebugPrint((1, "Device Is a%s.\n",
  1345. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1346. if (!commonExtension->IsFdo) {
  1347. //
  1348. // Pdo should issue this request to the lower device object
  1349. //
  1350. ClassReleaseRemoveLock (DeviceObject, Irp);
  1351. ExFreePool (srb);
  1352. SendToFdo (DeviceObject, Irp, status);
  1353. return status;
  1354. } else {
  1355. status = DiskIoctlGetDriveGeometryEx( DeviceObject, Irp );
  1356. }
  1357. break;
  1358. }
  1359. case IOCTL_STORAGE_PREDICT_FAILURE : {
  1360. PSTORAGE_PREDICT_FAILURE checkFailure;
  1361. STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
  1362. DebugPrint((2, "IOCTL_STORAGE_PREDICT_FAILURE to device %p through irp %p\n",
  1363. DeviceObject, Irp));
  1364. DebugPrint((2, "Device is a%s.\n",
  1365. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1366. checkFailure = (PSTORAGE_PREDICT_FAILURE)Irp->AssociatedIrp.SystemBuffer;
  1367. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1368. sizeof(STORAGE_PREDICT_FAILURE)) {
  1369. status = STATUS_BUFFER_TOO_SMALL;
  1370. break;
  1371. }
  1372. if(!commonExtension->IsFdo) {
  1373. //
  1374. // Pdo should issue this request to the lower device object
  1375. //
  1376. ClassReleaseRemoveLock(DeviceObject, Irp);
  1377. ExFreePool(srb);
  1378. SendToFdo(DeviceObject, Irp, status);
  1379. return status;
  1380. }
  1381. //
  1382. // See if the disk is predicting failure
  1383. //
  1384. if (diskData->FailurePredictionCapability == FailurePredictionSense) {
  1385. ULONG readBufferSize;
  1386. PUCHAR readBuffer;
  1387. PIRP readIrp;
  1388. PDEVICE_OBJECT topOfStack;
  1389. checkFailure->PredictFailure = 0;
  1390. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1391. topOfStack = IoGetAttachedDeviceReference(DeviceObject);
  1392. //
  1393. // SCSI disks need to have a read sent down to provoke any
  1394. // failures to be reported.
  1395. //
  1396. // Issue a normal read operation. The error-handling code in
  1397. // classpnp will take care of a failure prediction by logging the
  1398. // correct event.
  1399. //
  1400. readBufferSize = fdoExtension->DiskGeometry.BytesPerSector;
  1401. readBuffer = ExAllocatePoolWithTag(NonPagedPool,
  1402. readBufferSize,
  1403. DISK_TAG_SMART);
  1404. if (readBuffer != NULL) {
  1405. LARGE_INTEGER offset;
  1406. offset.QuadPart = 0;
  1407. readIrp = IoBuildSynchronousFsdRequest(
  1408. IRP_MJ_READ,
  1409. topOfStack,
  1410. readBuffer,
  1411. readBufferSize,
  1412. &offset,
  1413. &event,
  1414. &ioStatus);
  1415. if (readIrp != NULL) {
  1416. status = IoCallDriver(topOfStack, readIrp);
  1417. if (status == STATUS_PENDING) {
  1418. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1419. status = ioStatus.Status;
  1420. }
  1421. }
  1422. else
  1423. {
  1424. status = STATUS_INSUFFICIENT_RESOURCES;
  1425. }
  1426. ExFreePool(readBuffer);
  1427. }
  1428. else
  1429. {
  1430. status = STATUS_INSUFFICIENT_RESOURCES;
  1431. }
  1432. ObDereferenceObject(topOfStack);
  1433. }
  1434. if ((diskData->FailurePredictionCapability == FailurePredictionSmart) ||
  1435. (diskData->FailurePredictionCapability == FailurePredictionSense))
  1436. {
  1437. status = DiskReadFailurePredictStatus(fdoExtension,
  1438. &diskSmartStatus);
  1439. if (NT_SUCCESS(status))
  1440. {
  1441. status = DiskReadFailurePredictData(fdoExtension,
  1442. Irp->AssociatedIrp.SystemBuffer);
  1443. if (diskSmartStatus.PredictFailure)
  1444. {
  1445. checkFailure->PredictFailure = 1;
  1446. } else {
  1447. checkFailure->PredictFailure = 0;
  1448. }
  1449. Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE);
  1450. }
  1451. } else {
  1452. status = STATUS_INVALID_DEVICE_REQUEST;
  1453. }
  1454. break;
  1455. }
  1456. case IOCTL_DISK_VERIFY: {
  1457. PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
  1458. LARGE_INTEGER byteOffset;
  1459. DebugPrint((2, "IOCTL_DISK_VERIFY to device %p through irp %p\n",
  1460. DeviceObject, Irp));
  1461. DebugPrint((2, "Device is a%s.\n",
  1462. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1463. //
  1464. // Validate buffer length.
  1465. //
  1466. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1467. sizeof(VERIFY_INFORMATION)) {
  1468. status = STATUS_INFO_LENGTH_MISMATCH;
  1469. break;
  1470. }
  1471. //
  1472. // Add disk offset to starting sector.
  1473. //
  1474. byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart +
  1475. verifyInfo->StartingOffset.QuadPart;
  1476. if(!commonExtension->IsFdo) {
  1477. //
  1478. // Adjust the request and forward it down
  1479. //
  1480. verifyInfo->StartingOffset.QuadPart = byteOffset.QuadPart;
  1481. ClassReleaseRemoveLock(DeviceObject, Irp);
  1482. SendToFdo(DeviceObject, Irp, status);
  1483. ExFreePool(srb);
  1484. return status;
  1485. }
  1486. //
  1487. // Perform a bounds check on the sector range
  1488. //
  1489. if ((verifyInfo->StartingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
  1490. (verifyInfo->StartingOffset.QuadPart < 0))
  1491. {
  1492. status = STATUS_NONEXISTENT_SECTOR;
  1493. break;
  1494. }
  1495. else
  1496. {
  1497. ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart;
  1498. if ((ULONGLONG)verifyInfo->Length > bytesRemaining)
  1499. {
  1500. status = STATUS_NONEXISTENT_SECTOR;
  1501. break;
  1502. }
  1503. }
  1504. {
  1505. PDISK_VERIFY_WORKITEM_CONTEXT Context = NULL;
  1506. Context = ExAllocatePoolWithTag(NonPagedPool,
  1507. sizeof(DISK_VERIFY_WORKITEM_CONTEXT),
  1508. DISK_TAG_WI_CONTEXT);
  1509. if (Context)
  1510. {
  1511. Context->Irp = Irp;
  1512. Context->Srb = srb;
  1513. Context->WorkItem = IoAllocateWorkItem(DeviceObject);
  1514. if (Context->WorkItem)
  1515. {
  1516. IoMarkIrpPending(Irp);
  1517. IoQueueWorkItem(Context->WorkItem,
  1518. DiskIoctlVerify,
  1519. DelayedWorkQueue,
  1520. Context);
  1521. return STATUS_PENDING;
  1522. }
  1523. ExFreePool(Context);
  1524. }
  1525. status = STATUS_INSUFFICIENT_RESOURCES;
  1526. }
  1527. break;
  1528. }
  1529. case IOCTL_DISK_CREATE_DISK: {
  1530. if (!commonExtension->IsFdo) {
  1531. ClassReleaseRemoveLock(DeviceObject, Irp);
  1532. ExFreePool(srb);
  1533. SendToFdo(DeviceObject, Irp, status);
  1534. return status;
  1535. }
  1536. status = DiskIoctlCreateDisk (
  1537. DeviceObject,
  1538. Irp
  1539. );
  1540. //
  1541. // Notify everyone that the disk layout has changed
  1542. //
  1543. if (NT_SUCCESS(status))
  1544. {
  1545. TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
  1546. Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
  1547. Notification.Version = 1;
  1548. Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
  1549. Notification.FileObject = NULL;
  1550. Notification.NameBufferOffset = -1;
  1551. IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
  1552. &Notification,
  1553. NULL,
  1554. NULL);
  1555. }
  1556. break;
  1557. }
  1558. case IOCTL_DISK_GET_DRIVE_LAYOUT: {
  1559. DebugPrint((1, "IOCTL_DISK_GET_DRIVE_LAYOUT to device %p through irp %p\n",
  1560. DeviceObject, Irp));
  1561. DebugPrint((1, "Device is a%s.\n",
  1562. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1563. if (!commonExtension->IsFdo) {
  1564. ClassReleaseRemoveLock(DeviceObject, Irp);
  1565. ExFreePool(srb);
  1566. SendToFdo(DeviceObject, Irp, status);
  1567. return status;
  1568. }
  1569. status = DiskIoctlGetDriveLayout(
  1570. DeviceObject,
  1571. Irp);
  1572. break;
  1573. }
  1574. case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: {
  1575. DebugPrint((1, "IOCTL_DISK_GET_DRIVE_LAYOUT_EX to device %p through irp %p\n",
  1576. DeviceObject, Irp));
  1577. DebugPrint((1, "Device is a%s.\n",
  1578. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1579. if (!commonExtension->IsFdo) {
  1580. ClassReleaseRemoveLock(DeviceObject, Irp);
  1581. ExFreePool(srb);
  1582. SendToFdo(DeviceObject, Irp, status);
  1583. return status;
  1584. }
  1585. status = DiskIoctlGetDriveLayoutEx(
  1586. DeviceObject,
  1587. Irp);
  1588. break;
  1589. }
  1590. case IOCTL_DISK_SET_DRIVE_LAYOUT: {
  1591. DebugPrint((1, "IOCTL_DISK_SET_DRIVE_LAYOUT to device %p through irp %p\n",
  1592. DeviceObject, Irp));
  1593. DebugPrint((1, "Device is a%s.\n",
  1594. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1595. if(!commonExtension->IsFdo) {
  1596. ClassReleaseRemoveLock(DeviceObject, Irp);
  1597. ExFreePool(srb);
  1598. SendToFdo(DeviceObject, Irp, status);
  1599. return status;
  1600. }
  1601. status = DiskIoctlSetDriveLayout(DeviceObject, Irp);
  1602. //
  1603. // Notify everyone that the disk layout has changed
  1604. //
  1605. if (NT_SUCCESS(status))
  1606. {
  1607. TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
  1608. Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
  1609. Notification.Version = 1;
  1610. Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
  1611. Notification.FileObject = NULL;
  1612. Notification.NameBufferOffset = -1;
  1613. IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
  1614. &Notification,
  1615. NULL,
  1616. NULL);
  1617. }
  1618. break;
  1619. }
  1620. case IOCTL_DISK_SET_DRIVE_LAYOUT_EX: {
  1621. DebugPrint((1, "IOCTL_DISK_SET_DRIVE_LAYOUT_EX to device %p through irp %p\n",
  1622. DeviceObject, Irp));
  1623. DebugPrint((1, "Device is a%s.\n",
  1624. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1625. if (!commonExtension->IsFdo) {
  1626. ClassReleaseRemoveLock(DeviceObject, Irp);
  1627. ExFreePool(srb);
  1628. SendToFdo(DeviceObject, Irp, status);
  1629. return status;
  1630. }
  1631. status = DiskIoctlSetDriveLayoutEx(
  1632. DeviceObject,
  1633. Irp);
  1634. //
  1635. // Notify everyone that the disk layout has changed
  1636. //
  1637. if (NT_SUCCESS(status))
  1638. {
  1639. TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
  1640. Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
  1641. Notification.Version = 1;
  1642. Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
  1643. Notification.FileObject = NULL;
  1644. Notification.NameBufferOffset = -1;
  1645. IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
  1646. &Notification,
  1647. NULL,
  1648. NULL);
  1649. }
  1650. break;
  1651. }
  1652. case IOCTL_DISK_GET_PARTITION_INFO: {
  1653. DebugPrint((1, "IOCTL_DISK_GET_PARTITION_INFO to device %p through irp %p\n",
  1654. DeviceObject, Irp));
  1655. DebugPrint((1, "Device is a%s.\n",
  1656. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1657. status = DiskIoctlGetPartitionInfo(
  1658. DeviceObject,
  1659. Irp);
  1660. break;
  1661. }
  1662. case IOCTL_DISK_GET_PARTITION_INFO_EX: {
  1663. DebugPrint((1, "IOCTL_DISK_GET_PARTITION_INFO to device %p through irp %p\n",
  1664. DeviceObject, Irp));
  1665. DebugPrint((1, "Device is a%s.\n",
  1666. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1667. status = DiskIoctlGetPartitionInfoEx(
  1668. DeviceObject,
  1669. Irp);
  1670. break;
  1671. }
  1672. case IOCTL_DISK_GET_LENGTH_INFO: {
  1673. DebugPrint((1, "IOCTL_DISK_GET_LENGTH_INFO to device %p through irp %p\n",
  1674. DeviceObject, Irp));
  1675. DebugPrint((1, "Device is a%s.\n",
  1676. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1677. status = DiskIoctlGetLengthInfo(
  1678. DeviceObject,
  1679. Irp);
  1680. break;
  1681. }
  1682. case IOCTL_DISK_SET_PARTITION_INFO: {
  1683. DebugPrint((1, "IOCTL_DISK_SET_PARTITION_INFO to device %p through irp %p\n",
  1684. DeviceObject, Irp));
  1685. DebugPrint((1, "Device is a%s.\n",
  1686. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1687. status = DiskIoctlSetPartitionInfo (
  1688. DeviceObject,
  1689. Irp);
  1690. //
  1691. // Notify everyone that the disk layout has changed
  1692. //
  1693. if (NT_SUCCESS(status))
  1694. {
  1695. TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
  1696. Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
  1697. Notification.Version = 1;
  1698. Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
  1699. Notification.FileObject = NULL;
  1700. Notification.NameBufferOffset = -1;
  1701. //
  1702. // We can safely assume that we are in the context of a PDO
  1703. //
  1704. IoReportTargetDeviceChangeAsynchronous((commonExtension->PartitionZeroExtension)->LowerPdo,
  1705. &Notification,
  1706. NULL,
  1707. NULL);
  1708. }
  1709. break;
  1710. }
  1711. case IOCTL_DISK_SET_PARTITION_INFO_EX: {
  1712. DebugPrint((1, "IOCTL_DISK_SET_PARTITION_INFO_EX to device %p through irp %p\n",
  1713. DeviceObject, Irp));
  1714. DebugPrint((1, "Device is a%s.\n",
  1715. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1716. status = DiskIoctlSetPartitionInfoEx(
  1717. DeviceObject,
  1718. Irp);
  1719. //
  1720. // Notify everyone that the disk layout has changed
  1721. //
  1722. if (NT_SUCCESS(status))
  1723. {
  1724. TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
  1725. Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
  1726. Notification.Version = 1;
  1727. Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
  1728. Notification.FileObject = NULL;
  1729. Notification.NameBufferOffset = -1;
  1730. //
  1731. // We can safely assume that we are in the context of a PDO
  1732. //
  1733. IoReportTargetDeviceChangeAsynchronous((commonExtension->PartitionZeroExtension)->LowerPdo,
  1734. &Notification,
  1735. NULL,
  1736. NULL);
  1737. }
  1738. break;
  1739. }
  1740. case IOCTL_DISK_DELETE_DRIVE_LAYOUT: {
  1741. CREATE_DISK CreateDiskInfo = { 0 };
  1742. //
  1743. // Update the disk with new partition information.
  1744. //
  1745. DebugPrint((1, "IOCTL_DISK_DELETE_DRIVE_LAYOUT to device %p through irp %p\n",
  1746. DeviceObject, Irp));
  1747. DebugPrint((1, "Device is a%s.\n",
  1748. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1749. if(!commonExtension->IsFdo) {
  1750. ClassReleaseRemoveLock(DeviceObject, Irp);
  1751. ExFreePool(srb);
  1752. SendToFdo(DeviceObject, Irp, status);
  1753. return status;
  1754. }
  1755. DiskAcquirePartitioningLock(fdoExtension);
  1756. DiskInvalidatePartitionTable(fdoExtension, TRUE);
  1757. //
  1758. // IoCreateDisk called with a partition style of raw
  1759. // will remove any partition tables from the disk.
  1760. //
  1761. CreateDiskInfo.PartitionStyle = PARTITION_STYLE_RAW;
  1762. status = IoCreateDisk(
  1763. DeviceObject,
  1764. &CreateDiskInfo);
  1765. //
  1766. // Notify everyone that the disk layout has changed
  1767. //
  1768. if (NT_SUCCESS(status))
  1769. {
  1770. TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
  1771. Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
  1772. Notification.Version = 1;
  1773. Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
  1774. Notification.FileObject = NULL;
  1775. Notification.NameBufferOffset = -1;
  1776. IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
  1777. &Notification,
  1778. NULL,
  1779. NULL);
  1780. }
  1781. DiskReleasePartitioningLock(fdoExtension);
  1782. ClassInvalidateBusRelations(DeviceObject);
  1783. Irp->IoStatus.Status = status;
  1784. break;
  1785. }
  1786. case IOCTL_DISK_REASSIGN_BLOCKS: {
  1787. //
  1788. // Map defective blocks to new location on disk.
  1789. //
  1790. PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
  1791. ULONG bufferSize;
  1792. ULONG blockNumber;
  1793. ULONG blockCount;
  1794. DebugPrint((2, "IOCTL_DISK_REASSIGN_BLOCKS to device %p through irp %p\n",
  1795. DeviceObject, Irp));
  1796. DebugPrint((2, "Device is a%s.\n",
  1797. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1798. //
  1799. // Validate buffer length.
  1800. //
  1801. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1802. sizeof(REASSIGN_BLOCKS)) {
  1803. status = STATUS_INFO_LENGTH_MISMATCH;
  1804. break;
  1805. }
  1806. bufferSize = sizeof(REASSIGN_BLOCKS) +
  1807. ((badBlocks->Count - 1) * sizeof(ULONG));
  1808. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  1809. bufferSize) {
  1810. status = STATUS_INFO_LENGTH_MISMATCH;
  1811. break;
  1812. }
  1813. //
  1814. // Send to FDO
  1815. //
  1816. if(!commonExtension->IsFdo) {
  1817. ClassReleaseRemoveLock(DeviceObject, Irp);
  1818. ExFreePool(srb);
  1819. SendToFdo(DeviceObject, Irp, status);
  1820. return status;
  1821. }
  1822. //
  1823. // Build the data buffer to be transferred in the input buffer.
  1824. // The format of the data to the device is:
  1825. //
  1826. // 2 bytes Reserved
  1827. // 2 bytes Length
  1828. // x * 4 btyes Block Address
  1829. //
  1830. // All values are big endian.
  1831. //
  1832. badBlocks->Reserved = 0;
  1833. blockCount = badBlocks->Count;
  1834. //
  1835. // Convert # of entries to # of bytes.
  1836. //
  1837. blockCount *= 4;
  1838. badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
  1839. badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
  1840. //
  1841. // Convert back to number of entries.
  1842. //
  1843. blockCount /= 4;
  1844. for (; blockCount > 0; blockCount--) {
  1845. blockNumber = badBlocks->BlockNumber[blockCount-1];
  1846. REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
  1847. (PFOUR_BYTE) &blockNumber);
  1848. }
  1849. srb->CdbLength = 6;
  1850. cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
  1851. //
  1852. // Set timeout value.
  1853. //
  1854. srb->TimeOutValue = fdoExtension->TimeOutValue;
  1855. status = ClassSendSrbSynchronous(DeviceObject,
  1856. srb,
  1857. badBlocks,
  1858. bufferSize,
  1859. TRUE);
  1860. break;
  1861. }
  1862. case IOCTL_DISK_IS_WRITABLE: {
  1863. //
  1864. // This routine mimics IOCTL_STORAGE_GET_MEDIA_TYPES_EX
  1865. //
  1866. ULONG modeLength;
  1867. ULONG retries = 4;
  1868. DebugPrint((3, "Disk.DiskDeviceControl: IOCTL_DISK_IS_WRITABLE\n"));
  1869. if (!commonExtension->IsFdo)
  1870. {
  1871. ClassReleaseRemoveLock(DeviceObject, Irp);
  1872. ExFreePool(srb);
  1873. SendToFdo(DeviceObject, Irp, status);
  1874. return status;
  1875. }
  1876. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  1877. //
  1878. // Allocate memory for a mode header and then some
  1879. // for port drivers that need to convert to MODE10
  1880. // or always return the MODE_PARAMETER_BLOCK (even
  1881. // when memory was not allocated for this purpose)
  1882. //
  1883. modeLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
  1884. modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1885. modeLength,
  1886. DISK_TAG_MODE_DATA);
  1887. if (modeData == NULL)
  1888. {
  1889. status = STATUS_INSUFFICIENT_RESOURCES;
  1890. break;
  1891. }
  1892. RtlZeroMemory(modeData, modeLength);
  1893. //
  1894. // Build the MODE SENSE CDB
  1895. //
  1896. srb->CdbLength = 6;
  1897. cdb = (PCDB)srb->Cdb;
  1898. //
  1899. // Set the timeout value from the device extension
  1900. //
  1901. srb->TimeOutValue = fdoExtension->TimeOutValue;
  1902. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  1903. cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL;
  1904. cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
  1905. while (retries != 0)
  1906. {
  1907. status = ClassSendSrbSynchronous(DeviceObject,
  1908. srb,
  1909. modeData,
  1910. modeLength,
  1911. FALSE);
  1912. if (status != STATUS_VERIFY_REQUIRED)
  1913. {
  1914. if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)
  1915. {
  1916. status = STATUS_SUCCESS;
  1917. }
  1918. break;
  1919. }
  1920. retries--;
  1921. }
  1922. if (NT_SUCCESS(status))
  1923. {
  1924. if (TEST_FLAG(modeData->DeviceSpecificParameter, MODE_DSP_WRITE_PROTECT))
  1925. {
  1926. status = STATUS_MEDIA_WRITE_PROTECTED;
  1927. }
  1928. }
  1929. ExFreePool(modeData);
  1930. break;
  1931. }
  1932. case IOCTL_DISK_INTERNAL_SET_VERIFY: {
  1933. //
  1934. // If the caller is kernel mode, set the verify bit.
  1935. //
  1936. if (Irp->RequestorMode == KernelMode) {
  1937. SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
  1938. }
  1939. DiskInvalidatePartitionTable(fdoExtension, FALSE);
  1940. status = STATUS_SUCCESS;
  1941. break;
  1942. }
  1943. case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: {
  1944. //
  1945. // If the caller is kernel mode, clear the verify bit.
  1946. //
  1947. if (Irp->RequestorMode == KernelMode) {
  1948. CLEAR_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
  1949. }
  1950. status = STATUS_SUCCESS;
  1951. break;
  1952. }
  1953. case IOCTL_DISK_UPDATE_DRIVE_SIZE: {
  1954. DebugPrint((2, "IOCTL_DISK_UPDATE_DRIVE_SIZE to device %p "
  1955. "through irp %p\n",
  1956. DeviceObject, Irp));
  1957. DebugPrint((2, "Device is a%s.\n",
  1958. commonExtension->IsFdo ? "n fdo" : " pdo"));
  1959. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1960. sizeof(DISK_GEOMETRY)) {
  1961. status = STATUS_BUFFER_TOO_SMALL;
  1962. break;
  1963. }
  1964. if(!commonExtension->IsFdo) {
  1965. //
  1966. // Pdo should issue this request to the lower device object.
  1967. //
  1968. ClassReleaseRemoveLock(DeviceObject, Irp);
  1969. ExFreePool(srb);
  1970. SendToFdo(DeviceObject, Irp, status);
  1971. return status;
  1972. }
  1973. DiskAcquirePartitioningLock(fdoExtension);
  1974. //
  1975. // Invalidate the cached partition table.
  1976. //
  1977. DiskInvalidatePartitionTable(fdoExtension, TRUE);
  1978. //
  1979. // At this point, commonExtension *is* the FDO extension. This
  1980. // should be the same as PartitionZeroExtension.
  1981. //
  1982. ASSERT(commonExtension ==
  1983. &(commonExtension->PartitionZeroExtension->CommonExtension));
  1984. //
  1985. // Issue ReadCapacity to update device extension with information
  1986. // for current media.
  1987. //
  1988. status = DiskReadDriveCapacity(DeviceObject);
  1989. //
  1990. // Note whether the drive is ready.
  1991. //
  1992. diskData->ReadyStatus = status;
  1993. //
  1994. // The disk's partition tables may be invalid after the drive geometry
  1995. // has been updated. The call to IoValidatePartitionTable (below) will
  1996. // fix it if this is the case.
  1997. //
  1998. if (NT_SUCCESS(status)) {
  1999. status = DiskVerifyPartitionTable (fdoExtension, TRUE);
  2000. }
  2001. if (NT_SUCCESS(status)) {
  2002. //
  2003. // Copy drive geometry information from the device extension.
  2004. //
  2005. RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
  2006. &(fdoExtension->DiskGeometry),
  2007. sizeof(DISK_GEOMETRY));
  2008. Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
  2009. status = STATUS_SUCCESS;
  2010. //
  2011. // Notify everyone that the disk layout may have changed
  2012. //
  2013. {
  2014. TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
  2015. Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
  2016. Notification.Version = 1;
  2017. Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
  2018. Notification.FileObject = NULL;
  2019. Notification.NameBufferOffset = -1;
  2020. IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
  2021. &Notification,
  2022. NULL,
  2023. NULL);
  2024. }
  2025. }
  2026. DiskReleasePartitioningLock(fdoExtension);
  2027. break;
  2028. }
  2029. case IOCTL_DISK_GROW_PARTITION: {
  2030. PDISK_GROW_PARTITION inputBuffer;
  2031. PCOMMON_DEVICE_EXTENSION pdoCommonExtension = &commonExtension->ChildList->CommonExtension;
  2032. LARGE_INTEGER bytesPerCylinder;
  2033. LARGE_INTEGER newStoppingOffset;
  2034. LARGE_INTEGER newPartitionLength;
  2035. PPHYSICAL_DEVICE_EXTENSION sibling;
  2036. PDRIVE_LAYOUT_INFORMATION_EX layoutInfo;
  2037. PPARTITION_INFORMATION_EX pdoPartition;
  2038. PPARTITION_INFORMATION_EX containerPartition;
  2039. ULONG partitionIndex;
  2040. DebugPrint((2, "IOCTL_DISK_GROW_PARTITION to device %p through "
  2041. "irp %p\n",
  2042. DeviceObject, Irp));
  2043. DebugPrint((2, "Device is a%s.\n",
  2044. commonExtension->IsFdo ? "n fdo" : " pdo"));
  2045. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  2046. sizeof(DISK_GROW_PARTITION)) {
  2047. status = STATUS_INFO_LENGTH_MISMATCH;
  2048. break;
  2049. }
  2050. if(!commonExtension->IsFdo) {
  2051. //
  2052. // Pdo should issue this request to the lower device object
  2053. //
  2054. ClassReleaseRemoveLock(DeviceObject, Irp);
  2055. ExFreePool(srb);
  2056. SendToFdo(DeviceObject, Irp, status);
  2057. return status;
  2058. }
  2059. DiskAcquirePartitioningLock(fdoExtension);
  2060. ClassAcquireChildLock(fdoExtension);
  2061. //
  2062. // At this point, commonExtension *is* the FDO extension. This should
  2063. // be the same as PartitionZeroExtension.
  2064. //
  2065. ASSERT(commonExtension ==
  2066. &(commonExtension->PartitionZeroExtension->CommonExtension));
  2067. //
  2068. // Get the input parameters
  2069. //
  2070. inputBuffer = (PDISK_GROW_PARTITION) Irp->AssociatedIrp.SystemBuffer;
  2071. ASSERT(inputBuffer);
  2072. //
  2073. // Make sure that we are actually being asked to grow the partition.
  2074. //
  2075. if(inputBuffer->BytesToGrow.QuadPart <= 0) {
  2076. status = STATUS_INVALID_PARAMETER;
  2077. ClassReleaseChildLock(fdoExtension);
  2078. DiskReleasePartitioningLock(fdoExtension);
  2079. break;
  2080. }
  2081. //
  2082. // Find the partition that matches the supplied number
  2083. //
  2084. while (pdoCommonExtension){
  2085. //
  2086. // Is this the partition we are searching for?
  2087. //
  2088. if(inputBuffer->PartitionNumber == pdoCommonExtension->PartitionNumber) {
  2089. break;
  2090. }
  2091. pdoCommonExtension = &pdoCommonExtension->ChildList->CommonExtension;
  2092. }
  2093. // Did we find the partition?
  2094. if (pdoCommonExtension == NULL){
  2095. status = STATUS_INVALID_PARAMETER;
  2096. ClassReleaseChildLock(fdoExtension);
  2097. DiskReleasePartitioningLock(fdoExtension);
  2098. break;
  2099. }
  2100. //
  2101. // Compute the new values for the partition to grow.
  2102. //
  2103. newPartitionLength.QuadPart =
  2104. (pdoCommonExtension->PartitionLength.QuadPart +
  2105. inputBuffer->BytesToGrow.QuadPart);
  2106. newStoppingOffset.QuadPart =
  2107. (pdoCommonExtension->StartingOffset.QuadPart +
  2108. newPartitionLength.QuadPart - 1);
  2109. //
  2110. // The below alignment requirement only applies to the MBR layout
  2111. //
  2112. if (diskData->PartitionStyle == PARTITION_STYLE_MBR) {
  2113. //
  2114. // Test the partition alignment before getting to involved.
  2115. //
  2116. // NOTE:
  2117. // All partition stopping offsets should be one byte less
  2118. // than a cylinder boundary offset. Also, all first partitions
  2119. // (within partition0 and within an extended partition) start
  2120. // on the second track while all other partitions start on a
  2121. // cylinder boundary.
  2122. //
  2123. bytesPerCylinder.QuadPart =
  2124. ((LONGLONG) fdoExtension->DiskGeometry.TracksPerCylinder *
  2125. (LONGLONG) fdoExtension->DiskGeometry.SectorsPerTrack *
  2126. (LONGLONG) fdoExtension->DiskGeometry.BytesPerSector);
  2127. // Temporarily adjust up to cylinder boundary.
  2128. newStoppingOffset.QuadPart += 1;
  2129. if(newStoppingOffset.QuadPart % bytesPerCylinder.QuadPart) {
  2130. // Adjust the length first...
  2131. newPartitionLength.QuadPart -=
  2132. (newStoppingOffset.QuadPart % bytesPerCylinder.QuadPart);
  2133. // ...and then the stopping offset.
  2134. newStoppingOffset.QuadPart -=
  2135. (newStoppingOffset.QuadPart % bytesPerCylinder.QuadPart);
  2136. DebugPrint((2, "IOCTL_DISK_GROW_PARTITION: "
  2137. "Adjusted the requested partition size to cylinder boundary"));
  2138. }
  2139. // Restore to one byte less than a cylinder boundary.
  2140. newStoppingOffset.QuadPart -= 1;
  2141. }
  2142. //
  2143. // Will the new partition fit within Partition0?
  2144. // Remember: commonExtension == &PartitionZeroExtension->CommonExtension
  2145. //
  2146. if(newStoppingOffset.QuadPart >
  2147. (commonExtension->StartingOffset.QuadPart +
  2148. commonExtension->PartitionLength.QuadPart - 1)) {
  2149. //
  2150. // The new partition falls outside Partition0
  2151. //
  2152. status = STATUS_UNSUCCESSFUL;
  2153. ClassReleaseChildLock(fdoExtension);
  2154. DiskReleasePartitioningLock(fdoExtension);
  2155. break;
  2156. }
  2157. //
  2158. // Search for any partition that will conflict with the new partition.
  2159. // This is done before testing for any containing partitions to
  2160. // simplify the container handling.
  2161. //
  2162. sibling = commonExtension->ChildList;
  2163. while(sibling != NULL) {
  2164. LARGE_INTEGER sibStoppingOffset;
  2165. PCOMMON_DEVICE_EXTENSION siblingExtension;
  2166. siblingExtension = &(sibling->CommonExtension);
  2167. ASSERT( siblingExtension );
  2168. sibStoppingOffset.QuadPart =
  2169. (siblingExtension->StartingOffset.QuadPart +
  2170. siblingExtension->PartitionLength.QuadPart - 1);
  2171. //
  2172. // Only check the siblings that start beyond the new partition
  2173. // starting offset. Also, assume that since the starting offset
  2174. // has not changed, it will not be in conflict with any other
  2175. // partitions; only the new stopping offset needs to be tested.
  2176. //
  2177. if((inputBuffer->PartitionNumber !=
  2178. siblingExtension->PartitionNumber) &&
  2179. (siblingExtension->StartingOffset.QuadPart >
  2180. pdoCommonExtension->StartingOffset.QuadPart) &&
  2181. (newStoppingOffset.QuadPart >=
  2182. siblingExtension->StartingOffset.QuadPart)) {
  2183. //
  2184. // We have a conflict; bail out leaving pdoSibling set.
  2185. //
  2186. break;
  2187. }
  2188. sibling = siblingExtension->ChildList;
  2189. }
  2190. //
  2191. // If there is a sibling that conflicts, it will be in pdoSibling; there
  2192. // could be more than one, but this is the first one detected.
  2193. //
  2194. if(sibling != NULL) {
  2195. //
  2196. // Report the conflict and abort the grow request.
  2197. //
  2198. status = STATUS_UNSUCCESSFUL;
  2199. ClassReleaseChildLock(fdoExtension);
  2200. DiskReleasePartitioningLock(fdoExtension);
  2201. break;
  2202. }
  2203. //
  2204. // Read the partition table. Since we're planning on modifying it
  2205. // we should bypass the cache.
  2206. //
  2207. status = DiskReadPartitionTableEx(fdoExtension, TRUE, &layoutInfo );
  2208. if( !NT_SUCCESS(status) ) {
  2209. ClassReleaseChildLock(fdoExtension);
  2210. DiskReleasePartitioningLock(fdoExtension);
  2211. break;
  2212. }
  2213. ASSERT( layoutInfo );
  2214. //
  2215. // Search the layout for the partition that matches the
  2216. // PDO in hand.
  2217. //
  2218. pdoPartition =
  2219. DiskPdoFindPartitionEntry(
  2220. (PPHYSICAL_DEVICE_EXTENSION)pdoCommonExtension,
  2221. layoutInfo);
  2222. if(pdoPartition == NULL) {
  2223. // Looks like something is wrong interally-- error ok?
  2224. status = STATUS_DRIVER_INTERNAL_ERROR;
  2225. layoutInfo = NULL;
  2226. ClassReleaseChildLock(fdoExtension);
  2227. DiskReleasePartitioningLock(fdoExtension);
  2228. break;
  2229. }
  2230. //
  2231. // Search the on-disk partition information to find the root containing
  2232. // partition (top-to-bottom).
  2233. //
  2234. // Remember: commonExtension == &PartitionZeroExtension->CommonExtension
  2235. //
  2236. //
  2237. // All affected containers will have a new stopping offset
  2238. // that is equal to the new partition (logical drive)
  2239. // stopping offset. Walk the layout information from
  2240. // bottom-to-top searching for logical drive containers and
  2241. // propagating the change.
  2242. //
  2243. containerPartition =
  2244. DiskFindContainingPartition(
  2245. layoutInfo,
  2246. pdoPartition,
  2247. FALSE);
  2248. //
  2249. // This loop should only execute at most 2 times; once for
  2250. // the logical drive container, and once for the root
  2251. // extended partition container. If the growing partition
  2252. // is not contained, the loop does not run.
  2253. //
  2254. while(containerPartition != NULL) {
  2255. LARGE_INTEGER containerStoppingOffset;
  2256. PPARTITION_INFORMATION_EX nextContainerPartition;
  2257. //
  2258. // Plan ahead and get the container's container before
  2259. // modifing the current size.
  2260. //
  2261. nextContainerPartition =
  2262. DiskFindContainingPartition(
  2263. layoutInfo,
  2264. containerPartition,
  2265. FALSE);
  2266. //
  2267. // Figure out where the current container ends and test
  2268. // to see if it already encompasses the containee.
  2269. //
  2270. containerStoppingOffset.QuadPart =
  2271. (containerPartition->StartingOffset.QuadPart +
  2272. containerPartition->PartitionLength.QuadPart - 1);
  2273. if(newStoppingOffset.QuadPart <=
  2274. containerStoppingOffset.QuadPart) {
  2275. //
  2276. // No need to continue since this container fits
  2277. //
  2278. break;
  2279. }
  2280. //
  2281. // Adjust the container to have a stopping offset that
  2282. // matches the grown partition stopping offset.
  2283. //
  2284. containerPartition->PartitionLength.QuadPart =
  2285. newStoppingOffset.QuadPart + 1 -
  2286. containerPartition->StartingOffset.QuadPart;
  2287. containerPartition->RewritePartition = TRUE;
  2288. // Continue with the next container
  2289. containerPartition = nextContainerPartition;
  2290. }
  2291. //
  2292. // Wait until after searching the containers to update the
  2293. // partition size.
  2294. //
  2295. pdoPartition->PartitionLength.QuadPart =
  2296. newPartitionLength.QuadPart;
  2297. pdoPartition->RewritePartition = TRUE;
  2298. //
  2299. // Commit the changes to disk
  2300. //
  2301. status = DiskWritePartitionTableEx(fdoExtension, layoutInfo );
  2302. if( NT_SUCCESS(status) ) {
  2303. //
  2304. // Everything looks good so commit the new length to the
  2305. // PDO. This has to be done carefully. We may potentially
  2306. // grow the partition in three steps:
  2307. // * increase the high-word of the partition length
  2308. // to be just below the new size - the high word should
  2309. // be greater than or equal to the current length.
  2310. //
  2311. // * change the low-word of the partition length to the
  2312. // new value - this value may potentially be lower than
  2313. // the current value (if the high part was changed which
  2314. // is why we changed that first)
  2315. //
  2316. // * change the high part to the correct value.
  2317. //
  2318. if(newPartitionLength.HighPart >
  2319. pdoCommonExtension->PartitionLength.HighPart) {
  2320. //
  2321. // Swap in one less than the high word.
  2322. //
  2323. InterlockedExchange(
  2324. &pdoCommonExtension->PartitionLength.HighPart,
  2325. (newPartitionLength.HighPart - 1));
  2326. }
  2327. //
  2328. // Swap in the low part.
  2329. //
  2330. InterlockedExchange(
  2331. &(pdoCommonExtension->PartitionLength.LowPart),
  2332. newPartitionLength.LowPart);
  2333. if(newPartitionLength.HighPart !=
  2334. pdoCommonExtension->PartitionLength.HighPart) {
  2335. //
  2336. // Swap in one less than the high word.
  2337. //
  2338. InterlockedExchange(
  2339. &(pdoCommonExtension->PartitionLength.HighPart),
  2340. newPartitionLength.HighPart);
  2341. }
  2342. //
  2343. // Notify everyone that the disk layout has changed
  2344. //
  2345. {
  2346. TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
  2347. Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
  2348. Notification.Version = 1;
  2349. Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
  2350. Notification.FileObject = NULL;
  2351. Notification.NameBufferOffset = -1;
  2352. IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
  2353. &Notification,
  2354. NULL,
  2355. NULL);
  2356. }
  2357. }
  2358. //
  2359. // Invalidate and free the cached partition table.
  2360. //
  2361. DiskInvalidatePartitionTable(fdoExtension, TRUE);
  2362. //
  2363. // Free the partition buffer regardless of the status
  2364. //
  2365. ClassReleaseChildLock(fdoExtension);
  2366. DiskReleasePartitioningLock(fdoExtension);
  2367. break;
  2368. }
  2369. case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
  2370. case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN:
  2371. {
  2372. if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
  2373. {
  2374. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VOLUME_DISK_EXTENTS))
  2375. {
  2376. status = STATUS_BUFFER_TOO_SMALL;
  2377. break;
  2378. }
  2379. status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
  2380. //
  2381. // Note whether the drive is ready.
  2382. //
  2383. diskData->ReadyStatus = status;
  2384. if (NT_SUCCESS(status))
  2385. {
  2386. PVOLUME_DISK_EXTENTS pVolExt = (PVOLUME_DISK_EXTENTS)Irp->AssociatedIrp.SystemBuffer;
  2387. pVolExt->NumberOfDiskExtents = 1;
  2388. pVolExt->Extents[0].DiskNumber = commonExtension->PartitionZeroExtension->DeviceNumber;
  2389. pVolExt->Extents[0].StartingOffset = commonExtension->StartingOffset;
  2390. pVolExt->Extents[0].ExtentLength = commonExtension->PartitionLength;
  2391. Irp->IoStatus.Information = sizeof(VOLUME_DISK_EXTENTS);
  2392. }
  2393. }
  2394. else
  2395. {
  2396. status = STATUS_INVALID_DEVICE_REQUEST;
  2397. }
  2398. break;
  2399. }
  2400. case IOCTL_DISK_UPDATE_PROPERTIES: {
  2401. if (!commonExtension->IsFdo)
  2402. {
  2403. ClassReleaseRemoveLock(DeviceObject, Irp);
  2404. ExFreePool(srb);
  2405. SendToFdo(DeviceObject,Irp,status);
  2406. return status;
  2407. }
  2408. //
  2409. // Invalidate the partition table and re-enumerate the device.
  2410. //
  2411. if (DiskInvalidatePartitionTable(fdoExtension, FALSE))
  2412. {
  2413. IoInvalidateDeviceRelations(fdoExtension->LowerPdo, BusRelations);
  2414. //
  2415. // Notify everyone that the disk layout may have changed
  2416. //
  2417. {
  2418. TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
  2419. Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
  2420. Notification.Version = 1;
  2421. Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
  2422. Notification.FileObject = NULL;
  2423. Notification.NameBufferOffset = -1;
  2424. IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
  2425. &Notification,
  2426. NULL,
  2427. NULL);
  2428. }
  2429. }
  2430. status = STATUS_SUCCESS;
  2431. break;
  2432. }
  2433. default: {
  2434. //
  2435. // Free the Srb, since it is not needed.
  2436. //
  2437. ExFreePool(srb);
  2438. //
  2439. // Pass the request to the common device control routine.
  2440. //
  2441. return(ClassDeviceControl(DeviceObject, Irp));
  2442. break;
  2443. }
  2444. } // end switch
  2445. Irp->IoStatus.Status = status;
  2446. if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
  2447. IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
  2448. }
  2449. ClassReleaseRemoveLock(DeviceObject, Irp);
  2450. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  2451. ExFreePool(srb);
  2452. return(status);
  2453. } // end DiskDeviceControl()
  2454. NTSTATUS
  2455. DiskShutdownFlush(
  2456. IN PDEVICE_OBJECT DeviceObject,
  2457. IN PIRP Irp
  2458. )
  2459. /*++
  2460. Routine Description:
  2461. This routine is the handler for shutdown and flush requests. It sends
  2462. down a synch cache command to the device if its cache is enabled. If
  2463. the request is a shutdown and the media is removable, it sends down
  2464. an unlock request
  2465. Finally, an SRB_FUNCTION_SHUTDOWN or SRB_FUNCTION_FLUSH is sent down
  2466. the stack
  2467. Arguments:
  2468. DeviceObject - The device object processing the request
  2469. Irp - The shutdown | flush request being serviced
  2470. Return Value:
  2471. STATUS_PENDING if successful, an error code otherwise
  2472. --*/
  2473. {
  2474. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  2475. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension;
  2476. PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData;
  2477. PIO_STACK_LOCATION irpStack;
  2478. NTSTATUS status = STATUS_SUCCESS;
  2479. PAGED_CODE();
  2480. //
  2481. // Send partition flush requests to the FDO
  2482. //
  2483. if(!commonExtension->IsFdo) {
  2484. PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject;
  2485. ClassReleaseRemoveLock(DeviceObject, Irp);
  2486. IoMarkIrpPending(Irp);
  2487. IoCopyCurrentIrpStackLocationToNext(Irp);
  2488. IoCallDriver(lowerDevice, Irp);
  2489. return STATUS_PENDING;
  2490. }
  2491. //
  2492. // Flush requests are combined and need to be handled in a special manner
  2493. //
  2494. irpStack = IoGetCurrentIrpStackLocation(Irp);
  2495. if (irpStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) {
  2496. KeWaitForMutexObject(&diskData->FlushContext.Mutex, Executive, KernelMode, FALSE, NULL);
  2497. //
  2498. // This request will most likely be completed asynchronously
  2499. //
  2500. IoMarkIrpPending(Irp);
  2501. //
  2502. // Look to see if a flush is in progress
  2503. //
  2504. if (diskData->FlushContext.CurrIrp != NULL) {
  2505. //
  2506. // There is an outstanding flush. Queue this
  2507. // request to the group that is next in line
  2508. //
  2509. if (diskData->FlushContext.NextIrp != NULL) {
  2510. #if DBG
  2511. diskData->FlushContext.DbgTagCount++;
  2512. #endif
  2513. InsertTailList(&diskData->FlushContext.NextList, &Irp->Tail.Overlay.ListEntry);
  2514. KeReleaseMutex(&diskData->FlushContext.Mutex, FALSE);
  2515. //
  2516. // This request will be completed by its representative
  2517. //
  2518. } else {
  2519. #if DBG
  2520. if (diskData->FlushContext.DbgTagCount < 64) {
  2521. diskData->FlushContext.DbgRefCount[diskData->FlushContext.DbgTagCount]++;
  2522. }
  2523. diskData->FlushContext.DbgSavCount += diskData->FlushContext.DbgTagCount;
  2524. diskData->FlushContext.DbgTagCount = 0;
  2525. #endif
  2526. diskData->FlushContext.NextIrp = Irp;
  2527. ASSERT(IsListEmpty(&diskData->FlushContext.NextList));
  2528. KeReleaseMutex(&diskData->FlushContext.Mutex, FALSE);
  2529. //
  2530. // Wait for the outstanding flush to complete
  2531. //
  2532. KeWaitForSingleObject(&diskData->FlushContext.Event, Executive, KernelMode, FALSE, NULL);
  2533. //
  2534. // Make this group the outstanding one and free up the next slot
  2535. //
  2536. KeWaitForMutexObject(&diskData->FlushContext.Mutex, Executive, KernelMode, FALSE, NULL);
  2537. ASSERT(IsListEmpty(&diskData->FlushContext.CurrList));
  2538. while (!IsListEmpty(&diskData->FlushContext.NextList)) {
  2539. PLIST_ENTRY listEntry = RemoveHeadList(&diskData->FlushContext.NextList);
  2540. InsertTailList(&diskData->FlushContext.CurrList, listEntry);
  2541. }
  2542. diskData->FlushContext.CurrIrp = diskData->FlushContext.NextIrp;
  2543. diskData->FlushContext.NextIrp = NULL;
  2544. KeReleaseMutex(&diskData->FlushContext.Mutex, FALSE);
  2545. //
  2546. // Send this request down to the device
  2547. //
  2548. DiskFlushDispatch(DeviceObject, &diskData->FlushContext);
  2549. }
  2550. } else {
  2551. diskData->FlushContext.CurrIrp = Irp;
  2552. ASSERT(IsListEmpty(&diskData->FlushContext.CurrList));
  2553. ASSERT(diskData->FlushContext.NextIrp == NULL);
  2554. ASSERT(IsListEmpty(&diskData->FlushContext.NextList));
  2555. KeReleaseMutex(&diskData->FlushContext.Mutex, FALSE);
  2556. //
  2557. // Send this request down to the device
  2558. //
  2559. DiskFlushDispatch(DeviceObject, &diskData->FlushContext);
  2560. }
  2561. } else {
  2562. //
  2563. // Allocate SCSI request block.
  2564. //
  2565. PSCSI_REQUEST_BLOCK srb = ExAllocatePoolWithTag(NonPagedPool,
  2566. sizeof(SCSI_REQUEST_BLOCK),
  2567. DISK_TAG_SRB);
  2568. if (srb == NULL) {
  2569. //
  2570. // Set the status and complete the request.
  2571. //
  2572. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2573. ClassReleaseRemoveLock(DeviceObject, Irp);
  2574. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  2575. return(STATUS_INSUFFICIENT_RESOURCES);
  2576. }
  2577. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  2578. //
  2579. // Write length to SRB.
  2580. //
  2581. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  2582. //
  2583. // Set timeout value and mark the request as not being a tagged request.
  2584. //
  2585. srb->TimeOutValue = fdoExtension->TimeOutValue * 4;
  2586. srb->QueueTag = SP_UNTAGGED;
  2587. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  2588. srb->SrbFlags = fdoExtension->SrbFlags;
  2589. //
  2590. // If the write cache is enabled then send a synchronize cache request.
  2591. //
  2592. if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE)) {
  2593. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  2594. srb->CdbLength = 10;
  2595. srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
  2596. status = ClassSendSrbSynchronous(DeviceObject,
  2597. srb,
  2598. NULL,
  2599. 0,
  2600. TRUE);
  2601. DebugPrint((1, "DiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status ));
  2602. }
  2603. //
  2604. // Unlock the device if it contains removable media
  2605. //
  2606. if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
  2607. {
  2608. PCDB cdb;
  2609. srb->CdbLength = 6;
  2610. cdb = (PVOID) srb->Cdb;
  2611. cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
  2612. cdb->MEDIA_REMOVAL.Prevent = FALSE;
  2613. //
  2614. // Set timeout value.
  2615. //
  2616. srb->TimeOutValue = fdoExtension->TimeOutValue;
  2617. status = ClassSendSrbSynchronous(DeviceObject,
  2618. srb,
  2619. NULL,
  2620. 0,
  2621. TRUE);
  2622. DebugPrint((1, "DiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
  2623. }
  2624. srb->CdbLength = 0;
  2625. //
  2626. // Save a few parameters in the current stack location.
  2627. //
  2628. srb->Function = SRB_FUNCTION_SHUTDOWN;
  2629. //
  2630. // Set the retry count to zero.
  2631. //
  2632. irpStack->Parameters.Others.Argument4 = (PVOID) 0;
  2633. //
  2634. // Set up IoCompletion routine address.
  2635. //
  2636. IoSetCompletionRoutine(Irp, ClassIoComplete, srb, TRUE, TRUE, TRUE);
  2637. //
  2638. // Get next stack location and
  2639. // set major function code.
  2640. //
  2641. irpStack = IoGetNextIrpStackLocation(Irp);
  2642. irpStack->MajorFunction = IRP_MJ_SCSI;
  2643. //
  2644. // Set up SRB for execute scsi request.
  2645. // Save SRB address in next stack for port driver.
  2646. //
  2647. irpStack->Parameters.Scsi.Srb = srb;
  2648. //
  2649. // Set up Irp Address.
  2650. //
  2651. srb->OriginalRequest = Irp;
  2652. //
  2653. // Call the port driver to process the request.
  2654. //
  2655. IoMarkIrpPending(Irp);
  2656. IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  2657. }
  2658. return STATUS_PENDING;
  2659. }
  2660. VOID
  2661. DiskFlushDispatch(
  2662. IN PDEVICE_OBJECT Fdo,
  2663. IN PDISK_GROUP_CONTEXT FlushContext
  2664. )
  2665. /*++
  2666. Routine Description:
  2667. This routine is the handler for flush requests. It sends down a synch
  2668. cache command to the device if its cache is enabled. This is followed
  2669. by an SRB_FUNCTION_FLUSH
  2670. Arguments:
  2671. Fdo - The device object processing the flush request
  2672. FlushContext - The flush group context
  2673. Return Value:
  2674. None
  2675. --*/
  2676. {
  2677. PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  2678. PSCSI_REQUEST_BLOCK srb = &FlushContext->Srb;
  2679. PIO_STACK_LOCATION irpSp = NULL;
  2680. PAGED_CODE();
  2681. ASSERT_FDO(Fdo);
  2682. //
  2683. // Fill in the srb fields appropriately
  2684. //
  2685. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  2686. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  2687. srb->TimeOutValue = fdoExt->TimeOutValue * 4;
  2688. srb->QueueTag = SP_UNTAGGED;
  2689. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  2690. srb->SrbFlags = fdoExt->SrbFlags;
  2691. //
  2692. // If write caching is enabled then send down a synchronize cache request
  2693. //
  2694. if (TEST_FLAG(fdoExt->DeviceFlags, DEV_WRITE_CACHE) && !TEST_FLAG(fdoExt->DeviceFlags, DEV_POWER_PROTECTED))
  2695. {
  2696. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  2697. srb->CdbLength = 10;
  2698. srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
  2699. ClassSendSrbSynchronous(Fdo, srb, NULL, 0, TRUE);
  2700. }
  2701. srb->Function = SRB_FUNCTION_FLUSH;
  2702. srb->CdbLength = 0;
  2703. srb->OriginalRequest = FlushContext->CurrIrp;
  2704. //
  2705. // Make sure that this srb does not get freed
  2706. //
  2707. SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT);
  2708. //
  2709. // Make sure that this request does not get retried
  2710. //
  2711. irpSp = IoGetCurrentIrpStackLocation(FlushContext->CurrIrp);
  2712. irpSp->Parameters.Others.Argument4 = (PVOID) 0;
  2713. //
  2714. // Fill in the irp fields appropriately
  2715. //
  2716. irpSp = IoGetNextIrpStackLocation(FlushContext->CurrIrp);
  2717. irpSp->MajorFunction = IRP_MJ_SCSI;
  2718. irpSp->Parameters.Scsi.Srb = srb;
  2719. IoSetCompletionRoutine(FlushContext->CurrIrp, DiskFlushComplete, FlushContext, TRUE, TRUE, TRUE);
  2720. //
  2721. // Send down the flush request
  2722. //
  2723. IoCallDriver(((PCOMMON_DEVICE_EXTENSION)fdoExt)->LowerDeviceObject, FlushContext->CurrIrp);
  2724. }
  2725. NTSTATUS
  2726. DiskFlushComplete(
  2727. IN PDEVICE_OBJECT Fdo,
  2728. IN PIRP Irp,
  2729. IN PVOID Context
  2730. )
  2731. /*++
  2732. Routine Description:
  2733. This completion routine is a wrapper around ClassIoComplete. It
  2734. will complete all the flush requests that are tagged to it, set
  2735. an event to signal the next group to proceed and return
  2736. Arguments:
  2737. Fdo - The device object which requested the completion routine
  2738. Irp - The irp that is being completed
  2739. Context - The flush group context
  2740. Return Value:
  2741. STATUS_SUCCESS if successful, an error code otherwise
  2742. --*/
  2743. {
  2744. PDISK_GROUP_CONTEXT FlushContext = Context;
  2745. NTSTATUS status;
  2746. DebugPrint((ClassDebugInfo, "DiskFlushComplete: %p %p %p\n", Fdo, Irp, FlushContext));
  2747. //
  2748. // Make sure everything is in order
  2749. //
  2750. ASSERT(Irp == FlushContext->CurrIrp);
  2751. status = ClassIoComplete(Fdo, Irp, &FlushContext->Srb);
  2752. //
  2753. // Make sure that ClassIoComplete did not decide to retry this request
  2754. //
  2755. ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED);
  2756. //
  2757. // Complete the flush requests tagged to this one
  2758. //
  2759. while (!IsListEmpty(&FlushContext->CurrList)) {
  2760. PLIST_ENTRY listEntry = RemoveHeadList(&FlushContext->CurrList);
  2761. PIRP tempIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  2762. InitializeListHead(&tempIrp->Tail.Overlay.ListEntry);
  2763. tempIrp->IoStatus = Irp->IoStatus;
  2764. ClassReleaseRemoveLock(Fdo, tempIrp);
  2765. ClassCompleteRequest(Fdo, tempIrp, IO_NO_INCREMENT);
  2766. }
  2767. //
  2768. // Notify the next group's representative that it may go ahead now
  2769. //
  2770. KeSetEvent(&FlushContext->Event, IO_NO_INCREMENT, FALSE);
  2771. return status;
  2772. }
  2773. NTSTATUS
  2774. DiskModeSelect(
  2775. IN PDEVICE_OBJECT Fdo,
  2776. IN PCHAR ModeSelectBuffer,
  2777. IN ULONG Length,
  2778. IN BOOLEAN SavePage
  2779. )
  2780. /*++
  2781. Routine Description:
  2782. This routine sends a mode select command.
  2783. Arguments:
  2784. DeviceObject - Supplies the device object associated with this request.
  2785. ModeSelectBuffer - Supplies a buffer containing the page data.
  2786. Length - Supplies the length in bytes of the mode select buffer.
  2787. SavePage - Indicates that parameters should be written to disk.
  2788. Return Value:
  2789. Length of the transferred data is returned.
  2790. --*/
  2791. {
  2792. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2793. PCDB cdb;
  2794. SCSI_REQUEST_BLOCK srb = {0};
  2795. ULONG retries = 1;
  2796. ULONG length2;
  2797. NTSTATUS status;
  2798. PULONG buffer;
  2799. PMODE_PARAMETER_BLOCK blockDescriptor;
  2800. PAGED_CODE();
  2801. ASSERT_FDO(Fdo);
  2802. length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
  2803. //
  2804. // Allocate buffer for mode select header, block descriptor, and mode page.
  2805. //
  2806. buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  2807. length2,
  2808. DISK_TAG_MODE_DATA);
  2809. if(buffer == NULL) {
  2810. return STATUS_INSUFFICIENT_RESOURCES;
  2811. }
  2812. RtlZeroMemory(buffer, length2);
  2813. //
  2814. // Set length in header to size of mode page.
  2815. //
  2816. ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
  2817. (PULONG)blockDescriptor = (buffer + 1);
  2818. //
  2819. // Set size
  2820. //
  2821. blockDescriptor->BlockLength[1]=0x02;
  2822. //
  2823. // Copy mode page to buffer.
  2824. //
  2825. RtlCopyMemory(buffer + 3, ModeSelectBuffer, Length);
  2826. //
  2827. // Build the MODE SELECT CDB.
  2828. //
  2829. srb.CdbLength = 6;
  2830. cdb = (PCDB)srb.Cdb;
  2831. //
  2832. // Set timeout value from device extension.
  2833. //
  2834. srb.TimeOutValue = fdoExtension->TimeOutValue * 2;
  2835. cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
  2836. cdb->MODE_SELECT.SPBit = SavePage;
  2837. cdb->MODE_SELECT.PFBit = 1;
  2838. cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
  2839. Retry:
  2840. status = ClassSendSrbSynchronous(Fdo,
  2841. &srb,
  2842. buffer,
  2843. length2,
  2844. TRUE);
  2845. if (status == STATUS_VERIFY_REQUIRED) {
  2846. //
  2847. // Routine ClassSendSrbSynchronous does not retry requests returned with
  2848. // this status.
  2849. //
  2850. if (retries--) {
  2851. //
  2852. // Retry request.
  2853. //
  2854. goto Retry;
  2855. }
  2856. } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  2857. status = STATUS_SUCCESS;
  2858. }
  2859. ExFreePool(buffer);
  2860. return status;
  2861. } // end DiskModeSelect()
  2862. //
  2863. // This routine is structured as a work-item routine
  2864. //
  2865. VOID
  2866. DisableWriteCache(
  2867. IN PDEVICE_OBJECT Fdo,
  2868. IN PIO_WORKITEM WorkItem
  2869. )
  2870. {
  2871. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2872. DISK_CACHE_INFORMATION cacheInfo = { 0 };
  2873. NTSTATUS status;
  2874. PAGED_CODE();
  2875. ASSERT_FDO(Fdo);
  2876. status = DiskGetCacheInformation(fdoExtension, &cacheInfo);
  2877. if (NT_SUCCESS(status) && (cacheInfo.WriteCacheEnabled == TRUE)) {
  2878. cacheInfo.WriteCacheEnabled = FALSE;
  2879. DiskSetCacheInformation(fdoExtension, &cacheInfo);
  2880. }
  2881. IoFreeWorkItem(WorkItem);
  2882. }
  2883. //
  2884. // This routine is structured as a work-item routine
  2885. //
  2886. VOID
  2887. DiskIoctlVerify(
  2888. IN PDEVICE_OBJECT Fdo,
  2889. IN PDISK_VERIFY_WORKITEM_CONTEXT Context
  2890. )
  2891. {
  2892. PIRP Irp = Context->Irp;
  2893. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = Fdo->DeviceExtension;
  2894. PDISK_DATA DiskData = (PDISK_DATA)FdoExtension->CommonExtension.DriverData;
  2895. PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
  2896. PSCSI_REQUEST_BLOCK Srb = Context->Srb;
  2897. PCDB Cdb = (PCDB)Srb->Cdb;
  2898. LARGE_INTEGER byteOffset;
  2899. ULONG sectorOffset;
  2900. USHORT sectorCount;
  2901. NTSTATUS status = STATUS_SUCCESS;
  2902. PAGED_CODE();
  2903. ASSERT(FdoExtension->CommonExtension.IsFdo);
  2904. //
  2905. // We don't need to hold on to this memory as
  2906. // the following operation may take some time
  2907. //
  2908. IoFreeWorkItem(Context->WorkItem);
  2909. DebugPrint((1, "Disk.DiskIoctlVerify: Spliting up the request\n"));
  2910. //
  2911. // Add disk offset to starting the sector
  2912. //
  2913. byteOffset.QuadPart = FdoExtension->CommonExtension.StartingOffset.QuadPart +
  2914. verifyInfo->StartingOffset.QuadPart;
  2915. //
  2916. // Convert byte offset to the sector offset
  2917. //
  2918. sectorOffset = (ULONG)(byteOffset.QuadPart >> FdoExtension->SectorShift);
  2919. //
  2920. // Convert ULONG byte count to USHORT sector count.
  2921. //
  2922. sectorCount = (USHORT)(verifyInfo->Length >> FdoExtension->SectorShift);
  2923. //
  2924. // Make sure that all previous verify requests have indeed completed
  2925. // This greatly reduces the possibility of a Denial-of-Service attack
  2926. //
  2927. KeWaitForMutexObject(&DiskData->VerifyMutex,
  2928. Executive,
  2929. KernelMode,
  2930. FALSE,
  2931. NULL);
  2932. while (NT_SUCCESS(status) && (sectorCount != 0))
  2933. {
  2934. USHORT numSectors = min(sectorCount, MAX_SECTORS_PER_VERIFY);
  2935. RtlZeroMemory(Srb, SCSI_REQUEST_BLOCK_SIZE);
  2936. Srb->CdbLength = 10;
  2937. Cdb->CDB10.OperationCode = SCSIOP_VERIFY;
  2938. //
  2939. // Move little endian values into CDB in big endian format
  2940. //
  2941. Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
  2942. Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
  2943. Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
  2944. Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
  2945. Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numSectors)->Byte1;
  2946. Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numSectors)->Byte0;
  2947. //
  2948. // Calculate the request timeout value based
  2949. // on the number of sectors being verified
  2950. //
  2951. Srb->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue;
  2952. status = ClassSendSrbSynchronous(Fdo,
  2953. Srb,
  2954. NULL,
  2955. 0,
  2956. FALSE);
  2957. ASSERT(status != STATUS_NONEXISTENT_SECTOR);
  2958. sectorCount -= numSectors;
  2959. sectorOffset += numSectors;
  2960. }
  2961. KeReleaseMutex(&DiskData->VerifyMutex, FALSE);
  2962. Irp->IoStatus.Status = status;
  2963. Irp->IoStatus.Information = 0;
  2964. ClassReleaseRemoveLock(Fdo, Irp);
  2965. ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT);
  2966. ExFreePool(Srb);
  2967. ExFreePool(Context);
  2968. }
  2969. VOID
  2970. DiskFdoProcessError(
  2971. PDEVICE_OBJECT Fdo,
  2972. PSCSI_REQUEST_BLOCK Srb,
  2973. NTSTATUS *Status,
  2974. BOOLEAN *Retry
  2975. )
  2976. /*++
  2977. Routine Description:
  2978. This routine checks the type of error. If the error indicates an underrun
  2979. then indicate the request should be retried.
  2980. Arguments:
  2981. Fdo - Supplies a pointer to the functional device object.
  2982. Srb - Supplies a pointer to the failing Srb.
  2983. Status - Status with which the IRP will be completed.
  2984. Retry - Indication of whether the request will be retried.
  2985. Return Value:
  2986. None.
  2987. --*/
  2988. {
  2989. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2990. PCDB cdb = (PCDB)(Srb->Cdb);
  2991. ASSERT(fdoExtension->CommonExtension.IsFdo);
  2992. if (*Status == STATUS_DATA_OVERRUN &&
  2993. ( cdb->CDB10.OperationCode == SCSIOP_WRITE ||
  2994. cdb->CDB10.OperationCode == SCSIOP_READ)) {
  2995. *Retry = TRUE;
  2996. //
  2997. // Update the error count for the device.
  2998. //
  2999. fdoExtension->ErrorCount++;
  3000. } else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
  3001. Srb->ScsiStatus == SCSISTAT_BUSY) {
  3002. //
  3003. // a disk drive should never be busy this long. Reset the scsi bus
  3004. // maybe this will clear the condition.
  3005. //
  3006. ResetBus(Fdo);
  3007. //
  3008. // Update the error count for the device.
  3009. //
  3010. fdoExtension->ErrorCount++;
  3011. } else {
  3012. BOOLEAN invalidatePartitionTable = FALSE;
  3013. BOOLEAN bForceBusRelations = FALSE;
  3014. //
  3015. // See if this might indicate that something on the drive has changed.
  3016. //
  3017. if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
  3018. (Srb->SenseInfoBufferLength >=
  3019. FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation))) {
  3020. PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
  3021. ULONG senseKey = senseBuffer->SenseKey & 0xf;
  3022. ULONG asc = senseBuffer->AdditionalSenseCode;
  3023. ULONG ascq = senseBuffer->AdditionalSenseCodeQualifier;
  3024. switch (senseKey) {
  3025. case SCSI_SENSE_ILLEGAL_REQUEST: {
  3026. switch (asc) {
  3027. case SCSI_ADSENSE_ILLEGAL_BLOCK: {
  3028. if ((cdb->CDB10.OperationCode == SCSIOP_READ) ||
  3029. (cdb->CDB10.OperationCode == SCSIOP_WRITE)
  3030. ) {
  3031. // should only retry these if the request was
  3032. // truly within our expected size. however,
  3033. // this check was already done in the
  3034. // ReadWriteVerification routine.
  3035. /*
  3036. * Fujitsu IDE drives have been observed to
  3037. * return this error transiently for a legal LBA;
  3038. * manual retry in the debugger then works, so
  3039. * there is a good chance that a programmed retry
  3040. * will also work.
  3041. */
  3042. *Retry = TRUE;
  3043. }
  3044. break;
  3045. }
  3046. case SCSI_ADSENSE_INVALID_CDB:
  3047. {
  3048. //
  3049. // Look to see if this is an Io request with the ForceUnitAccess flag set
  3050. //
  3051. if ((cdb->CDB10.OperationCode == SCSIOP_WRITE) && (cdb->CDB10.ForceUnitAccess))
  3052. {
  3053. PDISK_DATA diskData = (PDISK_DATA)fdoExtension->CommonExtension.DriverData;
  3054. if (diskData->WriteCacheOverride == DiskWriteCacheEnable)
  3055. {
  3056. //
  3057. // The user has explicitly requested that write caching be turned on
  3058. //
  3059. }
  3060. else
  3061. {
  3062. //
  3063. // Turn off write caching on this device. This is so that future
  3064. // critical requests need not be sent down with ForceUnitAccess
  3065. //
  3066. PIO_WORKITEM workItem = IoAllocateWorkItem(Fdo);
  3067. if (workItem)
  3068. {
  3069. IoQueueWorkItem(workItem, DisableWriteCache, CriticalWorkQueue, workItem);
  3070. }
  3071. }
  3072. SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_FUA_NOT_SUPPORTED);
  3073. cdb->CDB10.ForceUnitAccess = FALSE;
  3074. *Retry = TRUE;
  3075. }
  3076. break;
  3077. }
  3078. } // end switch(asc)
  3079. break;
  3080. }
  3081. case SCSI_SENSE_NOT_READY: {
  3082. switch (asc) {
  3083. case SCSI_ADSENSE_LUN_NOT_READY: {
  3084. switch (ascq) {
  3085. case SCSI_SENSEQ_BECOMING_READY:
  3086. case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
  3087. case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: {
  3088. invalidatePartitionTable = TRUE;
  3089. break;
  3090. }
  3091. } // end switch(ascq)
  3092. break;
  3093. }
  3094. case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: {
  3095. invalidatePartitionTable = TRUE;
  3096. break;
  3097. }
  3098. } // end switch(asc)
  3099. break;
  3100. }
  3101. case SCSI_SENSE_MEDIUM_ERROR: {
  3102. invalidatePartitionTable = TRUE;
  3103. break;
  3104. }
  3105. case SCSI_SENSE_HARDWARE_ERROR: {
  3106. invalidatePartitionTable = TRUE;
  3107. break;
  3108. }
  3109. case SCSI_SENSE_UNIT_ATTENTION:
  3110. {
  3111. invalidatePartitionTable = TRUE;
  3112. switch (senseBuffer->AdditionalSenseCode)
  3113. {
  3114. case SCSI_ADSENSE_MEDIUM_CHANGED:
  3115. {
  3116. bForceBusRelations = TRUE;
  3117. break;
  3118. }
  3119. }
  3120. break;
  3121. }
  3122. case SCSI_SENSE_RECOVERED_ERROR: {
  3123. invalidatePartitionTable = TRUE;
  3124. break;
  3125. }
  3126. } // end switch(senseKey)
  3127. } else {
  3128. //
  3129. // On any exceptional scsi condition which might indicate that the
  3130. // device was changed we will flush out the state of the partition
  3131. // table.
  3132. //
  3133. switch (SRB_STATUS(Srb->SrbStatus)) {
  3134. case SRB_STATUS_INVALID_LUN:
  3135. case SRB_STATUS_INVALID_TARGET_ID:
  3136. case SRB_STATUS_NO_DEVICE:
  3137. case SRB_STATUS_NO_HBA:
  3138. case SRB_STATUS_INVALID_PATH_ID:
  3139. case SRB_STATUS_COMMAND_TIMEOUT:
  3140. case SRB_STATUS_TIMEOUT:
  3141. case SRB_STATUS_SELECTION_TIMEOUT:
  3142. case SRB_STATUS_REQUEST_FLUSHED:
  3143. case SRB_STATUS_UNEXPECTED_BUS_FREE:
  3144. case SRB_STATUS_PARITY_ERROR:
  3145. {
  3146. invalidatePartitionTable = TRUE;
  3147. break;
  3148. }
  3149. case SRB_STATUS_ERROR:
  3150. {
  3151. if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT)
  3152. {
  3153. invalidatePartitionTable = TRUE;
  3154. }
  3155. break;
  3156. }
  3157. } // end switch(Srb->SrbStatus)
  3158. }
  3159. if (invalidatePartitionTable)
  3160. {
  3161. if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA) && (fdoExtension->CommonExtension.ChildList))
  3162. {
  3163. //
  3164. // Locate the PDO associated with this removable device
  3165. //
  3166. PDEVICE_OBJECT Pdo = (fdoExtension->CommonExtension.ChildList)->CommonExtension.DeviceObject;
  3167. if ((ClassGetVpb(Pdo) != NULL) && (ClassGetVpb(Pdo)->Flags & VPB_MOUNTED))
  3168. {
  3169. //
  3170. // Set a flag to inform the filesystem
  3171. // that this volume needs verification
  3172. //
  3173. SET_FLAG(Pdo->Flags, DO_VERIFY_VOLUME);
  3174. }
  3175. }
  3176. if (DiskInvalidatePartitionTable(fdoExtension, FALSE) || bForceBusRelations)
  3177. {
  3178. IoInvalidateDeviceRelations(fdoExtension->LowerPdo, BusRelations);
  3179. }
  3180. }
  3181. }
  3182. return;
  3183. }
  3184. VOID
  3185. DiskSetSpecialHacks(
  3186. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  3187. IN ULONG_PTR Data
  3188. )
  3189. /*++
  3190. Routine Description:
  3191. This function checks to see if an SCSI logical unit requires speical
  3192. flags to be set.
  3193. Arguments:
  3194. Fdo - Supplies the device object to be tested.
  3195. InquiryData - Supplies the inquiry data returned by the device of interest.
  3196. AdapterDescriptor - Supplies the capabilities of the device object.
  3197. Return Value:
  3198. None.
  3199. --*/
  3200. {
  3201. PDEVICE_OBJECT fdo = FdoExtension->DeviceObject;
  3202. PAGED_CODE();
  3203. DebugPrint((1, "Disk SetSpecialHacks, Setting Hacks %p\n", Data));
  3204. //
  3205. // Found a listed controller. Determine what must be done.
  3206. //
  3207. if (TEST_FLAG(Data, HackDisableTaggedQueuing)) {
  3208. //
  3209. // Disable tagged queuing.
  3210. //
  3211. CLEAR_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
  3212. }
  3213. if (TEST_FLAG(Data, HackDisableSynchronousTransfers)) {
  3214. //
  3215. // Disable synchronous data transfers.
  3216. //
  3217. SET_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  3218. }
  3219. if (TEST_FLAG(Data, HackDisableSpinDown)) {
  3220. //
  3221. // Disable spinning down of drives.
  3222. //
  3223. SET_FLAG(FdoExtension->ScanForSpecialFlags,
  3224. CLASS_SPECIAL_DISABLE_SPIN_DOWN);
  3225. }
  3226. if (TEST_FLAG(Data, HackDisableWriteCache)) {
  3227. //
  3228. // Disable the drive's write cache
  3229. //
  3230. SET_FLAG(FdoExtension->ScanForSpecialFlags,
  3231. CLASS_SPECIAL_DISABLE_WRITE_CACHE);
  3232. }
  3233. if (TEST_FLAG(Data, HackCauseNotReportableHack)) {
  3234. SET_FLAG(FdoExtension->ScanForSpecialFlags,
  3235. CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK);
  3236. }
  3237. if (TEST_FLAG(fdo->Characteristics, FILE_REMOVABLE_MEDIA) &&
  3238. TEST_FLAG(Data, HackRequiresStartUnitCommand)
  3239. ) {
  3240. //
  3241. // this is a list of vendors who require the START_UNIT command
  3242. //
  3243. DebugPrint((1, "DiskScanForSpecial (%p) => This unit requires "
  3244. " START_UNITS\n", fdo));
  3245. SET_FLAG(FdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
  3246. }
  3247. return;
  3248. }
  3249. VOID
  3250. ResetBus(
  3251. IN PDEVICE_OBJECT Fdo
  3252. )
  3253. /*++
  3254. Routine Description:
  3255. This command sends a reset bus command to the SCSI port driver.
  3256. Arguments:
  3257. Fdo - The functional device object for the logical unit with hardware problem.
  3258. Return Value:
  3259. None.
  3260. --*/
  3261. {
  3262. PIO_STACK_LOCATION irpStack;
  3263. PIRP irp;
  3264. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  3265. PSCSI_REQUEST_BLOCK srb;
  3266. PCOMPLETION_CONTEXT context;
  3267. DebugPrint((1, "Disk ResetBus: Sending reset bus request to port driver.\n"));
  3268. //
  3269. // Allocate Srb from nonpaged pool.
  3270. //
  3271. context = ExAllocatePoolWithTag(NonPagedPool,
  3272. sizeof(COMPLETION_CONTEXT),
  3273. DISK_TAG_CCONTEXT);
  3274. if(context == NULL) {
  3275. return;
  3276. }
  3277. //
  3278. // Save the device object in the context for use by the completion
  3279. // routine.
  3280. //
  3281. context->DeviceObject = Fdo;
  3282. srb = &context->Srb;
  3283. //
  3284. // Zero out srb.
  3285. //
  3286. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  3287. //
  3288. // Write length to SRB.
  3289. //
  3290. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  3291. srb->Function = SRB_FUNCTION_RESET_BUS;
  3292. //
  3293. // Build the asynchronous request to be sent to the port driver.
  3294. // Since this routine is called from a DPC the IRP should always be
  3295. // available.
  3296. //
  3297. irp = IoAllocateIrp(Fdo->StackSize, FALSE);
  3298. if(irp == NULL) {
  3299. ExFreePool(context);
  3300. return;
  3301. }
  3302. ClassAcquireRemoveLock(Fdo, irp);
  3303. IoSetCompletionRoutine(irp,
  3304. (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
  3305. context,
  3306. TRUE,
  3307. TRUE,
  3308. TRUE);
  3309. irpStack = IoGetNextIrpStackLocation(irp);
  3310. irpStack->MajorFunction = IRP_MJ_SCSI;
  3311. srb->OriginalRequest = irp;
  3312. //
  3313. // Store the SRB address in next stack for port driver.
  3314. //
  3315. irpStack->Parameters.Scsi.Srb = srb;
  3316. //
  3317. // Call the port driver with the IRP.
  3318. //
  3319. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
  3320. return;
  3321. } // end ResetBus()
  3322. NTSTATUS
  3323. DiskQueryPnpCapabilities(
  3324. IN PDEVICE_OBJECT DeviceObject,
  3325. IN PDEVICE_CAPABILITIES Capabilities
  3326. )
  3327. {
  3328. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  3329. PDISK_DATA diskData = commonExtension->DriverData;
  3330. PAGED_CODE();
  3331. ASSERT(DeviceObject);
  3332. ASSERT(Capabilities);
  3333. if(commonExtension->IsFdo) {
  3334. return STATUS_NOT_IMPLEMENTED;
  3335. } else {
  3336. PPHYSICAL_DEVICE_EXTENSION physicalExtension =
  3337. DeviceObject->DeviceExtension;
  3338. Capabilities->SilentInstall = 1;
  3339. Capabilities->RawDeviceOK = 1;
  3340. Capabilities->Address = commonExtension->PartitionNumber;
  3341. if(!TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
  3342. //
  3343. // Media's not removable, deviceId/DeviceInstance should be
  3344. // globally unique.
  3345. //
  3346. Capabilities->UniqueID = 1;
  3347. } else {
  3348. Capabilities->UniqueID = 0;
  3349. }
  3350. }
  3351. return STATUS_SUCCESS;
  3352. }
  3353. NTSTATUS
  3354. DiskGetCacheInformation(
  3355. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  3356. IN PDISK_CACHE_INFORMATION CacheInfo
  3357. )
  3358. {
  3359. PMODE_PARAMETER_HEADER modeData;
  3360. PMODE_CACHING_PAGE pageData;
  3361. ULONG length;
  3362. NTSTATUS status;
  3363. PAGED_CODE();
  3364. modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  3365. MODE_DATA_SIZE,
  3366. DISK_TAG_DISABLE_CACHE);
  3367. if (modeData == NULL) {
  3368. DebugPrint((1, "DiskGetSetCacheInformation: Unable to allocate mode "
  3369. "data buffer\n"));
  3370. return STATUS_INSUFFICIENT_RESOURCES;
  3371. }
  3372. RtlZeroMemory(modeData, MODE_DATA_SIZE);
  3373. length = ClassModeSense(FdoExtension->DeviceObject,
  3374. (PUCHAR) modeData,
  3375. MODE_DATA_SIZE,
  3376. MODE_SENSE_RETURN_ALL);
  3377. if (length < sizeof(MODE_PARAMETER_HEADER)) {
  3378. //
  3379. // Retry the request in case of a check condition.
  3380. //
  3381. length = ClassModeSense(FdoExtension->DeviceObject,
  3382. (PUCHAR) modeData,
  3383. MODE_DATA_SIZE,
  3384. MODE_SENSE_RETURN_ALL);
  3385. if (length < sizeof(MODE_PARAMETER_HEADER)) {
  3386. DebugPrint((1, "Disk.DisableWriteCache: Mode Sense failed\n"));
  3387. ExFreePool(modeData);
  3388. return STATUS_IO_DEVICE_ERROR;
  3389. }
  3390. }
  3391. //
  3392. // If the length is greater than length indicated by the mode data reset
  3393. // the data to the mode data.
  3394. //
  3395. if (length > (ULONG) (modeData->ModeDataLength + 1)) {
  3396. length = modeData->ModeDataLength + 1;
  3397. }
  3398. //
  3399. // Check to see if the write cache is enabled.
  3400. //
  3401. pageData = ClassFindModePage((PUCHAR) modeData,
  3402. length,
  3403. MODE_PAGE_CACHING,
  3404. TRUE);
  3405. //
  3406. // Check if valid caching page exists.
  3407. //
  3408. if (pageData == NULL) {
  3409. ExFreePool(modeData);
  3410. return STATUS_NOT_SUPPORTED;
  3411. }
  3412. //
  3413. // Copy the parameters over.
  3414. //
  3415. RtlZeroMemory(CacheInfo, sizeof(DISK_CACHE_INFORMATION));
  3416. CacheInfo->ParametersSavable = pageData->PageSavable;
  3417. CacheInfo->ReadCacheEnabled = !(pageData->ReadDisableCache);
  3418. CacheInfo->WriteCacheEnabled = pageData->WriteCacheEnable;
  3419. //
  3420. // Translate the values in the mode page into the ones defined in
  3421. // ntdddisk.h.
  3422. //
  3423. CacheInfo->ReadRetentionPriority =
  3424. TRANSLATE_RETENTION_PRIORITY(pageData->ReadRetensionPriority);
  3425. CacheInfo->WriteRetentionPriority =
  3426. TRANSLATE_RETENTION_PRIORITY(pageData->WriteRetensionPriority);
  3427. CacheInfo->DisablePrefetchTransferLength =
  3428. ((pageData->DisablePrefetchTransfer[0] << 8) +
  3429. pageData->DisablePrefetchTransfer[1]);
  3430. CacheInfo->ScalarPrefetch.Minimum =
  3431. ((pageData->MinimumPrefetch[0] << 8) + pageData->MinimumPrefetch[1]);
  3432. CacheInfo->ScalarPrefetch.Maximum =
  3433. ((pageData->MaximumPrefetch[0] << 8) + pageData->MaximumPrefetch[1]);
  3434. if(pageData->MultiplicationFactor) {
  3435. CacheInfo->PrefetchScalar = TRUE;
  3436. CacheInfo->ScalarPrefetch.MaximumBlocks =
  3437. ((pageData->MaximumPrefetchCeiling[0] << 8) +
  3438. pageData->MaximumPrefetchCeiling[1]);
  3439. }
  3440. ExFreePool(modeData);
  3441. return STATUS_SUCCESS;
  3442. }
  3443. NTSTATUS
  3444. DiskSetCacheInformation(
  3445. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  3446. IN PDISK_CACHE_INFORMATION CacheInfo
  3447. )
  3448. {
  3449. PMODE_PARAMETER_HEADER modeData;
  3450. ULONG length;
  3451. PMODE_CACHING_PAGE pageData;
  3452. ULONG i;
  3453. NTSTATUS status;
  3454. PAGED_CODE();
  3455. modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  3456. MODE_DATA_SIZE,
  3457. DISK_TAG_DISABLE_CACHE);
  3458. if (modeData == NULL) {
  3459. DebugPrint((1, "DiskSetCacheInformation: Unable to allocate mode "
  3460. "data buffer\n"));
  3461. return STATUS_INSUFFICIENT_RESOURCES;
  3462. }
  3463. RtlZeroMemory(modeData, MODE_DATA_SIZE);
  3464. length = ClassModeSense(FdoExtension->DeviceObject,
  3465. (PUCHAR) modeData,
  3466. MODE_DATA_SIZE,
  3467. MODE_PAGE_CACHING);
  3468. if (length < sizeof(MODE_PARAMETER_HEADER)) {
  3469. //
  3470. // Retry the request in case of a check condition.
  3471. //
  3472. length = ClassModeSense(FdoExtension->DeviceObject,
  3473. (PUCHAR) modeData,
  3474. MODE_DATA_SIZE,
  3475. MODE_PAGE_CACHING);
  3476. if (length < sizeof(MODE_PARAMETER_HEADER)) {
  3477. DebugPrint((1, "Disk.DisableWriteCache: Mode Sense failed\n"));
  3478. ExFreePool(modeData);
  3479. return STATUS_IO_DEVICE_ERROR;
  3480. }
  3481. }
  3482. //
  3483. // If the length is greater than length indicated by the mode data reset
  3484. // the data to the mode data.
  3485. //
  3486. if (length > (ULONG) (modeData->ModeDataLength + 1)) {
  3487. length = modeData->ModeDataLength + 1;
  3488. }
  3489. //
  3490. // Check to see if the write cache is enabled.
  3491. //
  3492. pageData = ClassFindModePage((PUCHAR) modeData,
  3493. length,
  3494. MODE_PAGE_CACHING,
  3495. TRUE);
  3496. //
  3497. // Check if valid caching page exists.
  3498. //
  3499. if (pageData == NULL) {
  3500. ExFreePool(modeData);
  3501. return STATUS_NOT_SUPPORTED;
  3502. }
  3503. //
  3504. // Don't touch any of the normal parameters - not all drives actually
  3505. // use the correct size of caching mode page. Just change the things
  3506. // which the user could have modified.
  3507. //
  3508. pageData->PageSavable = FALSE;
  3509. pageData->ReadDisableCache = !(CacheInfo->ReadCacheEnabled);
  3510. pageData->MultiplicationFactor = CacheInfo->PrefetchScalar;
  3511. pageData->WriteCacheEnable = CacheInfo->WriteCacheEnabled;
  3512. pageData->WriteRetensionPriority = (UCHAR)
  3513. TRANSLATE_RETENTION_PRIORITY(CacheInfo->WriteRetentionPriority);
  3514. pageData->ReadRetensionPriority = (UCHAR)
  3515. TRANSLATE_RETENTION_PRIORITY(CacheInfo->ReadRetentionPriority);
  3516. pageData->DisablePrefetchTransfer[0] =
  3517. (UCHAR) (CacheInfo->DisablePrefetchTransferLength >> 8);
  3518. pageData->DisablePrefetchTransfer[1] =
  3519. (UCHAR) (CacheInfo->DisablePrefetchTransferLength & 0x00ff);
  3520. pageData->MinimumPrefetch[0] =
  3521. (UCHAR) (CacheInfo->ScalarPrefetch.Minimum >> 8);
  3522. pageData->MinimumPrefetch[1] =
  3523. (UCHAR) (CacheInfo->ScalarPrefetch.Minimum & 0x00ff);
  3524. pageData->MaximumPrefetch[0] =
  3525. (UCHAR) (CacheInfo->ScalarPrefetch.Maximum >> 8);
  3526. pageData->MaximumPrefetch[1] =
  3527. (UCHAR) (CacheInfo->ScalarPrefetch.Maximum & 0x00ff);
  3528. if(pageData->MultiplicationFactor) {
  3529. pageData->MaximumPrefetchCeiling[0] =
  3530. (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks >> 8);
  3531. pageData->MaximumPrefetchCeiling[1] =
  3532. (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks & 0x00ff);
  3533. }
  3534. //
  3535. // We will attempt (twice) to issue the mode select with the page.
  3536. //
  3537. for (i = 0; i < 2; i++) {
  3538. status = DiskModeSelect(FdoExtension->DeviceObject,
  3539. (PUCHAR) pageData,
  3540. (pageData->PageLength + 2),
  3541. CacheInfo->ParametersSavable);
  3542. if (NT_SUCCESS(status)) {
  3543. if (CacheInfo->WriteCacheEnabled)
  3544. {
  3545. SET_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
  3546. }
  3547. else
  3548. {
  3549. CLEAR_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
  3550. }
  3551. break;
  3552. }
  3553. }
  3554. if (!NT_SUCCESS(status))
  3555. {
  3556. //
  3557. // We were unable to modify the disk write cache setting
  3558. //
  3559. SET_FLAG(FdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_MODIFY_CACHE_UNSUCCESSFUL);
  3560. }
  3561. ExFreePool(modeData);
  3562. return status;
  3563. }
  3564. VOID
  3565. DiskLogCacheInformation(
  3566. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  3567. IN PDISK_CACHE_INFORMATION CacheInfo,
  3568. IN NTSTATUS Status
  3569. )
  3570. {
  3571. PIO_ERROR_LOG_PACKET logEntry = NULL;
  3572. PAGED_CODE();
  3573. logEntry = IoAllocateErrorLogEntry(FdoExtension->DeviceObject, sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG)));
  3574. if (logEntry != NULL)
  3575. {
  3576. PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
  3577. BOOLEAN bIsEnabled = TEST_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
  3578. logEntry->FinalStatus = Status;
  3579. logEntry->ErrorCode = (bIsEnabled) ? IO_WRITE_CACHE_ENABLED : IO_WRITE_CACHE_DISABLED;
  3580. logEntry->SequenceNumber = 0;
  3581. logEntry->MajorFunctionCode = IRP_MJ_SCSI;
  3582. logEntry->IoControlCode = 0;
  3583. logEntry->RetryCount = 0;
  3584. logEntry->UniqueErrorValue = 0x1;
  3585. logEntry->DumpDataSize = 4;
  3586. logEntry->DumpData[0] = diskData->ScsiAddress.PathId;
  3587. logEntry->DumpData[1] = diskData->ScsiAddress.TargetId;
  3588. logEntry->DumpData[2] = diskData->ScsiAddress.Lun;
  3589. logEntry->DumpData[3] = CacheInfo->WriteCacheEnabled;
  3590. //
  3591. // Write the error log packet.
  3592. //
  3593. IoWriteErrorLogEntry(logEntry);
  3594. }
  3595. }
  3596. NTSTATUS
  3597. DiskIoctlGetCacheSetting(
  3598. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  3599. IN PIRP Irp
  3600. )
  3601. /*++
  3602. Routine description:
  3603. This routine services IOCTL_DISK_GET_CACHE_SETTING. It looks to
  3604. see if there are any issues with the disk cache and whether the
  3605. user had previously indicated that the cache is power-protected
  3606. Arguments:
  3607. Fdo - The functional device object processing the request
  3608. Irp - The ioctl to be processed
  3609. Return Value:
  3610. STATUS_SUCCESS if successful, an error code otherwise
  3611. --*/
  3612. {
  3613. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3614. NTSTATUS status = STATUS_SUCCESS;
  3615. PAGED_CODE();
  3616. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_SETTING))
  3617. {
  3618. status = STATUS_BUFFER_TOO_SMALL;
  3619. }
  3620. else
  3621. {
  3622. PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer;
  3623. cacheSetting->Version = sizeof(DISK_CACHE_SETTING);
  3624. cacheSetting->State = DiskCacheNormal;
  3625. //
  3626. // Determine whether it is safe to turn on the cache
  3627. //
  3628. if (TEST_FLAG(FdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_FUA_NOT_SUPPORTED))
  3629. {
  3630. cacheSetting->State = DiskCacheWriteThroughNotSupported;
  3631. }
  3632. //
  3633. // Determine whether it is possible to modify the cache setting
  3634. //
  3635. if (TEST_FLAG(FdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_MODIFY_CACHE_UNSUCCESSFUL))
  3636. {
  3637. cacheSetting->State = DiskCacheModifyUnsuccessful;
  3638. }
  3639. cacheSetting->IsPowerProtected = TEST_FLAG(FdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
  3640. Irp->IoStatus.Information = sizeof(DISK_CACHE_SETTING);
  3641. }
  3642. return status;
  3643. }
  3644. NTSTATUS
  3645. DiskIoctlSetCacheSetting(
  3646. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  3647. IN PIRP Irp
  3648. )
  3649. /*++
  3650. Routine description:
  3651. This routine services IOCTL_DISK_SET_CACHE_SETTING. It allows
  3652. the user to specify whether the disk cache is power-protected
  3653. or not
  3654. Arguments:
  3655. Fdo - The functional device object processing the request
  3656. Irp - The ioctl to be processed
  3657. Return Value:
  3658. STATUS_SUCCESS if successful, an error code otherwise
  3659. --*/
  3660. {
  3661. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3662. NTSTATUS status = STATUS_SUCCESS;
  3663. PAGED_CODE();
  3664. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_SETTING))
  3665. {
  3666. status = STATUS_INFO_LENGTH_MISMATCH;
  3667. }
  3668. else
  3669. {
  3670. PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer;
  3671. if (cacheSetting->Version == sizeof(DISK_CACHE_SETTING))
  3672. {
  3673. ULONG isPowerProtected;
  3674. //
  3675. // Save away the user-defined override in our extension and the registry
  3676. //
  3677. if (cacheSetting->IsPowerProtected)
  3678. {
  3679. SET_FLAG(FdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
  3680. isPowerProtected = 1;
  3681. }
  3682. else
  3683. {
  3684. CLEAR_FLAG(FdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
  3685. isPowerProtected = 0;
  3686. }
  3687. ClassSetDeviceParameter(FdoExtension, DiskDeviceParameterSubkey, DiskDeviceCacheIsPowerProtected, isPowerProtected);
  3688. }
  3689. else
  3690. {
  3691. status = STATUS_INVALID_PARAMETER;
  3692. }
  3693. }
  3694. return status;
  3695. }
  3696. PPARTITION_INFORMATION_EX
  3697. DiskPdoFindPartitionEntry(
  3698. IN PPHYSICAL_DEVICE_EXTENSION Pdo,
  3699. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
  3700. )
  3701. {
  3702. PCOMMON_DEVICE_EXTENSION commonExtension= &(Pdo->CommonExtension);
  3703. ULONG partitionIndex;
  3704. PAGED_CODE();
  3705. DebugPrint((1, "DiskPdoFindPartitionEntry: Searching layout for "
  3706. "matching partition.\n"));
  3707. for(partitionIndex = 0;
  3708. partitionIndex < LayoutInfo->PartitionCount;
  3709. partitionIndex++) {
  3710. PPARTITION_INFORMATION_EX partitionInfo;
  3711. //
  3712. // Get the partition entry
  3713. //
  3714. partitionInfo = &LayoutInfo->PartitionEntry[partitionIndex];
  3715. //
  3716. // See if it is the one we are looking for...
  3717. //
  3718. if( LayoutInfo->PartitionStyle == PARTITION_STYLE_MBR &&
  3719. (partitionInfo->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
  3720. IsContainerPartition(partitionInfo->Mbr.PartitionType)) ) {
  3721. continue;
  3722. }
  3723. if( LayoutInfo->PartitionStyle == PARTITION_STYLE_GPT &&
  3724. DiskCompareGuid (&partitionInfo->Gpt.PartitionType, &GUID_NULL) == 00) {
  3725. continue;
  3726. }
  3727. if( (commonExtension->StartingOffset.QuadPart ==
  3728. partitionInfo->StartingOffset.QuadPart) &&
  3729. (commonExtension->PartitionLength.QuadPart ==
  3730. partitionInfo->PartitionLength.QuadPart)) {
  3731. //
  3732. // Found it!
  3733. //
  3734. DebugPrint((1, "DiskPdoFindPartitionEntry: Found matching "
  3735. "partition.\n"));
  3736. return partitionInfo;
  3737. }
  3738. }
  3739. return NULL;
  3740. }
  3741. PPARTITION_INFORMATION_EX
  3742. DiskFindAdjacentPartition(
  3743. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
  3744. IN PPARTITION_INFORMATION_EX BasePartition
  3745. )
  3746. {
  3747. ULONG partitionIndex;
  3748. LONGLONG baseStoppingOffset;
  3749. LONGLONG adjacentStartingOffset;
  3750. PPARTITION_INFORMATION_EX adjacentPartition = 0;
  3751. ASSERT(LayoutInfo && BasePartition);
  3752. PAGED_CODE();
  3753. DebugPrint((1, "DiskPdoFindAdjacentPartition: Searching layout for adjacent partition.\n"));
  3754. //
  3755. // Construct the base stopping offset for comparison
  3756. //
  3757. baseStoppingOffset = (BasePartition->StartingOffset.QuadPart +
  3758. BasePartition->PartitionLength.QuadPart -
  3759. 1);
  3760. adjacentStartingOffset = MAXLONGLONG;
  3761. for(partitionIndex = 0;
  3762. partitionIndex < LayoutInfo->PartitionCount;
  3763. partitionIndex++) {
  3764. PPARTITION_INFORMATION_EX partitionInfo;
  3765. //
  3766. // Get the partition entry
  3767. //
  3768. partitionInfo = &LayoutInfo->PartitionEntry[partitionIndex];
  3769. //
  3770. // See if it is the one we are looking for...
  3771. //
  3772. if( LayoutInfo->PartitionStyle == PARTITION_STYLE_MBR &&
  3773. partitionInfo->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ) {
  3774. continue;
  3775. }
  3776. if( LayoutInfo->PartitionStyle == PARTITION_STYLE_GPT &&
  3777. DiskCompareGuid (&partitionInfo->Gpt.PartitionType, &GUID_NULL) == 00 ) {
  3778. continue;
  3779. }
  3780. if((partitionInfo->StartingOffset.QuadPart > baseStoppingOffset) &&
  3781. (partitionInfo->StartingOffset.QuadPart < adjacentStartingOffset)) {
  3782. // Found a closer neighbor...update and remember.
  3783. adjacentPartition = partitionInfo;
  3784. adjacentStartingOffset = adjacentPartition->StartingOffset.QuadPart;
  3785. DebugPrint((1, "DiskPdoFindAdjacentPartition: Found adjacent "
  3786. "partition.\n"));
  3787. }
  3788. }
  3789. return adjacentPartition;
  3790. }
  3791. PPARTITION_INFORMATION_EX
  3792. DiskFindContainingPartition(
  3793. IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
  3794. IN PPARTITION_INFORMATION_EX BasePartition,
  3795. IN BOOLEAN SearchTopToBottom
  3796. )
  3797. {
  3798. LONG partitionIndex;
  3799. LONG startIndex;
  3800. LONG stopIndex;
  3801. LONG stepIndex;
  3802. LONGLONG baseStoppingOffset;
  3803. LONGLONG containerStoppingOffset;
  3804. PPARTITION_INFORMATION_EX partitionInfo = 0;
  3805. PPARTITION_INFORMATION_EX containerPartition = 0;
  3806. PAGED_CODE();
  3807. ASSERT( LayoutInfo && BasePartition);
  3808. DebugPrint((1, "DiskFindContainingPartition: Searching for extended partition.\n"));
  3809. if( LayoutInfo->PartitionCount != 0) {
  3810. baseStoppingOffset = (BasePartition->StartingOffset.QuadPart +
  3811. BasePartition->PartitionLength.QuadPart - 1);
  3812. //
  3813. // Determine the search direction and setup the loop
  3814. //
  3815. if(SearchTopToBottom == TRUE) {
  3816. startIndex = 0;
  3817. stopIndex = LayoutInfo->PartitionCount;
  3818. stepIndex = +1;
  3819. } else {
  3820. startIndex = LayoutInfo->PartitionCount - 1;
  3821. stopIndex = -1;
  3822. stepIndex = -1;
  3823. }
  3824. //
  3825. // Using the loop parameters, walk the layout information and
  3826. // return the first containing partition.
  3827. //
  3828. for(partitionIndex = startIndex;
  3829. partitionIndex != stopIndex;
  3830. partitionIndex += stepIndex) {
  3831. //
  3832. // Get the next partition entry
  3833. //
  3834. partitionInfo = &LayoutInfo->PartitionEntry[partitionIndex];
  3835. containerStoppingOffset = (partitionInfo->StartingOffset.QuadPart +
  3836. partitionInfo->PartitionLength.QuadPart -
  3837. 1);
  3838. //
  3839. // Search for a containing partition without detecting the
  3840. // same partition as a container of itself. The starting
  3841. // offset of a partition and its container should never be
  3842. // the same; however, the stopping offset can be the same.
  3843. //
  3844. //
  3845. // NOTE: Container partitions are MBR only.
  3846. //
  3847. if((LayoutInfo->PartitionStyle == PARTITION_STYLE_MBR) &&
  3848. (IsContainerPartition(partitionInfo->Mbr.PartitionType)) &&
  3849. (BasePartition->StartingOffset.QuadPart >
  3850. partitionInfo->StartingOffset.QuadPart) &&
  3851. (baseStoppingOffset <= containerStoppingOffset)) {
  3852. containerPartition = partitionInfo;
  3853. DebugPrint((1, "DiskFindContainingPartition: Found a "
  3854. "containing extended partition.\n"));
  3855. break;
  3856. }
  3857. }
  3858. }
  3859. return containerPartition;
  3860. }
  3861. NTSTATUS
  3862. DiskGetInfoExceptionInformation(
  3863. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  3864. IN PMODE_INFO_EXCEPTIONS ReturnPageData
  3865. )
  3866. {
  3867. PMODE_PARAMETER_HEADER modeData;
  3868. PMODE_INFO_EXCEPTIONS pageData;
  3869. ULONG length;
  3870. NTSTATUS status;
  3871. PAGED_CODE();
  3872. //
  3873. // ReturnPageData is allocated by the caller
  3874. //
  3875. modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  3876. MODE_DATA_SIZE,
  3877. DISK_TAG_INFO_EXCEPTION);
  3878. if (modeData == NULL) {
  3879. DebugPrint((1, "DiskGetInfoExceptionInformation: Unable to allocate mode "
  3880. "data buffer\n"));
  3881. return STATUS_INSUFFICIENT_RESOURCES;
  3882. }
  3883. RtlZeroMemory(modeData, MODE_DATA_SIZE);
  3884. length = ClassModeSense(FdoExtension->DeviceObject,
  3885. (PUCHAR) modeData,
  3886. MODE_DATA_SIZE,
  3887. MODE_PAGE_FAULT_REPORTING);
  3888. if (length < sizeof(MODE_PARAMETER_HEADER)) {
  3889. //
  3890. // Retry the request in case of a check condition.
  3891. //
  3892. length = ClassModeSense(FdoExtension->DeviceObject,
  3893. (PUCHAR) modeData,
  3894. MODE_DATA_SIZE,
  3895. MODE_PAGE_FAULT_REPORTING);
  3896. if (length < sizeof(MODE_PARAMETER_HEADER)) {
  3897. DebugPrint((1, "Disk.DisableWriteCache: Mode Sense failed\n"));
  3898. ExFreePool(modeData);
  3899. return STATUS_IO_DEVICE_ERROR;
  3900. }
  3901. }
  3902. //
  3903. // If the length is greater than length indicated by the mode data reset
  3904. // the data to the mode data.
  3905. //
  3906. if (length > (ULONG) (modeData->ModeDataLength + 1)) {
  3907. length = modeData->ModeDataLength + 1;
  3908. }
  3909. //
  3910. // Find the mode page for info exceptions
  3911. //
  3912. pageData = ClassFindModePage((PUCHAR) modeData,
  3913. length,
  3914. MODE_PAGE_FAULT_REPORTING,
  3915. TRUE);
  3916. if (pageData != NULL) {
  3917. RtlCopyMemory(ReturnPageData, pageData, sizeof(MODE_INFO_EXCEPTIONS));
  3918. status = STATUS_SUCCESS;
  3919. } else {
  3920. status = STATUS_NOT_SUPPORTED;
  3921. }
  3922. DebugPrint((3, "DiskGetInfoExceptionInformation: %s support SMART for device %x\n",
  3923. NT_SUCCESS(status) ? "does" : "does not",
  3924. FdoExtension->DeviceObject));
  3925. ExFreePool(modeData);
  3926. return(status);
  3927. }
  3928. NTSTATUS
  3929. DiskSetInfoExceptionInformation(
  3930. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  3931. IN PMODE_INFO_EXCEPTIONS PageData
  3932. )
  3933. {
  3934. ULONG i;
  3935. NTSTATUS status;
  3936. PAGED_CODE();
  3937. //
  3938. // We will attempt (twice) to issue the mode select with the page.
  3939. // Make the setting persistant so that we don't have to turn it back
  3940. // on after a bus reset.
  3941. //
  3942. for (i = 0; i < 2; i++)
  3943. {
  3944. status = DiskModeSelect(FdoExtension->DeviceObject,
  3945. (PUCHAR) PageData,
  3946. sizeof(MODE_INFO_EXCEPTIONS),
  3947. TRUE);
  3948. }
  3949. DebugPrint((3, "DiskSetInfoExceptionInformation: %s for device %p\n",
  3950. NT_SUCCESS(status) ? "succeeded" : "failed",
  3951. FdoExtension->DeviceObject));
  3952. return status;
  3953. }
  3954. NTSTATUS
  3955. DiskIoctlCreateDisk(
  3956. IN OUT PDEVICE_OBJECT DeviceObject,
  3957. IN OUT PIRP Irp
  3958. )
  3959. /*++
  3960. Routine Description:
  3961. Handler for IOCTL_DISK_CREATE_DISK ioctl.
  3962. Arguments:
  3963. DeviceObject - Device object representing a disk that will be created or
  3964. erased.
  3965. Irp - The IRP for this request.
  3966. Return Values:
  3967. NTSTATUS code.
  3968. --*/
  3969. {
  3970. NTSTATUS status;
  3971. PCOMMON_DEVICE_EXTENSION commonExtension;
  3972. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  3973. PIO_STACK_LOCATION irpStack;
  3974. PDISK_DATA diskData;
  3975. PCREATE_DISK createDiskInfo;
  3976. PAGED_CODE ();
  3977. ASSERT ( DeviceObject != NULL );
  3978. ASSERT ( Irp != NULL );
  3979. //
  3980. // Initialization
  3981. //
  3982. commonExtension = DeviceObject->DeviceExtension;
  3983. fdoExtension = DeviceObject->DeviceExtension;
  3984. irpStack = IoGetCurrentIrpStackLocation(Irp);
  3985. diskData = (PDISK_DATA)(commonExtension->DriverData);
  3986. ASSERT (commonExtension->IsFdo);
  3987. //
  3988. // Check the input buffer size.
  3989. //
  3990. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  3991. sizeof (CREATE_DISK) ) {
  3992. return STATUS_INFO_LENGTH_MISMATCH;
  3993. }
  3994. //
  3995. // If we are being asked to create a GPT disk on a system that doesn't
  3996. // support GPT, fail.
  3997. //
  3998. createDiskInfo = (PCREATE_DISK)Irp->AssociatedIrp.SystemBuffer;
  3999. if (DiskDisableGpt &&
  4000. createDiskInfo->PartitionStyle == PARTITION_STYLE_GPT) {
  4001. return STATUS_INVALID_PARAMETER;
  4002. }
  4003. //
  4004. // Call the lower level Io routine to do the dirty work of writing a
  4005. // new partition table.
  4006. //
  4007. DiskAcquirePartitioningLock(fdoExtension);
  4008. DiskInvalidatePartitionTable(fdoExtension, TRUE);
  4009. status = IoCreateDisk (
  4010. commonExtension->PartitionZeroExtension->CommonExtension.DeviceObject,
  4011. Irp->AssociatedIrp.SystemBuffer
  4012. );
  4013. DiskReleasePartitioningLock(fdoExtension);
  4014. ClassInvalidateBusRelations(DeviceObject);
  4015. Irp->IoStatus.Status = status;
  4016. return status;
  4017. }
  4018. NTSTATUS
  4019. DiskIoctlGetDriveLayout(
  4020. IN OUT PDEVICE_OBJECT DeviceObject,
  4021. IN OUT PIRP Irp
  4022. )
  4023. /*++
  4024. Routine Description:
  4025. Handler for IOCTL_DISK_GET_DRIVE_LAYOUT ioctl.
  4026. This ioctl has been replace by IOCTL_DISK_GET_DRIVE_LAYOUT_EX.
  4027. Arguments:
  4028. DeviceObject - Device object representing a disk the layout information
  4029. will be obtained for.
  4030. Irp - The IRP for this request.
  4031. Return Values:
  4032. NTSTATUS code.
  4033. --*/
  4034. {
  4035. NTSTATUS status;
  4036. ULONG size;
  4037. PDRIVE_LAYOUT_INFORMATION partitionList;
  4038. PDRIVE_LAYOUT_INFORMATION_EX partitionListEx;
  4039. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  4040. PPHYSICAL_DEVICE_EXTENSION pdoExtension;
  4041. PCOMMON_DEVICE_EXTENSION commonExtension;
  4042. PIO_STACK_LOCATION irpStack;
  4043. PDISK_DATA diskData;
  4044. BOOLEAN bUseCache = TRUE;
  4045. PAGED_CODE ();
  4046. ASSERT ( DeviceObject );
  4047. ASSERT ( Irp );
  4048. //
  4049. // Initialization
  4050. //
  4051. partitionListEx = NULL;
  4052. partitionList = NULL;
  4053. fdoExtension = DeviceObject->DeviceExtension;
  4054. commonExtension = DeviceObject->DeviceExtension;
  4055. irpStack = IoGetCurrentIrpStackLocation(Irp);
  4056. diskData = (PDISK_DATA)(commonExtension->DriverData);
  4057. //
  4058. // If our cached partition table is valid we do not need to touch the disk
  4059. //
  4060. if (diskData->CachedPartitionTableValid == FALSE)
  4061. {
  4062. //
  4063. // Issue a read capacity to update the apparent size of the disk.
  4064. //
  4065. DiskReadDriveCapacity(fdoExtension->DeviceObject);
  4066. bUseCache = FALSE;
  4067. }
  4068. DiskAcquirePartitioningLock(fdoExtension);
  4069. status = DiskReadPartitionTableEx(fdoExtension, FALSE, &partitionListEx);
  4070. if (!NT_SUCCESS(status)) {
  4071. DiskReleasePartitioningLock(fdoExtension);
  4072. return status;
  4073. }
  4074. //
  4075. // This ioctl is only supported on MBR partitioned disks. Fail the
  4076. // call otherwise.
  4077. //
  4078. if (partitionListEx->PartitionStyle != PARTITION_STYLE_MBR) {
  4079. DiskReleasePartitioningLock(fdoExtension);
  4080. return STATUS_INVALID_DEVICE_REQUEST;
  4081. }
  4082. //
  4083. // The disk layout has been returned in the partitionListEx
  4084. // buffer. Determine its size and, if the data will fit
  4085. // into the intermediate buffer, return it.
  4086. //
  4087. size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]);
  4088. size += partitionListEx->PartitionCount * sizeof(PARTITION_INFORMATION);
  4089. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  4090. size) {
  4091. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  4092. DiskReleasePartitioningLock(fdoExtension);
  4093. return STATUS_BUFFER_TOO_SMALL;
  4094. }
  4095. //
  4096. // Update the partition device objects and set valid partition numbers
  4097. //
  4098. ASSERT(diskData->UpdatePartitionRoutine != NULL);
  4099. diskData->UpdatePartitionRoutine(DeviceObject, partitionListEx);
  4100. //
  4101. // Convert the extended drive layout structure to a regular drive layout
  4102. // structure to return. DiskConvertExtendedToLayout() allocates pool
  4103. // that we must free.
  4104. //
  4105. partitionList = DiskConvertExtendedToLayout(partitionListEx);
  4106. if (partitionList == NULL) {
  4107. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4108. DiskReleasePartitioningLock (fdoExtension);
  4109. return STATUS_INSUFFICIENT_RESOURCES;
  4110. }
  4111. //
  4112. // We're done with the extended partition list now.
  4113. //
  4114. partitionListEx = NULL;
  4115. //
  4116. // Copy partition information to system buffer.
  4117. //
  4118. RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
  4119. partitionList,
  4120. size);
  4121. Irp->IoStatus.Information = size;
  4122. Irp->IoStatus.Status = status;
  4123. //
  4124. // Finally, free the buffer allocated by reading the
  4125. // partition table.
  4126. //
  4127. ExFreePool(partitionList);
  4128. DiskReleasePartitioningLock(fdoExtension);
  4129. if (bUseCache == FALSE)
  4130. {
  4131. ClassInvalidateBusRelations(DeviceObject);
  4132. }
  4133. return status;
  4134. }
  4135. NTSTATUS
  4136. DiskIoctlGetDriveLayoutEx(
  4137. IN OUT PDEVICE_OBJECT DeviceObject,
  4138. IN OUT PIRP Irp
  4139. )
  4140. /*++
  4141. Routine Description:
  4142. Handler for IOCTL_DISK_GET_DRIVE_LAYOUT_EX ioctl.
  4143. This ioctl replaces IOCTL_DISK_GET_DRIVE_LAYOUT.
  4144. Arguments:
  4145. DeviceObject - Device object representing a disk the layout information
  4146. will be obtained for.
  4147. Irp - The IRP for this request.
  4148. Return Values:
  4149. NTSTATUS code.
  4150. --*/
  4151. {
  4152. NTSTATUS status;
  4153. ULONG size;
  4154. PDRIVE_LAYOUT_INFORMATION_EX partitionList;
  4155. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  4156. PPHYSICAL_DEVICE_EXTENSION pdoExtension;
  4157. PCOMMON_DEVICE_EXTENSION commonExtension;
  4158. PIO_STACK_LOCATION irpStack;
  4159. PDISK_DATA diskData;
  4160. BOOLEAN bUseCache = TRUE;
  4161. PAGED_CODE ();
  4162. ASSERT ( DeviceObject );
  4163. ASSERT ( Irp );
  4164. //
  4165. // Initialization
  4166. //
  4167. fdoExtension = DeviceObject->DeviceExtension;
  4168. pdoExtension = DeviceObject->DeviceExtension;
  4169. commonExtension = DeviceObject->DeviceExtension;
  4170. irpStack = IoGetCurrentIrpStackLocation(Irp);
  4171. diskData = (PDISK_DATA)(commonExtension->DriverData);
  4172. //
  4173. // If our cached partition table is valid we do not need to touch the disk
  4174. //
  4175. if (diskData->CachedPartitionTableValid == FALSE)
  4176. {
  4177. //
  4178. // Issue a read capacity to update the apparent size of the disk.
  4179. //
  4180. DiskReadDriveCapacity(fdoExtension->DeviceObject);
  4181. bUseCache = FALSE;
  4182. }
  4183. DiskAcquirePartitioningLock (fdoExtension);
  4184. status = DiskReadPartitionTableEx (fdoExtension, FALSE, &partitionList);
  4185. if ( !NT_SUCCESS (status) ) {
  4186. DiskReleasePartitioningLock (fdoExtension);
  4187. return status;
  4188. }
  4189. size = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) +
  4190. partitionList->PartitionCount * sizeof (PARTITION_INFORMATION_EX);
  4191. //
  4192. // If the output buffer is large enough, copy data to the output buffer,
  4193. // otherwise, fail.
  4194. //
  4195. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  4196. size) {
  4197. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  4198. DiskReleasePartitioningLock(fdoExtension);
  4199. return STATUS_BUFFER_TOO_SMALL;
  4200. }
  4201. //
  4202. // Update the partition device objects and set valid partition numbers
  4203. //
  4204. ASSERT(diskData->UpdatePartitionRoutine != NULL);
  4205. diskData->UpdatePartitionRoutine(DeviceObject, partitionList);
  4206. RtlCopyMemory (Irp->AssociatedIrp.SystemBuffer,
  4207. partitionList,
  4208. size
  4209. );
  4210. Irp->IoStatus.Information = size;
  4211. Irp->IoStatus.Status = status;
  4212. DiskReleasePartitioningLock(fdoExtension);
  4213. if (bUseCache == FALSE)
  4214. {
  4215. ClassInvalidateBusRelations(DeviceObject);
  4216. }
  4217. return status;
  4218. }
  4219. NTSTATUS
  4220. DiskIoctlSetDriveLayout(
  4221. IN OUT PDEVICE_OBJECT DeviceObject,
  4222. IN OUT PIRP Irp
  4223. )
  4224. /*++
  4225. Routine Description:
  4226. Handler for IOCTL_DISK_SET_DRIVE_LAYOUT ioctl.
  4227. This ioctl has been replaced by IOCTL_DISK_SET_DRIVE_LAYOUT_EX.
  4228. Arguments:
  4229. DeviceObject - Device object for which partition table should be written.
  4230. Irp - IRP involved.
  4231. Return Values:
  4232. NTSTATUS code.
  4233. --*/
  4234. {
  4235. NTSTATUS status;
  4236. PDRIVE_LAYOUT_INFORMATION partitionList;
  4237. PDRIVE_LAYOUT_INFORMATION_EX partitionListEx;
  4238. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  4239. PPHYSICAL_DEVICE_EXTENSION pdoExtension;
  4240. PCOMMON_DEVICE_EXTENSION commonExtension;
  4241. PIO_STACK_LOCATION irpStack;
  4242. PDISK_DATA diskData;
  4243. BOOLEAN invalidateBusRelations;
  4244. SIZE_T listSize;
  4245. SIZE_T inputBufferLength;
  4246. SIZE_T outputBufferLength;
  4247. PAGED_CODE ();
  4248. ASSERT ( DeviceObject );
  4249. ASSERT ( Irp );
  4250. //
  4251. // Initialization
  4252. //
  4253. partitionListEx = NULL;
  4254. partitionList = NULL;
  4255. fdoExtension = DeviceObject->DeviceExtension;
  4256. pdoExtension = DeviceObject->DeviceExtension;
  4257. commonExtension = DeviceObject->DeviceExtension;
  4258. irpStack = IoGetCurrentIrpStackLocation(Irp);
  4259. diskData = (PDISK_DATA)(commonExtension->DriverData);
  4260. partitionList = Irp->AssociatedIrp.SystemBuffer;
  4261. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  4262. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  4263. //
  4264. // Update the partition table.
  4265. //
  4266. if (inputBufferLength < sizeof (DRIVE_LAYOUT_INFORMATION)) {
  4267. status = STATUS_INFO_LENGTH_MISMATCH;
  4268. return status;
  4269. }
  4270. DiskAcquirePartitioningLock(fdoExtension);
  4271. listSize = (partitionList->PartitionCount - 1);
  4272. listSize *= sizeof(PARTITION_INFORMATION);
  4273. listSize += sizeof(DRIVE_LAYOUT_INFORMATION);
  4274. if (inputBufferLength < listSize) {
  4275. //
  4276. // The remaning size of the input buffer not big enough to
  4277. // hold the additional partition entries
  4278. //
  4279. status = STATUS_INFO_LENGTH_MISMATCH;
  4280. DiskReleasePartitioningLock(fdoExtension);
  4281. return status;
  4282. }
  4283. //
  4284. // Convert the parititon information structure into an extended
  4285. // structure.
  4286. //
  4287. partitionListEx = DiskConvertLayoutToExtended (partitionList);
  4288. if ( partitionListEx == NULL ) {
  4289. status = STATUS_INSUFFICIENT_RESOURCES;
  4290. Irp->IoStatus.Status = status;
  4291. DiskReleasePartitioningLock(fdoExtension);
  4292. return status;
  4293. }
  4294. //
  4295. // Redo all the partition numbers in the partition information
  4296. //
  4297. ASSERT(diskData->UpdatePartitionRoutine != NULL);
  4298. diskData->UpdatePartitionRoutine(DeviceObject, partitionListEx);
  4299. //
  4300. // Write changes to disk.
  4301. //
  4302. status = DiskWritePartitionTableEx(fdoExtension, partitionListEx);
  4303. //
  4304. // Update IRP with bytes returned. Make sure we don't claim to be
  4305. // returning more bytes than the caller is expecting to get back.
  4306. //
  4307. if (NT_SUCCESS (status)) {
  4308. if (outputBufferLength < listSize) {
  4309. Irp->IoStatus.Information = outputBufferLength;
  4310. } else {
  4311. ULONG i;
  4312. Irp->IoStatus.Information = listSize;
  4313. //
  4314. // Also update the partition numbers.
  4315. //
  4316. for (i = 0; i < partitionList->PartitionCount; i++) {
  4317. PPARTITION_INFORMATION partition;
  4318. PPARTITION_INFORMATION_EX partitionEx;
  4319. partition = &partitionList->PartitionEntry[i];
  4320. partitionEx = &partitionListEx->PartitionEntry[i];
  4321. partition->PartitionNumber = partitionEx->PartitionNumber;
  4322. }
  4323. }
  4324. }
  4325. ExFreePool (partitionListEx);
  4326. DiskReleasePartitioningLock(fdoExtension);
  4327. ClassInvalidateBusRelations(DeviceObject);
  4328. Irp->IoStatus.Status = status;
  4329. return status;
  4330. }
  4331. NTSTATUS
  4332. DiskIoctlSetDriveLayoutEx(
  4333. IN OUT PDEVICE_OBJECT DeviceObject,
  4334. IN OUT PIRP Irp
  4335. )
  4336. /*++
  4337. Routine Description:
  4338. Handler for IOCTL_DISK_SET_DRIVE_LAYOUT_EX ioctl.
  4339. This ioctl replaces IOCTL_DISK_SET_DRIVE_LAYOUT.
  4340. Arguments:
  4341. DeviceObject - Device object for which partition table should be written.
  4342. Irp - IRP involved.
  4343. Return Values:
  4344. NTSTATUS code.
  4345. --*/
  4346. {
  4347. NTSTATUS status;
  4348. PDRIVE_LAYOUT_INFORMATION_EX partitionListEx;
  4349. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  4350. PCOMMON_DEVICE_EXTENSION commonExtension;
  4351. PIO_STACK_LOCATION irpStack;
  4352. PDISK_DATA diskData;
  4353. BOOLEAN invalidateBusRelations;
  4354. SIZE_T listSize;
  4355. SIZE_T inputBufferLength;
  4356. SIZE_T outputBufferLength;
  4357. PAGED_CODE ();
  4358. ASSERT ( DeviceObject );
  4359. ASSERT ( Irp );
  4360. //
  4361. // Initialization
  4362. //
  4363. partitionListEx = NULL;
  4364. fdoExtension = DeviceObject->DeviceExtension;
  4365. commonExtension = DeviceObject->DeviceExtension;
  4366. irpStack = IoGetCurrentIrpStackLocation(Irp);
  4367. diskData = (PDISK_DATA)(commonExtension->DriverData);
  4368. partitionListEx = Irp->AssociatedIrp.SystemBuffer;
  4369. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  4370. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  4371. //
  4372. // Update the partition table.
  4373. //
  4374. if (inputBufferLength <
  4375. FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry)) {
  4376. status = STATUS_INFO_LENGTH_MISMATCH;
  4377. return status;
  4378. }
  4379. DiskAcquirePartitioningLock(fdoExtension);
  4380. listSize = partitionListEx->PartitionCount;
  4381. listSize *= sizeof(PARTITION_INFORMATION_EX);
  4382. listSize += FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry);
  4383. if (inputBufferLength < listSize) {
  4384. //
  4385. // The remaning size of the input buffer not big enough to
  4386. // hold the additional partition entries
  4387. //
  4388. status = STATUS_INFO_LENGTH_MISMATCH;
  4389. DiskReleasePartitioningLock(fdoExtension);
  4390. return status;
  4391. }
  4392. //
  4393. // If the partition count is zero, this is a request to clear
  4394. // the partition table.
  4395. //
  4396. if (partitionListEx->PartitionCount == 0) {
  4397. CREATE_DISK CreateDiskInfo = { 0 };
  4398. CreateDiskInfo.PartitionStyle = diskData->PartitionStyle;
  4399. if (diskData->PartitionStyle == PARTITION_STYLE_MBR) {
  4400. CreateDiskInfo.Mbr.Signature = partitionListEx->Mbr.Signature;
  4401. } else {
  4402. ASSERT (diskData->PartitionStyle == PARTITION_STYLE_GPT);
  4403. CreateDiskInfo.Gpt.DiskId = partitionListEx->Gpt.DiskId;
  4404. //
  4405. // NB: Setting MaxPartitionCount to zero will
  4406. // force the GPT partition table writing code
  4407. // to use the default minimum for this value.
  4408. //
  4409. CreateDiskInfo.Gpt.MaxPartitionCount = 0;
  4410. }
  4411. DiskInvalidatePartitionTable(fdoExtension, TRUE);
  4412. status = IoCreateDisk(DeviceObject, &CreateDiskInfo);
  4413. } else {
  4414. //
  4415. // Redo all the partition numbers in the partition information
  4416. //
  4417. ASSERT(diskData->UpdatePartitionRoutine != NULL);
  4418. diskData->UpdatePartitionRoutine(DeviceObject, partitionListEx);
  4419. //
  4420. // Write changes to disk.
  4421. //
  4422. status = DiskWritePartitionTableEx(fdoExtension, partitionListEx);
  4423. }
  4424. //
  4425. // Update IRP with bytes returned. Make sure we don't claim to be
  4426. // returning more bytes than the caller is expecting to get back.
  4427. //
  4428. if (NT_SUCCESS(status)) {
  4429. if (outputBufferLength < listSize) {
  4430. Irp->IoStatus.Information = outputBufferLength;
  4431. } else {
  4432. Irp->IoStatus.Information = listSize;
  4433. }
  4434. }
  4435. DiskReleasePartitioningLock(fdoExtension);
  4436. ClassInvalidateBusRelations(DeviceObject);
  4437. Irp->IoStatus.Status = status;
  4438. return status;
  4439. }
  4440. NTSTATUS
  4441. DiskIoctlGetPartitionInfo(
  4442. IN OUT PDEVICE_OBJECT DeviceObject,
  4443. IN OUT PIRP Irp
  4444. )
  4445. /*++
  4446. Routine Description:
  4447. Handle the IOCTL_DISK_GET_PARTITION_INFO ioctl. Return the information
  4448. about the partition specified by the device object. Note that no
  4449. information is ever returned about the size or partition type of the
  4450. physical disk, as this doesn't make any sense.
  4451. This ioctl has been replaced by IOCTL_DISK_GET_PARTITION_INFO_EX.
  4452. Arguments:
  4453. DeviceObject -
  4454. Irp -
  4455. Return Values:
  4456. NTSTATUS code.
  4457. --*/
  4458. {
  4459. NTSTATUS status;
  4460. PIO_STACK_LOCATION irpStack;
  4461. PDISK_DATA diskData;
  4462. PPARTITION_INFORMATION partitionInfo;
  4463. PFUNCTIONAL_DEVICE_EXTENSION p0Extension;
  4464. PCOMMON_DEVICE_EXTENSION commonExtension;
  4465. PDISK_DATA partitionZeroData;
  4466. NTSTATUS oldReadyStatus;
  4467. PAGED_CODE ();
  4468. ASSERT ( DeviceObject );
  4469. ASSERT ( Irp );
  4470. //
  4471. // Initialization
  4472. //
  4473. commonExtension = DeviceObject->DeviceExtension;
  4474. irpStack = IoGetCurrentIrpStackLocation(Irp);
  4475. diskData = (PDISK_DATA)(commonExtension->DriverData);
  4476. p0Extension = commonExtension->PartitionZeroExtension;
  4477. partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData);
  4478. //
  4479. // Check that the buffer is large enough.
  4480. //
  4481. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  4482. sizeof(PARTITION_INFORMATION)) {
  4483. status = STATUS_BUFFER_TOO_SMALL;
  4484. return status;
  4485. }
  4486. //
  4487. // Update the geometry in case it has changed
  4488. //
  4489. status = DiskReadDriveCapacity(p0Extension->DeviceObject);
  4490. //
  4491. // Note whether the drive is ready. If the status has changed then
  4492. // notify pnp.
  4493. //
  4494. oldReadyStatus = InterlockedExchange(
  4495. &(partitionZeroData->ReadyStatus),
  4496. status);
  4497. if(partitionZeroData->ReadyStatus != oldReadyStatus) {
  4498. IoInvalidateDeviceRelations(p0Extension->LowerPdo,
  4499. BusRelations);
  4500. }
  4501. if(!NT_SUCCESS(status)) {
  4502. return status;
  4503. }
  4504. //
  4505. // Partition zero, the partition representing the entire disk, is
  4506. // special cased. The logic below allows for sending this ioctl to
  4507. // a GPT disk only for partition zero. This allows us to obtain
  4508. // the size of a GPT disk using Win2k compatible IOCTLs.
  4509. //
  4510. if (commonExtension->PartitionNumber == 0) {
  4511. partitionInfo = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  4512. partitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
  4513. partitionInfo->StartingOffset = commonExtension->StartingOffset;
  4514. partitionInfo->PartitionLength = commonExtension->PartitionLength;
  4515. partitionInfo->HiddenSectors = 0;
  4516. partitionInfo->PartitionNumber = commonExtension->PartitionNumber;
  4517. partitionInfo->BootIndicator = FALSE;
  4518. partitionInfo->RewritePartition = FALSE;
  4519. partitionInfo->RecognizedPartition = FALSE;
  4520. } else {
  4521. //
  4522. // We do not support this IOCTL on an EFI partitioned disk
  4523. // for any partition other than partition zero.
  4524. //
  4525. if (diskData->PartitionStyle != PARTITION_STYLE_MBR) {
  4526. status = STATUS_INVALID_DEVICE_REQUEST;
  4527. Irp->IoStatus.Status = status;
  4528. return status;
  4529. }
  4530. DiskEnumerateDevice(p0Extension->DeviceObject);
  4531. DiskAcquirePartitioningLock(p0Extension);
  4532. partitionInfo = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  4533. partitionInfo->PartitionType = diskData->Mbr.PartitionType;
  4534. partitionInfo->StartingOffset = commonExtension->StartingOffset;
  4535. partitionInfo->PartitionLength = commonExtension->PartitionLength;
  4536. partitionInfo->HiddenSectors = diskData->Mbr.HiddenSectors;
  4537. partitionInfo->PartitionNumber = commonExtension->PartitionNumber;
  4538. partitionInfo->BootIndicator = diskData->Mbr.BootIndicator;
  4539. partitionInfo->RewritePartition = FALSE;
  4540. partitionInfo->RecognizedPartition =
  4541. IsRecognizedPartition(diskData->Mbr.PartitionType);
  4542. DiskReleasePartitioningLock(p0Extension);
  4543. }
  4544. status = STATUS_SUCCESS;
  4545. Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
  4546. return status;
  4547. }
  4548. NTSTATUS
  4549. DiskIoctlGetPartitionInfoEx(
  4550. IN OUT PDEVICE_OBJECT DeviceObject,
  4551. IN OUT PIRP Irp
  4552. )
  4553. {
  4554. NTSTATUS status;
  4555. PIO_STACK_LOCATION irpStack;
  4556. PDISK_DATA diskData;
  4557. PPARTITION_INFORMATION_EX partitionInfo;
  4558. PFUNCTIONAL_DEVICE_EXTENSION p0Extension;
  4559. PCOMMON_DEVICE_EXTENSION commonExtension;
  4560. PDISK_DATA partitionZeroData;
  4561. NTSTATUS oldReadyStatus;
  4562. PAGED_CODE ();
  4563. ASSERT ( DeviceObject );
  4564. ASSERT ( Irp );
  4565. //
  4566. // Initialization
  4567. //
  4568. commonExtension = DeviceObject->DeviceExtension;
  4569. irpStack = IoGetCurrentIrpStackLocation(Irp);
  4570. diskData = (PDISK_DATA)(commonExtension->DriverData);
  4571. p0Extension = commonExtension->PartitionZeroExtension;
  4572. partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData);
  4573. //
  4574. // Check that the buffer is large enough.
  4575. //
  4576. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  4577. sizeof(PARTITION_INFORMATION_EX)) {
  4578. status = STATUS_BUFFER_TOO_SMALL;
  4579. Irp->IoStatus.Status = status;
  4580. return status;
  4581. }
  4582. //
  4583. // Update the geometry in case it has changed
  4584. //
  4585. status = DiskReadDriveCapacity(p0Extension->DeviceObject);
  4586. //
  4587. // Note whether the drive is ready. If the status has changed then
  4588. // notify pnp.
  4589. //
  4590. oldReadyStatus = InterlockedExchange(
  4591. &(partitionZeroData->ReadyStatus),
  4592. status);
  4593. if(partitionZeroData->ReadyStatus != oldReadyStatus) {
  4594. IoInvalidateDeviceRelations(p0Extension->LowerPdo,
  4595. BusRelations);
  4596. }
  4597. if(!NT_SUCCESS(status)) {
  4598. return status;
  4599. }
  4600. //
  4601. // If this is something other than partition 0 then do a
  4602. // re-enumeration to make sure we've got up-to-date information.
  4603. //
  4604. if(commonExtension->PartitionNumber != 0) {
  4605. DiskEnumerateDevice(p0Extension->DeviceObject);
  4606. DiskAcquirePartitioningLock(p0Extension);
  4607. }
  4608. partitionInfo = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer;
  4609. partitionInfo->StartingOffset = commonExtension->StartingOffset;
  4610. partitionInfo->PartitionLength = commonExtension->PartitionLength;
  4611. partitionInfo->RewritePartition = FALSE;
  4612. partitionInfo->PartitionNumber = commonExtension->PartitionNumber;
  4613. partitionInfo->PartitionStyle = diskData->PartitionStyle;
  4614. if ( diskData->PartitionStyle == PARTITION_STYLE_MBR ) {
  4615. partitionInfo->Mbr.PartitionType = diskData->Mbr.PartitionType;
  4616. partitionInfo->Mbr.HiddenSectors = diskData->Mbr.HiddenSectors;
  4617. partitionInfo->Mbr.BootIndicator = diskData->Mbr.BootIndicator;
  4618. partitionInfo->Mbr.RecognizedPartition =
  4619. IsRecognizedPartition(diskData->Mbr.PartitionType);
  4620. } else {
  4621. //
  4622. // ISSUE - 2000/02/09 - math: Review for Partition0.
  4623. // Is this correct for Partition0?
  4624. //
  4625. partitionInfo->Gpt.PartitionType = diskData->Efi.PartitionType;
  4626. partitionInfo->Gpt.PartitionId = diskData->Efi.PartitionId;
  4627. partitionInfo->Gpt.Attributes = diskData->Efi.Attributes;
  4628. RtlCopyMemory (
  4629. partitionInfo->Gpt.Name,
  4630. diskData->Efi.PartitionName,
  4631. sizeof (partitionInfo->Gpt.Name)
  4632. );
  4633. }
  4634. status = STATUS_SUCCESS;
  4635. Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
  4636. if(commonExtension->PartitionNumber != 0) {
  4637. DiskReleasePartitioningLock(p0Extension);
  4638. }
  4639. return status;
  4640. }
  4641. NTSTATUS
  4642. DiskIoctlGetLengthInfo(
  4643. IN OUT PDEVICE_OBJECT DeviceObject,
  4644. IN OUT PIRP Irp
  4645. )
  4646. {
  4647. NTSTATUS status;
  4648. PIO_STACK_LOCATION irpStack;
  4649. PDISK_DATA diskData;
  4650. PGET_LENGTH_INFORMATION lengthInfo;
  4651. PFUNCTIONAL_DEVICE_EXTENSION p0Extension;
  4652. PCOMMON_DEVICE_EXTENSION commonExtension;
  4653. PDISK_DATA partitionZeroData;
  4654. NTSTATUS oldReadyStatus;
  4655. PAGED_CODE ();
  4656. ASSERT ( DeviceObject );
  4657. ASSERT ( Irp );
  4658. //
  4659. // Initialization
  4660. //
  4661. commonExtension = DeviceObject->DeviceExtension;
  4662. irpStack = IoGetCurrentIrpStackLocation(Irp);
  4663. diskData = (PDISK_DATA)(commonExtension->DriverData);
  4664. p0Extension = commonExtension->PartitionZeroExtension;
  4665. partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData);
  4666. //
  4667. // Check that the buffer is large enough.
  4668. //
  4669. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  4670. sizeof(GET_LENGTH_INFORMATION)) {
  4671. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  4672. return STATUS_BUFFER_TOO_SMALL;
  4673. }
  4674. //
  4675. // Update the geometry in case it has changed
  4676. //
  4677. status = DiskReadDriveCapacity(p0Extension->DeviceObject);
  4678. //
  4679. // Note whether the drive is ready. If the status has changed then
  4680. // notify pnp.
  4681. //
  4682. oldReadyStatus = InterlockedExchange(
  4683. &(partitionZeroData->ReadyStatus),
  4684. status);
  4685. if(partitionZeroData->ReadyStatus != oldReadyStatus) {
  4686. IoInvalidateDeviceRelations(p0Extension->LowerPdo,
  4687. BusRelations);
  4688. }
  4689. if(!NT_SUCCESS(status)) {
  4690. return status;
  4691. }
  4692. //
  4693. // If this is something other than partition 0 then do a
  4694. // re-enumeration to make sure we've got up-to-date information.
  4695. //
  4696. if(commonExtension->PartitionNumber != 0) {
  4697. DiskEnumerateDevice(p0Extension->DeviceObject);
  4698. DiskAcquirePartitioningLock(p0Extension);
  4699. }
  4700. lengthInfo = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  4701. lengthInfo->Length = commonExtension->PartitionLength;
  4702. status = STATUS_SUCCESS;
  4703. Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
  4704. if(commonExtension->PartitionNumber != 0) {
  4705. DiskReleasePartitioningLock(p0Extension);
  4706. }
  4707. return status;
  4708. }
  4709. NTSTATUS
  4710. DiskIoctlSetPartitionInfo(
  4711. IN OUT PDEVICE_OBJECT DeviceObject,
  4712. IN OUT PIRP Irp
  4713. )
  4714. {
  4715. NTSTATUS status;
  4716. PSET_PARTITION_INFORMATION inputBuffer;
  4717. PDISK_DATA diskData;
  4718. PIO_STACK_LOCATION irpStack;
  4719. PCOMMON_DEVICE_EXTENSION commonExtension;
  4720. PAGED_CODE ();
  4721. ASSERT ( DeviceObject != NULL );
  4722. ASSERT ( Irp != NULL );
  4723. //
  4724. // Initialization
  4725. //
  4726. commonExtension = DeviceObject->DeviceExtension;
  4727. irpStack = IoGetCurrentIrpStackLocation(Irp);
  4728. diskData = (PDISK_DATA)(commonExtension->DriverData);
  4729. inputBuffer = (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  4730. if(commonExtension->IsFdo) {
  4731. return STATUS_UNSUCCESSFUL;
  4732. }
  4733. if (diskData->PartitionStyle != PARTITION_STYLE_MBR) {
  4734. return STATUS_INVALID_DEVICE_REQUEST;
  4735. }
  4736. //
  4737. // Validate buffer length
  4738. //
  4739. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  4740. sizeof(SET_PARTITION_INFORMATION)) {
  4741. return STATUS_INFO_LENGTH_MISMATCH;
  4742. }
  4743. DiskAcquirePartitioningLock(commonExtension->PartitionZeroExtension);
  4744. //
  4745. // The HAL routines IoGet- and IoSetPartitionInformation were
  4746. // developed before support of dynamic partitioning and therefore
  4747. // don't distinguish between partition ordinal (that is the order
  4748. // of a paritition on a disk) and the partition number. (The
  4749. // partition number is assigned to a partition to identify it to
  4750. // the system.) Use partition ordinals for these legacy calls.
  4751. //
  4752. status = DiskSetPartitionInformation(
  4753. commonExtension->PartitionZeroExtension,
  4754. commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector,
  4755. diskData->PartitionOrdinal,
  4756. inputBuffer->PartitionType);
  4757. if(NT_SUCCESS(status)) {
  4758. diskData->Mbr.PartitionType = inputBuffer->PartitionType;
  4759. }
  4760. DiskReleasePartitioningLock(commonExtension->PartitionZeroExtension);
  4761. return status;
  4762. }
  4763. NTSTATUS
  4764. DiskIoctlSetPartitionInfoEx(
  4765. IN OUT PDEVICE_OBJECT DeviceObject,
  4766. IN OUT PIRP Irp
  4767. )
  4768. {
  4769. NTSTATUS status;
  4770. PSET_PARTITION_INFORMATION_EX inputBuffer;
  4771. PDISK_DATA diskData;
  4772. PIO_STACK_LOCATION irpStack;
  4773. PCOMMON_DEVICE_EXTENSION commonExtension;
  4774. PAGED_CODE ();
  4775. ASSERT ( DeviceObject != NULL );
  4776. ASSERT ( Irp != NULL );
  4777. //
  4778. // Initialization
  4779. //
  4780. commonExtension = DeviceObject->DeviceExtension;
  4781. irpStack = IoGetCurrentIrpStackLocation(Irp);
  4782. diskData = (PDISK_DATA)(commonExtension->DriverData);
  4783. inputBuffer = (PSET_PARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
  4784. if(commonExtension->IsFdo) {
  4785. return STATUS_UNSUCCESSFUL;
  4786. }
  4787. //
  4788. // Validate buffer length
  4789. //
  4790. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  4791. sizeof(SET_PARTITION_INFORMATION_EX)) {
  4792. return STATUS_INFO_LENGTH_MISMATCH;
  4793. }
  4794. DiskAcquirePartitioningLock(commonExtension->PartitionZeroExtension);
  4795. //
  4796. // The HAL routines IoGet- and IoSetPartitionInformation were
  4797. // developed before support of dynamic partitioning and therefore
  4798. // don't distinguish between partition ordinal (that is the order
  4799. // of a paritition on a disk) and the partition number. (The
  4800. // partition number is assigned to a partition to identify it to
  4801. // the system.) Use partition ordinals for these legacy calls.
  4802. //
  4803. status = DiskSetPartitionInformationEx(
  4804. commonExtension->PartitionZeroExtension,
  4805. diskData->PartitionOrdinal,
  4806. inputBuffer
  4807. );
  4808. if(NT_SUCCESS(status)) {
  4809. if (diskData->PartitionStyle == PARTITION_STYLE_MBR) {
  4810. diskData->Mbr.PartitionType = inputBuffer->Mbr.PartitionType;
  4811. } else {
  4812. diskData->Efi.PartitionType = inputBuffer->Gpt.PartitionType;
  4813. diskData->Efi.PartitionId = inputBuffer->Gpt.PartitionId;
  4814. diskData->Efi.Attributes = inputBuffer->Gpt.Attributes;
  4815. RtlCopyMemory (
  4816. diskData->Efi.PartitionName,
  4817. inputBuffer->Gpt.Name,
  4818. sizeof (diskData->Efi.PartitionName)
  4819. );
  4820. }
  4821. }
  4822. DiskReleasePartitioningLock(commonExtension->PartitionZeroExtension);
  4823. return status;
  4824. }
  4825. typedef struct _DISK_GEOMETRY_EX_INTERNAL {
  4826. DISK_GEOMETRY Geometry;
  4827. LARGE_INTEGER DiskSize;
  4828. DISK_PARTITION_INFO Partition;
  4829. DISK_DETECTION_INFO Detection;
  4830. } DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL;
  4831. NTSTATUS
  4832. DiskIoctlGetDriveGeometryEx(
  4833. IN PDEVICE_OBJECT DeviceObject,
  4834. IN OUT PIRP Irp
  4835. )
  4836. /*++
  4837. Routine Description:
  4838. Obtain the extended geometry information for the drive.
  4839. Arguments:
  4840. DeviceObject - The device object to obtain the geometry for.
  4841. Irp - IRP with a return buffer large enough to receive the
  4842. extended geometry information.
  4843. Return Value:
  4844. NTSTATUS code
  4845. --*/
  4846. {
  4847. NTSTATUS status;
  4848. PIO_STACK_LOCATION irpStack;
  4849. PCOMMON_DEVICE_EXTENSION commonExtension;
  4850. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  4851. PDISK_DATA diskData;
  4852. PDISK_GEOMETRY_EX_INTERNAL geometryEx;
  4853. ULONG OutputBufferLength;
  4854. //
  4855. // Verification
  4856. //
  4857. PAGED_CODE ();
  4858. ASSERT ( DeviceObject != NULL );
  4859. ASSERT ( Irp != NULL );
  4860. //
  4861. // Setup parameters
  4862. //
  4863. commonExtension = DeviceObject->DeviceExtension;
  4864. fdoExtension = DeviceObject->DeviceExtension;
  4865. diskData = (PDISK_DATA)(commonExtension->DriverData);
  4866. irpStack = IoGetCurrentIrpStackLocation ( Irp );
  4867. geometryEx = NULL;
  4868. OutputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  4869. //
  4870. // This is only valid for the FDO.
  4871. //
  4872. ASSERT ( commonExtension->IsFdo );
  4873. //
  4874. // Check that the buffer is large enough. It must be large enough
  4875. // to hold at lest the Geometry and DiskSize fields of of the
  4876. // DISK_GEOMETRY_EX structure.
  4877. //
  4878. if ( OutputBufferLength < FIELD_OFFSET (DISK_GEOMETRY_EX, Data) ) {
  4879. //
  4880. // Buffer too small. Bail out, telling the caller the required
  4881. // size.
  4882. //
  4883. status = STATUS_BUFFER_TOO_SMALL;
  4884. return status;
  4885. }
  4886. if (TEST_FLAG (DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
  4887. //
  4888. // Issue a ReadCapacity to update device extension
  4889. // with information for the current media.
  4890. //
  4891. status = DiskReadDriveCapacity (
  4892. commonExtension->PartitionZeroExtension->DeviceObject);
  4893. diskData->ReadyStatus = status;
  4894. if (!NT_SUCCESS (status)) {
  4895. return status;
  4896. }
  4897. }
  4898. //
  4899. // Copy drive geometry.
  4900. //
  4901. geometryEx = (PDISK_GEOMETRY_EX_INTERNAL)Irp->AssociatedIrp.SystemBuffer;
  4902. geometryEx->Geometry = fdoExtension->DiskGeometry;
  4903. geometryEx->DiskSize = commonExtension->PartitionZeroExtension->CommonExtension.PartitionLength;
  4904. //
  4905. // If the user buffer is large enough to hold the partition information
  4906. // then add that as well.
  4907. //
  4908. if (OutputBufferLength >= FIELD_OFFSET (DISK_GEOMETRY_EX_INTERNAL, Detection)) {
  4909. geometryEx->Partition.SizeOfPartitionInfo = sizeof (geometryEx->Partition);
  4910. geometryEx->Partition.PartitionStyle = diskData->PartitionStyle;
  4911. switch ( diskData->PartitionStyle ) {
  4912. case PARTITION_STYLE_GPT:
  4913. //
  4914. // Copy GPT signature.
  4915. //
  4916. geometryEx->Partition.Gpt.DiskId = diskData->Efi.DiskId;
  4917. break;
  4918. case PARTITION_STYLE_MBR:
  4919. //
  4920. // Copy MBR signature and checksum.
  4921. //
  4922. geometryEx->Partition.Mbr.Signature = diskData->Mbr.Signature;
  4923. geometryEx->Partition.Mbr.CheckSum = diskData->Mbr.MbrCheckSum;
  4924. break;
  4925. default:
  4926. //
  4927. // This is a raw disk. Zero out the signature area so
  4928. // nobody gets confused.
  4929. //
  4930. RtlZeroMemory (
  4931. &geometryEx->Partition,
  4932. sizeof (geometryEx->Partition));
  4933. }
  4934. }
  4935. //
  4936. // If the buffer is large enough to hold the detection information,
  4937. // then also add that.
  4938. //
  4939. if (OutputBufferLength >= sizeof (DISK_GEOMETRY_EX_INTERNAL)) {
  4940. geometryEx->Detection.SizeOfDetectInfo =
  4941. sizeof (geometryEx->Detection);
  4942. status = DiskGetDetectInfo (
  4943. fdoExtension,
  4944. &geometryEx->Detection);
  4945. //
  4946. // Failed to obtain detection information, set to none.
  4947. //
  4948. if (!NT_SUCCESS (status)) {
  4949. geometryEx->Detection.DetectionType = DetectNone;
  4950. }
  4951. }
  4952. status = STATUS_SUCCESS;
  4953. Irp->IoStatus.Information = min (OutputBufferLength,
  4954. sizeof (DISK_GEOMETRY_EX_INTERNAL));
  4955. return status;
  4956. }