Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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