PageRenderTime 84ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/storage/class/disk_new/disk.c

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