[DRIVERS] Spelling fixes by Josh Soref. CORE-12286
[reactos.git] / reactos / drivers / storage / class / disk_new / disk.c
1 /*++
2
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4
5 Module Name:
6
7 disk.c
8
9 Abstract:
10
11 SCSI disk class driver
12
13 Environment:
14
15 kernel mode only
16
17 Notes:
18
19 Revision History:
20
21 --*/
22
23 #include "disk.h"
24
25 //
26 // Now instantiate the GUIDs
27 //
28
29 #include <initguid.h>
30 #include <ioevent.h>
31
32 NTSTATUS
33 NTAPI
34 DiskDetermineMediaTypes(
35 IN PDEVICE_OBJECT Fdo,
36 IN PIRP Irp,
37 IN UCHAR MediumType,
38 IN UCHAR DensityCode,
39 IN BOOLEAN MediaPresent,
40 IN BOOLEAN IsWritable
41 );
42
43 PPARTITION_INFORMATION_EX
44 NTAPI
45 DiskPdoFindPartitionEntry(
46 IN PPHYSICAL_DEVICE_EXTENSION Pdo,
47 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
48 );
49
50 PPARTITION_INFORMATION_EX
51 NTAPI
52 DiskFindAdjacentPartition(
53 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
54 IN PPARTITION_INFORMATION_EX BasePartition
55 );
56
57 PPARTITION_INFORMATION_EX
58 NTAPI
59 DiskFindContainingPartition(
60 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
61 IN PPARTITION_INFORMATION_EX BasePartition,
62 IN BOOLEAN SearchTopToBottom
63 );
64
65 NTSTATUS
66 NTAPI
67 DiskIoctlCreateDisk(
68 IN PDEVICE_OBJECT DeviceObject,
69 IN PIRP Irp
70 );
71
72 NTSTATUS
73 NTAPI
74 DiskIoctlGetDriveLayout(
75 IN PDEVICE_OBJECT DeviceObject,
76 IN PIRP Irp
77 );
78
79 NTSTATUS
80 NTAPI
81 DiskIoctlGetDriveLayoutEx(
82 IN PDEVICE_OBJECT DeviceObject,
83 IN PIRP Irp
84 );
85
86 NTSTATUS
87 NTAPI
88 DiskIoctlSetDriveLayout(
89 IN PDEVICE_OBJECT DeviceObject,
90 IN PIRP Irp
91 );
92
93 NTSTATUS
94 NTAPI
95 DiskIoctlSetDriveLayoutEx(
96 IN PDEVICE_OBJECT DeviceObject,
97 IN PIRP Irp
98 );
99
100 NTSTATUS
101 NTAPI
102 DiskIoctlGetPartitionInfo(
103 IN PDEVICE_OBJECT DeviceObject,
104 IN PIRP Irp
105 );
106
107 NTSTATUS
108 NTAPI
109 DiskIoctlGetPartitionInfoEx(
110 IN PDEVICE_OBJECT DeviceObject,
111 IN PIRP Irp
112 );
113
114 NTSTATUS
115 NTAPI
116 DiskIoctlGetLengthInfo(
117 IN PDEVICE_OBJECT DeviceObject,
118 IN PIRP Irp
119 );
120
121 NTSTATUS
122 NTAPI
123 DiskIoctlSetPartitionInfo(
124 IN PDEVICE_OBJECT DeviceObject,
125 IN PIRP Irp
126 );
127
128 NTSTATUS
129 NTAPI
130 DiskIoctlSetPartitionInfoEx(
131 IN PDEVICE_OBJECT DeviceObject,
132 IN PIRP Irp
133 );
134
135 NTSTATUS
136 NTAPI
137 DiskIoctlSetPartitionInfoEx(
138 IN PDEVICE_OBJECT DeviceObject,
139 IN PIRP Irp
140 );
141
142 NTSTATUS
143 NTAPI
144 DiskIoctlGetDriveGeometryEx(
145 IN PDEVICE_OBJECT DeviceObject,
146 IN PIRP Irp
147 );
148
149 #ifdef ALLOC_PRAGMA
150
151 #pragma alloc_text(INIT, DriverEntry)
152 #pragma alloc_text(PAGE, DiskUnload)
153 #pragma alloc_text(PAGE, DiskCreateFdo)
154 #pragma alloc_text(PAGE, DiskDetermineMediaTypes)
155 #pragma alloc_text(PAGE, DiskModeSelect)
156 #pragma alloc_text(PAGE, DisableWriteCache)
157 #pragma alloc_text(PAGE, DiskIoctlVerify)
158 #pragma alloc_text(PAGE, DiskSetSpecialHacks)
159 #pragma alloc_text(PAGE, DiskScanRegistryForSpecial)
160 #pragma alloc_text(PAGE, DiskQueryPnpCapabilities)
161 #pragma alloc_text(PAGE, DiskGetCacheInformation)
162 #pragma alloc_text(PAGE, DiskSetCacheInformation)
163 #pragma alloc_text(PAGE, DiskSetInfoExceptionInformation)
164 #pragma alloc_text(PAGE, DiskGetInfoExceptionInformation)
165
166 #pragma alloc_text(PAGE, DiskPdoFindPartitionEntry)
167 #pragma alloc_text(PAGE, DiskFindAdjacentPartition)
168 #pragma alloc_text(PAGE, DiskFindContainingPartition)
169
170 #pragma alloc_text(PAGE, DiskIoctlCreateDisk)
171 #pragma alloc_text(PAGE, DiskIoctlGetDriveLayout)
172 #pragma alloc_text(PAGE, DiskIoctlGetDriveLayoutEx)
173 #pragma alloc_text(PAGE, DiskIoctlSetDriveLayout)
174 #pragma alloc_text(PAGE, DiskIoctlSetDriveLayoutEx)
175 #pragma alloc_text(PAGE, DiskIoctlGetPartitionInfo)
176 #pragma alloc_text(PAGE, DiskIoctlGetPartitionInfoEx)
177 #pragma alloc_text(PAGE, DiskIoctlGetLengthInfo)
178 #pragma alloc_text(PAGE, DiskIoctlSetPartitionInfo)
179 #pragma alloc_text(PAGE, DiskIoctlSetPartitionInfoEx)
180 #pragma alloc_text(PAGE, DiskIoctlGetDriveGeometryEx)
181 #endif
182
183 extern ULONG DiskDisableGpt;
184
185 const GUID GUID_NULL = { 0 };
186 #define DiskCompareGuid(_First,_Second) \
187 (memcmp ((_First),(_Second), sizeof (GUID)))
188
189 NTSTATUS
190 NTAPI
191 DriverEntry(
192 IN PDRIVER_OBJECT DriverObject,
193 IN PUNICODE_STRING RegistryPath
194 )
195
196 /*++
197
198 Routine Description:
199
200 This routine initializes the SCSI hard disk class driver.
201
202 Arguments:
203
204 DriverObject - Pointer to driver object created by system.
205
206 RegistryPath - Pointer to the name of the services node for this driver.
207
208 Return Value:
209
210 The function value is the final status from the initialization operation.
211
212 --*/
213
214 {
215 CLASS_INIT_DATA InitializationData;
216 CLASS_QUERY_WMI_REGINFO_EX_LIST classQueryWmiRegInfoExList;
217 GUID guidQueryRegInfoEx = GUID_CLASSPNP_QUERY_REGINFOEX;
218
219 NTSTATUS status;
220
221 #if defined(_X86_)
222 //
223 // Read the information NtDetect squirreled away about the disks in this
224 // system.
225 //
226
227 status = DiskSaveDetectInfo(DriverObject);
228
229 if(!NT_SUCCESS(status)) {
230 DebugPrint((1, "Disk: couldn't save NtDetect information (%#08lx)\n",
231 status));
232 }
233 #endif
234
235 //
236 // Zero InitData
237 //
238
239 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
240
241 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
242
243 //
244 // Setup sizes and entry points for functional device objects
245 //
246
247 InitializationData.FdoData.DeviceExtensionSize = FUNCTIONAL_EXTENSION_SIZE;
248 InitializationData.FdoData.DeviceType = FILE_DEVICE_DISK;
249 InitializationData.FdoData.DeviceCharacteristics = FILE_DEVICE_SECURE_OPEN;
250
251 InitializationData.FdoData.ClassInitDevice = DiskInitFdo;
252 InitializationData.FdoData.ClassStartDevice = DiskStartFdo;
253 InitializationData.FdoData.ClassStopDevice = DiskStopDevice;
254 InitializationData.FdoData.ClassRemoveDevice = DiskRemoveDevice;
255 InitializationData.FdoData.ClassPowerDevice = ClassSpinDownPowerHandler;
256
257 InitializationData.FdoData.ClassError = DiskFdoProcessError;
258 InitializationData.FdoData.ClassReadWriteVerification = DiskReadWriteVerification;
259 InitializationData.FdoData.ClassDeviceControl = DiskDeviceControl;
260 InitializationData.FdoData.ClassShutdownFlush = DiskShutdownFlush;
261 InitializationData.FdoData.ClassCreateClose = NULL;
262
263 //
264 // Setup sizes and entry points for physical device objects
265 //
266
267 InitializationData.PdoData.DeviceExtensionSize = PHYSICAL_EXTENSION_SIZE;
268 InitializationData.PdoData.DeviceType = FILE_DEVICE_DISK;
269 InitializationData.PdoData.DeviceCharacteristics = FILE_DEVICE_SECURE_OPEN;
270
271 InitializationData.PdoData.ClassInitDevice = DiskInitPdo;
272 InitializationData.PdoData.ClassStartDevice = DiskStartPdo;
273 InitializationData.PdoData.ClassStopDevice = DiskStopDevice;
274 InitializationData.PdoData.ClassRemoveDevice = DiskRemoveDevice;
275
276 //
277 // Use default power routine for PDOs
278 //
279
280 InitializationData.PdoData.ClassPowerDevice = NULL;
281
282 InitializationData.PdoData.ClassError = NULL;
283 InitializationData.PdoData.ClassReadWriteVerification = DiskReadWriteVerification;
284 InitializationData.PdoData.ClassDeviceControl = DiskDeviceControl;
285 InitializationData.PdoData.ClassShutdownFlush = DiskShutdownFlush;
286 InitializationData.PdoData.ClassCreateClose = NULL;
287
288 InitializationData.PdoData.ClassDeviceControl = DiskDeviceControl;
289
290 InitializationData.PdoData.ClassQueryPnpCapabilities = DiskQueryPnpCapabilities;
291
292 InitializationData.ClassAddDevice = DiskAddDevice;
293 InitializationData.ClassEnumerateDevice = DiskEnumerateDevice;
294
295 InitializationData.ClassQueryId = DiskQueryId;
296
297
298 InitializationData.FdoData.ClassWmiInfo.GuidCount = 7;
299 InitializationData.FdoData.ClassWmiInfo.GuidRegInfo = DiskWmiFdoGuidList;
300 InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiRegInfo = DiskFdoQueryWmiRegInfo;
301 InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiDataBlock = DiskFdoQueryWmiDataBlock;
302 InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataBlock = DiskFdoSetWmiDataBlock;
303 InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataItem = DiskFdoSetWmiDataItem;
304 InitializationData.FdoData.ClassWmiInfo.ClassExecuteWmiMethod = DiskFdoExecuteWmiMethod;
305 InitializationData.FdoData.ClassWmiInfo.ClassWmiFunctionControl = DiskWmiFunctionControl;
306
307
308 #if 0
309 //
310 // Enable this to add WMI support for PDOs
311 InitializationData.PdoData.ClassWmiInfo.GuidCount = 1;
312 InitializationData.PdoData.ClassWmiInfo.GuidRegInfo = DiskWmiPdoGuidList;
313 InitializationData.PdoData.ClassWmiInfo.ClassQueryWmiRegInfo = DiskPdoQueryWmiRegInfo;
314 InitializationData.PdoData.ClassWmiInfo.ClassQueryWmiDataBlock = DiskPdoQueryWmiDataBlock;
315 InitializationData.PdoData.ClassWmiInfo.ClassSetWmiDataBlock = DiskPdoSetWmiDataBlock;
316 InitializationData.PdoData.ClassWmiInfo.ClassSetWmiDataItem = DiskPdoSetWmiDataItem;
317 InitializationData.PdoData.ClassWmiInfo.ClassExecuteWmiMethod = DiskPdoExecuteWmiMethod;
318 InitializationData.PdoData.ClassWmiInfo.ClassWmiFunctionControl = DiskWmiFunctionControl;
319 #endif
320
321 InitializationData.ClassUnload = DiskUnload;
322
323 //
324 // Initialize regregistration data structures
325 //
326
327 DiskInitializeReregistration();
328
329 //
330 // Call the class init routine
331 //
332
333 status = ClassInitialize( DriverObject, RegistryPath, &InitializationData);
334
335 #if defined(_X86_)
336 if(NT_SUCCESS(status)) {
337 IoRegisterBootDriverReinitialization(DriverObject,
338 DiskDriverReinitialization,
339 NULL);
340 }
341 #endif
342
343 //
344 // Call class init Ex routine to register a
345 // PCLASS_QUERY_WMI_REGINFO_EX routine
346 //
347 RtlZeroMemory(&classQueryWmiRegInfoExList, sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST));
348 classQueryWmiRegInfoExList.Size = sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST);
349 classQueryWmiRegInfoExList.ClassFdoQueryWmiRegInfoEx = DiskFdoQueryWmiRegInfoEx;
350
351 ClassInitializeEx(DriverObject,
352 &guidQueryRegInfoEx,
353 &classQueryWmiRegInfoExList);
354
355 return status;
356
357 } // end DriverEntry()
358
359 VOID
360 NTAPI
361 DiskUnload(
362 IN PDRIVER_OBJECT DriverObject
363 )
364 {
365 PAGED_CODE();
366
367 #if defined(_X86_)
368 DiskCleanupDetectInfo(DriverObject);
369 #endif
370 return;
371 }
372
373 NTSTATUS
374 NTAPI
375 DiskCreateFdo(
376 IN PDRIVER_OBJECT DriverObject,
377 IN PDEVICE_OBJECT PhysicalDeviceObject,
378 IN PULONG DeviceCount,
379 IN BOOLEAN DasdAccessOnly
380 )
381
382 /*++
383
384 Routine Description:
385
386 This routine creates an object for the functional device
387
388 Arguments:
389
390 DriverObject - Pointer to driver object created by system.
391
392 PhysicalDeviceObject - Lower level driver we should attach to
393
394 DeviceCount - Number of previously installed devices.
395
396 DasdAccessOnly - indicates whether or not a file system is allowed to mount
397 on this device object. Used to avoid double-mounting of
398 file systems on super-floppies (which can unfortunately be
399 fixed disks). If set the i/o system will only allow rawfs
400 to be mounted.
401
402 Return Value:
403
404 NTSTATUS
405
406 --*/
407
408 {
409 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
410 //STRING ntNameString;
411 //UNICODE_STRING ntUnicodeString;
412
413 PUCHAR deviceName = NULL;
414
415 OBJECT_ATTRIBUTES objectAttributes;
416 HANDLE handle;
417
418 NTSTATUS status;
419
420 PDEVICE_OBJECT lowerDevice = NULL;
421 PDEVICE_OBJECT deviceObject = NULL;
422
423 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
424 //STORAGE_PROPERTY_ID propertyId;
425 //PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
426
427 PAGED_CODE();
428
429 *DeviceCount = 0;
430
431 //
432 // Set up an object directory to contain the objects for this
433 // device and all its partitions.
434 //
435
436 do {
437
438 WCHAR buffer[64];
439 UNICODE_STRING unicodeDirectoryName;
440
441 swprintf(buffer, L"\\Device\\Harddisk%d", *DeviceCount);
442
443 RtlInitUnicodeString(&unicodeDirectoryName, buffer);
444
445 InitializeObjectAttributes(&objectAttributes,
446 &unicodeDirectoryName,
447 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
448 NULL,
449 NULL);
450
451 status = ZwCreateDirectoryObject(&handle,
452 DIRECTORY_ALL_ACCESS,
453 &objectAttributes);
454
455 (*DeviceCount)++;
456
457 } while((status == STATUS_OBJECT_NAME_COLLISION) ||
458 (status == STATUS_OBJECT_NAME_EXISTS));
459
460 if (!NT_SUCCESS(status)) {
461
462 DebugPrint((1, "DiskCreateFdo: Could not create directory - %lx\n",
463 status));
464
465 return(status);
466 }
467
468 //
469 // When this loop exits the count is inflated by one - fix that.
470 //
471
472 (*DeviceCount)--;
473
474 //
475 // Claim the device.
476 //
477
478 lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
479
480 status = ClassClaimDevice(lowerDevice, FALSE);
481
482 if (!NT_SUCCESS(status)) {
483 ZwMakeTemporaryObject(handle);
484 ZwClose(handle);
485 ObDereferenceObject(lowerDevice);
486 return status;
487 }
488
489 //
490 // Create a device object for this device. Each physical disk will
491 // have at least one device object. The required device object
492 // describes the entire device. Its directory path is
493 // \Device\HarddiskN\Partition0, where N = device number.
494 //
495
496 status = DiskGenerateDeviceName(TRUE,
497 *DeviceCount,
498 0,
499 NULL,
500 NULL,
501 &deviceName);
502
503 if(!NT_SUCCESS(status)) {
504 DebugPrint((1, "DiskCreateFdo - couldn't create name %lx\n",
505 status));
506
507 goto DiskCreateFdoExit;
508
509 }
510
511 status = ClassCreateDeviceObject(DriverObject,
512 deviceName,
513 PhysicalDeviceObject,
514 TRUE,
515 &deviceObject);
516
517 if (!NT_SUCCESS(status)) {
518
519 DebugPrint((1,
520 "DiskCreateFdo: Can not create device object %s\n",
521 ntNameBuffer));
522
523 goto DiskCreateFdoExit;
524 }
525
526 //
527 // Indicate that IRPs should include MDLs for data transfers.
528 //
529
530 SET_FLAG(deviceObject->Flags, DO_DIRECT_IO);
531
532 fdoExtension = deviceObject->DeviceExtension;
533
534 if(DasdAccessOnly) {
535
536 //
537 // Indicate that only RAW should be allowed to mount on the root
538 // partition object. This ensures that a file system can't doubly
539 // mount on a super-floppy by mounting once on P0 and once on P1.
540 //
541
542 SET_FLAG(deviceObject->Vpb->Flags, VPB_RAW_MOUNT);
543 }
544
545 //
546 // Initialize lock count to zero. The lock count is used to
547 // disable the ejection mechanism on devices that support
548 // removable media. Only the lock count in the physical
549 // device extension is used.
550 //
551
552 fdoExtension->LockCount = 0;
553
554 //
555 // Save system disk number.
556 //
557
558 fdoExtension->DeviceNumber = *DeviceCount;
559
560 //
561 // Set the alignment requirements for the device based on the
562 // host adapter requirements
563 //
564
565 if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
566 deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
567 }
568
569 //
570 // Finally, attach to the pdo
571 //
572
573 fdoExtension->LowerPdo = PhysicalDeviceObject;
574
575 fdoExtension->CommonExtension.LowerDeviceObject =
576 IoAttachDeviceToDeviceStack(
577 deviceObject,
578 PhysicalDeviceObject);
579
580 if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
581
582 //
583 // Uh - oh, we couldn't attach
584 // cleanup and return
585 //
586
587 status = STATUS_UNSUCCESSFUL;
588 goto DiskCreateFdoExit;
589 }
590
591 {
592 PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
593
594 //
595 // Initialize the partitioning lock as it may be used in the remove
596 // code.
597 //
598
599 KeInitializeEvent(&(diskData->PartitioningEvent),
600 SynchronizationEvent,
601 TRUE);
602 }
603
604
605 //
606 // Clear the init flag.
607 //
608
609 CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING);
610
611 //
612 // Store a handle to the device object directory for this disk
613 //
614
615 fdoExtension->DeviceDirectory = handle;
616
617 ObDereferenceObject(lowerDevice);
618
619 return STATUS_SUCCESS;
620
621 DiskCreateFdoExit:
622
623 //
624 // Release the device since an error occurred.
625 //
626
627 if (deviceObject != NULL) {
628 IoDeleteDevice(deviceObject);
629 }
630
631 //
632 // Delete directory and return.
633 //
634
635 if (!NT_SUCCESS(status)) {
636 ZwMakeTemporaryObject(handle);
637 ZwClose(handle);
638 }
639
640 ObDereferenceObject(lowerDevice);
641
642 return(status);
643 }
644
645 NTSTATUS
646 NTAPI
647 DiskReadWriteVerification(
648 IN PDEVICE_OBJECT DeviceObject,
649 IN PIRP Irp
650 )
651
652 /*++
653
654 Routine Description:
655
656 I/O System entry for read and write requests to SCSI disks.
657
658 Arguments:
659
660 DeviceObject - Pointer to driver object created by system.
661 Irp - IRP involved.
662
663 Return Value:
664
665 NT Status
666
667 --*/
668
669 {
670 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
671
672 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
673 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
674 LARGE_INTEGER startingOffset;
675
676 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
677 commonExtension->PartitionZeroExtension;
678
679 ULONG residualBytes;
680 NTSTATUS status;
681
682 //
683 // Verify parameters of this request.
684 // Check that ending sector is within partition and
685 // that number of bytes to transfer is a multiple of
686 // the sector size.
687 //
688
689 startingOffset.QuadPart =
690 (currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
691 transferByteCount);
692
693 residualBytes = transferByteCount &
694 (fdoExtension->DiskGeometry.BytesPerSector - 1);
695
696
697 if ((startingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
698 (residualBytes != 0)) {
699
700 //
701 // This error may be caused by the fact that the drive is not ready.
702 //
703
704 status = ((PDISK_DATA) commonExtension->DriverData)->ReadyStatus;
705
706 if (!NT_SUCCESS(status)) {
707
708 //
709 // Flag this as a user error so that a popup is generated.
710 //
711
712 DebugPrint((1, "DiskReadWriteVerification: ReadyStatus is %lx\n",
713 status));
714
715 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
716
717 //
718 // status will keep the current error
719 //
720
721 ASSERT( status != STATUS_INSUFFICIENT_RESOURCES );
722
723 } else if((commonExtension->IsFdo == TRUE) && (residualBytes == 0)) {
724
725 //
726 // This failed because we think the physical disk is too small.
727 // Send it down to the drive and let the hardware decide for
728 // itself.
729 //
730
731 status = STATUS_SUCCESS;
732
733 } else {
734
735 //
736 // Note fastfat depends on this parameter to determine when to
737 // remount due to a sector size change.
738 //
739
740 status = STATUS_INVALID_PARAMETER;
741
742 }
743
744 } else {
745
746 //
747 // the drive is ready, so ok the read/write
748 //
749
750 status = STATUS_SUCCESS;
751
752 }
753
754 Irp->IoStatus.Status = status;
755 return status;
756
757 } // end DiskReadWrite()
758
759 NTSTATUS
760 NTAPI
761 DiskDetermineMediaTypes(
762 IN PDEVICE_OBJECT Fdo,
763 IN PIRP Irp,
764 IN UCHAR MediumType,
765 IN UCHAR DensityCode,
766 IN BOOLEAN MediaPresent,
767 IN BOOLEAN IsWritable
768 )
769
770 /*++
771
772 Routine Description:
773
774 Determines number of types based on the physical device, validates the user buffer
775 and builds the MEDIA_TYPE information.
776
777 Arguments:
778
779 DeviceObject - Pointer to functional device object created by system.
780 Irp - IOCTL_STORAGE_GET_MEDIA_TYPES_EX Irp.
781 MediumType - byte returned in mode data header.
782 DensityCode - byte returned in mode data block descriptor.
783 NumberOfTypes - pointer to be updated based on actual device.
784
785 Return Value:
786
787 Status is returned.
788
789 --*/
790
791 {
792 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
793 //PPHYSICAL_DEVICE_EXTENSION pdoExtension = Fdo->DeviceExtension;
794 //PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
795 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
796
797 PGET_MEDIA_TYPES mediaTypes = Irp->AssociatedIrp.SystemBuffer;
798 PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
799 BOOLEAN deviceMatched = FALSE;
800
801 PAGED_CODE();
802
803 //
804 // this should be checked prior to calling into this routine
805 // as we use the buffer as mediaTypes
806 //
807 ASSERT(irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
808 sizeof(GET_MEDIA_TYPES));
809
810
811 //
812 // Determine if this device is removable or fixed.
813 //
814
815 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
816
817 //
818 // Fixed disk.
819 //
820
821 mediaTypes->DeviceType = FILE_DEVICE_DISK;
822 mediaTypes->MediaInfoCount = 1;
823
824 mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
825 mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
826 mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
827 mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
828 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
829
830 mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE);
831
832 if (!IsWritable) {
833 SET_FLAG(mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics,
834 MEDIA_WRITE_PROTECTED);
835 }
836
837 mediaInfo->DeviceSpecific.DiskInfo.MediaType = FixedMedia;
838
839
840 } else {
841
842 PUCHAR vendorId = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->VendorIdOffset;
843 PUCHAR productId = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductIdOffset;
844 PUCHAR productRevision = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductRevisionOffset;
845 DISK_MEDIA_TYPES_LIST const *mediaListEntry;
846 ULONG currentMedia;
847 ULONG i;
848 ULONG j;
849 ULONG sizeNeeded;
850
851 DebugPrint((1,
852 "DiskDetermineMediaTypes: Vendor %s, Product %s\n",
853 vendorId,
854 productId));
855
856 //
857 // Run through the list until we find the entry with a NULL Vendor Id.
858 //
859
860 for (i = 0; DiskMediaTypes[i].VendorId != NULL; i++) {
861
862 mediaListEntry = &DiskMediaTypes[i];
863
864 if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) {
865 continue;
866 }
867
868 if ((mediaListEntry->ProductId != NULL) &&
869 strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) {
870 continue;
871 }
872
873 if ((mediaListEntry->Revision != NULL) &&
874 strncmp(mediaListEntry->Revision, productRevision, strlen(mediaListEntry->Revision))) {
875 continue;
876 }
877
878 deviceMatched = TRUE;
879
880 mediaTypes->DeviceType = FILE_DEVICE_DISK;
881 mediaTypes->MediaInfoCount = mediaListEntry->NumberOfTypes;
882
883 //
884 // Ensure that buffer is large enough.
885 //
886
887 sizeNeeded = FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) +
888 (mediaListEntry->NumberOfTypes *
889 sizeof(DEVICE_MEDIA_INFO)
890 );
891
892 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
893 sizeNeeded) {
894
895 //
896 // Buffer too small
897 //
898
899 Irp->IoStatus.Information = sizeNeeded;
900 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
901 return STATUS_BUFFER_TOO_SMALL;
902 }
903
904 for (j = 0; j < mediaListEntry->NumberOfTypes; j++) {
905
906 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
907 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
908 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
909 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
910 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = mediaListEntry->NumberOfSides;
911
912 //
913 // Set the type.
914 //
915
916 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = mediaListEntry->MediaTypes[j];
917
918 if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == MO_5_WO) {
919 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_WRITE_ONCE;
920 } else {
921 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
922 }
923
924 //
925 // Status will either be success, if media is present, or no media.
926 // It would be optimal to base from density code and medium type, but not all devices
927 // have values for these fields.
928 //
929
930 if (MediaPresent) {
931
932 //
933 // The usage of MediumType and DensityCode is device specific, so this may need
934 // to be extended to further key off of product/vendor ids.
935 // Currently, the MO units are the only devices that return this information.
936 //
937
938 if (MediumType == 2) {
939 currentMedia = MO_5_WO;
940 } else if (MediumType == 3) {
941 currentMedia = MO_5_RW;
942
943 if (DensityCode == 0x87) {
944
945 //
946 // Indicate that the pinnacle 4.6 G media
947 // is present. Other density codes will default to normal
948 // RW MO media.
949 //
950
951 currentMedia = PINNACLE_APEX_5_RW;
952 }
953 } else {
954 currentMedia = 0;
955 }
956
957 if (currentMedia) {
958 if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == (STORAGE_MEDIA_TYPE)currentMedia) {
959 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
960 }
961
962 } else {
963 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
964 }
965 }
966
967 if (!IsWritable) {
968 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED);
969 }
970
971 //
972 // Advance to next entry.
973 //
974
975 mediaInfo++;
976 }
977 }
978
979 if (!deviceMatched) {
980
981 DebugPrint((1,
982 "DiskDetermineMediaTypes: Unknown device. Vendor: %s Product: %s Revision: %s\n",
983 vendorId,
984 productId,
985 productRevision));
986 //
987 // Build an entry for unknown.
988 //
989
990 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
991 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
992 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
993 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
994
995 //
996 // Set the type.
997 //
998
999 mediaTypes->DeviceType = FILE_DEVICE_DISK;
1000 mediaTypes->MediaInfoCount = 1;
1001
1002 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia;
1003 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
1004
1005 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
1006 if (MediaPresent) {
1007 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
1008 }
1009
1010 if (!IsWritable) {
1011 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED);
1012 }
1013 }
1014 }
1015
1016 Irp->IoStatus.Information =
1017 FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) +
1018 (mediaTypes->MediaInfoCount * sizeof(DEVICE_MEDIA_INFO));
1019
1020 return STATUS_SUCCESS;
1021
1022 }
1023
1024 NTSTATUS
1025 NTAPI
1026 DiskDeviceControl(
1027 PDEVICE_OBJECT DeviceObject,
1028 PIRP Irp
1029 )
1030
1031 /*++
1032
1033 Routine Description:
1034
1035 I/O system entry for device controls to SCSI disks.
1036
1037 Arguments:
1038
1039 Fdo - Pointer to functional device object created by system.
1040 Irp - IRP involved.
1041
1042 Return Value:
1043
1044 Status is returned.
1045
1046 --*/
1047
1048 #define SendToFdo(Dev, Irp, Rval) { \
1049 PCOMMON_DEVICE_EXTENSION ce = Dev->DeviceExtension; \
1050 ASSERT_PDO(Dev); \
1051 IoCopyCurrentIrpStackLocationToNext(Irp); \
1052 Rval = IoCallDriver(ce->LowerDeviceObject, Irp); \
1053 }
1054
1055 {
1056 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1057 //PPHYSICAL_DEVICE_EXTENSION pdoExtension = DeviceObject->DeviceExtension;
1058 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1059
1060 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1061 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
1062 PSCSI_REQUEST_BLOCK srb;
1063 PCDB cdb;
1064 PMODE_PARAMETER_HEADER modeData;
1065 PIRP irp2;
1066 ULONG length;
1067 NTSTATUS status;
1068 KEVENT event;
1069 IO_STATUS_BLOCK ioStatus;
1070
1071 BOOLEAN b = FALSE;
1072
1073 srb = ExAllocatePoolWithTag(NonPagedPool,
1074 SCSI_REQUEST_BLOCK_SIZE,
1075 DISK_TAG_SRB);
1076 Irp->IoStatus.Information = 0;
1077
1078 if (srb == NULL) {
1079
1080 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1081 ClassReleaseRemoveLock(DeviceObject, Irp);
1082 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1083 return(STATUS_INSUFFICIENT_RESOURCES);
1084 }
1085
1086 //
1087 // Write zeros to Srb.
1088 //
1089
1090 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1091
1092 cdb = (PCDB)srb->Cdb;
1093
1094 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
1095
1096 case IOCTL_DISK_GET_CACHE_INFORMATION:
1097 b = TRUE;
1098 case IOCTL_DISK_SET_CACHE_INFORMATION: {
1099
1100 BOOLEAN getCaching = b;
1101 PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer;
1102
1103 if(!commonExtension->IsFdo) {
1104
1105 ClassReleaseRemoveLock(DeviceObject, Irp);
1106 ExFreePool(srb);
1107 SendToFdo(DeviceObject, Irp, status);
1108 return status;
1109 }
1110
1111 //
1112 // Validate the request.
1113 //
1114
1115 if((getCaching) &&
1116 (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1117 sizeof(DISK_CACHE_INFORMATION))
1118 ) {
1119 status = STATUS_BUFFER_TOO_SMALL;
1120 Irp->IoStatus.Information = sizeof(DISK_CACHE_INFORMATION);
1121 break;
1122 }
1123
1124 if ((!getCaching) &&
1125 (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1126 sizeof(DISK_CACHE_INFORMATION))
1127 ) {
1128
1129 status = STATUS_INFO_LENGTH_MISMATCH;
1130 break;
1131 }
1132
1133 ASSERT(Irp->AssociatedIrp.SystemBuffer != NULL);
1134
1135 if (getCaching) {
1136
1137 status = DiskGetCacheInformation(fdoExtension, cacheInfo);
1138
1139 if (NT_SUCCESS(status)) {
1140 Irp->IoStatus.Information = sizeof(DISK_CACHE_INFORMATION);
1141 }
1142
1143 } else {
1144
1145 if (!cacheInfo->WriteCacheEnabled)
1146 {
1147 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags,
1148 CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED))
1149 {
1150 //
1151 // This request wants to disable write cache, which is
1152 // not supported on this device. Instead of sending it
1153 // down only to see it fail, return the error code now
1154 //
1155 status = STATUS_INVALID_DEVICE_REQUEST;
1156 break;
1157 }
1158 }
1159 else
1160 {
1161 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags,
1162 CLASS_SPECIAL_DISABLE_WRITE_CACHE))
1163 {
1164 //
1165 // This request wants to enable write cache, which
1166 // has been disabled to protect data integrity. So
1167 // fail this request with access denied
1168 //
1169 status = STATUS_ACCESS_DENIED;
1170 break;
1171 }
1172 }
1173
1174 status = DiskSetCacheInformation(fdoExtension, cacheInfo);
1175
1176 if (NT_SUCCESS(status))
1177 {
1178 //
1179 // Store the user-defined override in the registry
1180 //
1181 ClassSetDeviceParameter(fdoExtension,
1182 DiskDeviceParameterSubkey,
1183 DiskDeviceUserWriteCacheSetting,
1184 (cacheInfo->WriteCacheEnabled) ? DiskWriteCacheEnable : DiskWriteCacheDisable);
1185 }
1186 else if (status == STATUS_INVALID_DEVICE_REQUEST)
1187 {
1188 if (cacheInfo->WriteCacheEnabled == FALSE)
1189 {
1190 //
1191 // This device does not allow for
1192 // the write cache to be disabled
1193 //
1194 ULONG specialFlags = 0;
1195
1196 ClassGetDeviceParameter(fdoExtension,
1197 DiskDeviceParameterSubkey,
1198 DiskDeviceSpecialFlags,
1199 &specialFlags);
1200
1201 SET_FLAG(specialFlags, HackDisableWriteCacheNotSupported);
1202
1203 SET_FLAG(fdoExtension->ScanForSpecialFlags,
1204 CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED);
1205
1206 ClassSetDeviceParameter(fdoExtension,
1207 DiskDeviceParameterSubkey,
1208 DiskDeviceSpecialFlags,
1209 specialFlags);
1210 }
1211 }
1212 }
1213
1214 break;
1215 }
1216
1217 #if(_WIN32_WINNT >= 0x0500)
1218 case IOCTL_DISK_GET_WRITE_CACHE_STATE: {
1219
1220 PDISK_WRITE_CACHE_STATE writeCacheState = (PDISK_WRITE_CACHE_STATE)Irp->AssociatedIrp.SystemBuffer;
1221
1222 if(!commonExtension->IsFdo) {
1223
1224 ClassReleaseRemoveLock(DeviceObject, Irp);
1225 ExFreePool(srb);
1226 SendToFdo(DeviceObject, Irp, status);
1227 return status;
1228 }
1229
1230 //
1231 // Validate the request.
1232 //
1233
1234 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_WRITE_CACHE_STATE)) {
1235
1236 status = STATUS_BUFFER_TOO_SMALL;
1237 Irp->IoStatus.Information = sizeof(DISK_WRITE_CACHE_STATE);
1238 break;
1239 }
1240
1241 *writeCacheState = DiskWriteCacheNormal;
1242
1243 //
1244 // Determine whether it is possible to disable the write cache
1245 //
1246
1247 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED))
1248 {
1249 *writeCacheState = DiskWriteCacheDisableNotSupported;
1250 }
1251
1252 //
1253 // Determine whether it is safe to toggle the write cache
1254 //
1255
1256 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_WRITE_CACHE))
1257 {
1258 *writeCacheState = DiskWriteCacheForceDisable;
1259 }
1260
1261 Irp->IoStatus.Information = sizeof(DISK_WRITE_CACHE_STATE);
1262 status = STATUS_SUCCESS;
1263 break;
1264 }
1265 #endif
1266
1267 case SMART_GET_VERSION: {
1268
1269 PUCHAR buffer;
1270 PSRB_IO_CONTROL srbControl;
1271 PGETVERSIONINPARAMS versionParams;
1272
1273 if(!commonExtension->IsFdo) {
1274 ClassReleaseRemoveLock(DeviceObject, Irp);
1275 ExFreePool(srb);
1276 SendToFdo(DeviceObject, Irp, status);
1277 return status;
1278 }
1279
1280 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1281 sizeof(GETVERSIONINPARAMS)) {
1282 status = STATUS_BUFFER_TOO_SMALL;
1283 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
1284 break;
1285 }
1286
1287 //
1288 // Create notification event object to be used to signal the
1289 // request completion.
1290 //
1291
1292 KeInitializeEvent(&event, NotificationEvent, FALSE);
1293
1294 srbControl = ExAllocatePoolWithTag(NonPagedPool,
1295 sizeof(SRB_IO_CONTROL) +
1296 sizeof(GETVERSIONINPARAMS),
1297 DISK_TAG_SMART);
1298
1299 if (!srbControl) {
1300 status = STATUS_INSUFFICIENT_RESOURCES;
1301 break;
1302 }
1303
1304 RtlZeroMemory(srbControl,
1305 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS)
1306 );
1307
1308 //
1309 // fill in srbControl fields
1310 //
1311
1312 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1313 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1314 srbControl->Timeout = fdoExtension->TimeOutValue;
1315 srbControl->Length = sizeof(GETVERSIONINPARAMS);
1316 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
1317
1318 //
1319 // Point to the 'buffer' portion of the SRB_CONTROL
1320 //
1321
1322 buffer = (PUCHAR)srbControl;
1323 buffer += srbControl->HeaderLength;
1324
1325 //
1326 // Ensure correct target is set in the cmd parameters.
1327 //
1328
1329 versionParams = (PGETVERSIONINPARAMS)buffer;
1330 versionParams->bIDEDeviceMap = diskData->ScsiAddress.TargetId;
1331
1332 //
1333 // Copy the IOCTL parameters to the srb control buffer area.
1334 //
1335
1336 RtlMoveMemory(buffer,
1337 Irp->AssociatedIrp.SystemBuffer,
1338 sizeof(GETVERSIONINPARAMS));
1339
1340 ClassSendDeviceIoControlSynchronous(
1341 IOCTL_SCSI_MINIPORT,
1342 commonExtension->LowerDeviceObject,
1343 srbControl,
1344 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1345 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1346 FALSE,
1347 &ioStatus);
1348
1349 status = ioStatus.Status;
1350
1351 //
1352 // If successful, copy the data received into the output buffer.
1353 // This should only fail in the event that the IDE driver is older
1354 // than this driver.
1355 //
1356
1357 if (NT_SUCCESS(status)) {
1358
1359 buffer = (PUCHAR)srbControl;
1360 buffer += srbControl->HeaderLength;
1361
1362 RtlMoveMemory (Irp->AssociatedIrp.SystemBuffer, buffer,
1363 sizeof(GETVERSIONINPARAMS));
1364 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
1365 }
1366
1367 ExFreePool(srbControl);
1368 break;
1369 }
1370
1371 case SMART_RCV_DRIVE_DATA: {
1372
1373 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1374 ULONG controlCode = 0;
1375 PSRB_IO_CONTROL srbControl;
1376 PUCHAR buffer;
1377
1378 if(!commonExtension->IsFdo) {
1379 ClassReleaseRemoveLock(DeviceObject, Irp);
1380 ExFreePool(srb);
1381 SendToFdo(DeviceObject, Irp, status);
1382 return status;
1383 }
1384
1385 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1386 (sizeof(SENDCMDINPARAMS) - 1)) {
1387 status = STATUS_INVALID_PARAMETER;
1388 Irp->IoStatus.Information = 0;
1389 break;
1390
1391 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1392 (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
1393 status = STATUS_BUFFER_TOO_SMALL;
1394 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) + 512 - 1;
1395 break;
1396 }
1397
1398 //
1399 // Create notification event object to be used to signal the
1400 // request completion.
1401 //
1402
1403 KeInitializeEvent(&event, NotificationEvent, FALSE);
1404
1405 //
1406 // use controlCode as a sort of 'STATUS_SUCCESS' to see if it's
1407 // a valid request type
1408 //
1409
1410 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
1411
1412 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1413 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
1414
1415 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1416 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1417 case READ_ATTRIBUTES:
1418 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
1419 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1420 break;
1421 case READ_THRESHOLDS:
1422 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
1423 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1424 break;
1425 default:
1426 status = STATUS_INVALID_PARAMETER;
1427 break;
1428 }
1429 } else {
1430
1431 status = STATUS_INVALID_PARAMETER;
1432 }
1433
1434 if (controlCode == 0) {
1435 status = STATUS_INVALID_PARAMETER;
1436 break;
1437 }
1438
1439 srbControl = ExAllocatePoolWithTag(NonPagedPool,
1440 sizeof(SRB_IO_CONTROL) + length,
1441 DISK_TAG_SMART);
1442
1443 if (!srbControl) {
1444 status = STATUS_INSUFFICIENT_RESOURCES;
1445 break;
1446 }
1447
1448 //
1449 // fill in srbControl fields
1450 //
1451
1452 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1453 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1454 srbControl->Timeout = fdoExtension->TimeOutValue;
1455 srbControl->Length = length;
1456 srbControl->ControlCode = controlCode;
1457
1458 //
1459 // Point to the 'buffer' portion of the SRB_CONTROL
1460 //
1461
1462 buffer = (PUCHAR)srbControl;
1463 buffer += srbControl->HeaderLength;
1464
1465 //
1466 // Ensure correct target is set in the cmd parameters.
1467 //
1468
1469 cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
1470
1471 //
1472 // Copy the IOCTL parameters to the srb control buffer area.
1473 //
1474
1475 RtlMoveMemory(buffer,
1476 Irp->AssociatedIrp.SystemBuffer,
1477 sizeof(SENDCMDINPARAMS) - 1);
1478
1479 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1480 commonExtension->LowerDeviceObject,
1481 srbControl,
1482 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1483 srbControl,
1484 sizeof(SRB_IO_CONTROL) + length,
1485 FALSE,
1486 &event,
1487 &ioStatus);
1488
1489 if (irp2 == NULL) {
1490 status = STATUS_INSUFFICIENT_RESOURCES;
1491 ExFreePool(srbControl);
1492 break;
1493 }
1494
1495 //
1496 // Call the port driver with the request and wait for it to complete.
1497 //
1498
1499 status = IoCallDriver(commonExtension->LowerDeviceObject, irp2);
1500
1501 if (status == STATUS_PENDING) {
1502 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
1503 status = ioStatus.Status;
1504 }
1505
1506 //
1507 // Copy the data received into the output buffer. Since the status buffer
1508 // contains error information also, always perform this copy. IO will will
1509 // either pass this back to the app, or zero it, in case of error.
1510 //
1511
1512 buffer = (PUCHAR)srbControl;
1513 buffer += srbControl->HeaderLength;
1514
1515 if (NT_SUCCESS(status)) {
1516
1517 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length - 1);
1518 Irp->IoStatus.Information = length - 1;
1519
1520 } else {
1521
1522 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
1523 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
1524
1525 }
1526
1527 ExFreePool(srbControl);
1528 break;
1529
1530 }
1531
1532 case SMART_SEND_DRIVE_COMMAND: {
1533
1534 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1535 PSRB_IO_CONTROL srbControl;
1536 ULONG controlCode = 0;
1537 PUCHAR buffer;
1538
1539 if(!commonExtension->IsFdo) {
1540 ClassReleaseRemoveLock(DeviceObject, Irp);
1541 ExFreePool(srb);
1542 SendToFdo(DeviceObject, Irp, status);
1543 return status;
1544 }
1545
1546 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1547 (sizeof(SENDCMDINPARAMS) - 1)) {
1548 status = STATUS_INVALID_PARAMETER;
1549 Irp->IoStatus.Information = 0;
1550 break;
1551
1552 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1553 (sizeof(SENDCMDOUTPARAMS) - 1)) {
1554 status = STATUS_BUFFER_TOO_SMALL;
1555 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
1556 break;
1557 }
1558
1559 //
1560 // Create notification event object to be used to signal the
1561 // request completion.
1562 //
1563
1564 KeInitializeEvent(&event, NotificationEvent, FALSE);
1565
1566 length = 0;
1567
1568 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1569 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1570
1571 case ENABLE_SMART:
1572 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
1573 break;
1574
1575 case DISABLE_SMART:
1576 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
1577 break;
1578
1579 case RETURN_SMART_STATUS:
1580
1581 //
1582 // Ensure bBuffer is at least 2 bytes (to hold the values of
1583 // cylinderLow and cylinderHigh).
1584 //
1585
1586 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1587 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
1588
1589 status = STATUS_BUFFER_TOO_SMALL;
1590 Irp->IoStatus.Information =
1591 sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
1592 break;
1593 }
1594
1595 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
1596 length = sizeof(IDEREGS);
1597 break;
1598
1599 case ENABLE_DISABLE_AUTOSAVE:
1600 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
1601 break;
1602
1603 case SAVE_ATTRIBUTE_VALUES:
1604 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
1605 break;
1606
1607 case EXECUTE_OFFLINE_DIAGS:
1608 //
1609 // Validate that this is an ok self test command
1610 //
1611 if (DiskIsValidSmartSelfTest(cmdInParameters->irDriveRegs.bSectorNumberReg))
1612 {
1613 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
1614 }
1615 break;
1616
1617 case ENABLE_DISABLE_AUTO_OFFLINE:
1618 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE;
1619 break;
1620
1621 default:
1622 status = STATUS_INVALID_PARAMETER;
1623 break;
1624 }
1625 } else {
1626
1627 status = STATUS_INVALID_PARAMETER;
1628 }
1629
1630 if (controlCode == 0) {
1631 status = STATUS_INVALID_PARAMETER;
1632 break;
1633 }
1634
1635 length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);
1636 srbControl = ExAllocatePoolWithTag(NonPagedPool,
1637 sizeof(SRB_IO_CONTROL) + length,
1638 DISK_TAG_SMART);
1639
1640 if (!srbControl) {
1641 status = STATUS_INSUFFICIENT_RESOURCES;
1642 break;
1643 }
1644
1645 //
1646 // fill in srbControl fields
1647 //
1648
1649 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1650 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1651 srbControl->Timeout = fdoExtension->TimeOutValue;
1652 srbControl->Length = length;
1653
1654 //
1655 // Point to the 'buffer' portion of the SRB_CONTROL
1656 //
1657
1658 buffer = (PUCHAR)srbControl;
1659 buffer += srbControl->HeaderLength;
1660
1661 //
1662 // Ensure correct target is set in the cmd parameters.
1663 //
1664
1665 cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
1666
1667 //
1668 // Copy the IOCTL parameters to the srb control buffer area.
1669 //
1670
1671 RtlMoveMemory(buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1672
1673 srbControl->ControlCode = controlCode;
1674
1675 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1676 commonExtension->LowerDeviceObject,
1677 srbControl,
1678 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1679 srbControl,
1680 sizeof(SRB_IO_CONTROL) + length,
1681 FALSE,
1682 &event,
1683 &ioStatus);
1684
1685 if (irp2 == NULL) {
1686 status = STATUS_INSUFFICIENT_RESOURCES;
1687 ExFreePool(srbControl);
1688 break;
1689 }
1690
1691 //
1692 // Call the port driver with the request and wait for it to complete.
1693 //
1694
1695 status = IoCallDriver(commonExtension->LowerDeviceObject, irp2);
1696
1697 if (status == STATUS_PENDING) {
1698 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
1699 status = ioStatus.Status;
1700 }
1701
1702 //
1703 // Copy the data received into the output buffer. Since the status buffer
1704 // contains error information also, always perform this copy. IO will will
1705 // either pass this back to the app, or zero it, in case of error.
1706 //
1707
1708 buffer = (PUCHAR)srbControl;
1709 buffer += srbControl->HeaderLength;
1710
1711 //
1712 // Update the return buffer size based on the sub-command.
1713 //
1714
1715 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
1716 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
1717 } else {
1718 length = sizeof(SENDCMDOUTPARAMS) - 1;
1719 }
1720
1721 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length);
1722 Irp->IoStatus.Information = length;
1723
1724 ExFreePool(srbControl);
1725 break;
1726
1727 }
1728
1729 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {
1730
1731 PMODE_PARAMETER_BLOCK blockDescriptor;
1732 ULONG modeLength;
1733 ULONG retries = 4;
1734 BOOLEAN writable = FALSE;
1735 BOOLEAN mediaPresent = FALSE;
1736
1737 DebugPrint((3,
1738 "Disk.DiskDeviceControl: GetMediaTypes\n"));
1739
1740 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1741 sizeof(GET_MEDIA_TYPES)) {
1742 status = STATUS_BUFFER_TOO_SMALL;
1743 Irp->IoStatus.Information = sizeof(GET_MEDIA_TYPES);
1744 break;
1745 }
1746
1747 if(!commonExtension->IsFdo) {
1748 ClassReleaseRemoveLock(DeviceObject, Irp);
1749 ExFreePool(srb);
1750 SendToFdo(DeviceObject, Irp, status);
1751 return status;
1752 }
1753
1754 //
1755 // Send a TUR to determine if media is present.
1756 //
1757
1758 srb->CdbLength = 6;
1759 cdb = (PCDB)srb->Cdb;
1760 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1761
1762 //
1763 // Set timeout value.
1764 //
1765
1766 srb->TimeOutValue = fdoExtension->TimeOutValue;
1767
1768 status = ClassSendSrbSynchronous(DeviceObject,
1769 srb,
1770 NULL,
1771 0,
1772 FALSE);
1773
1774
1775 if (NT_SUCCESS(status)) {
1776 mediaPresent = TRUE;
1777 }
1778
1779 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1780
1781 //
1782 // Allocate memory for mode header and block descriptor.
1783 //
1784
1785 modeLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
1786 modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
1787 modeLength,
1788 DISK_TAG_MODE_DATA);
1789
1790 if (modeData == NULL) {
1791 status = STATUS_INSUFFICIENT_RESOURCES;
1792 break;
1793 }
1794
1795 RtlZeroMemory(modeData, modeLength);
1796
1797 //
1798 // Build the MODE SENSE CDB.
1799 //
1800
1801 srb->CdbLength = 6;
1802 cdb = (PCDB)srb->Cdb;
1803
1804 //
1805 // Set timeout value from device extension.
1806 //
1807
1808 srb->TimeOutValue = fdoExtension->TimeOutValue;
1809
1810 //
1811 // Page code of 0 will return header and block descriptor only.
1812 //
1813
1814 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1815 cdb->MODE_SENSE.PageCode = 0;
1816 cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
1817
1818 Retry:
1819 status = ClassSendSrbSynchronous(DeviceObject,
1820 srb,
1821 modeData,
1822 modeLength,
1823 FALSE);
1824
1825
1826 if (status == STATUS_VERIFY_REQUIRED) {
1827
1828 if (retries--) {
1829
1830 //
1831 // Retry request.
1832 //
1833
1834 goto Retry;
1835 }
1836 } else if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
1837 status = STATUS_SUCCESS;
1838 }
1839
1840 if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) {
1841
1842 //
1843 // Get the block descriptor.
1844 //
1845
1846 blockDescriptor = (PMODE_PARAMETER_BLOCK)modeData;
1847 blockDescriptor = (PMODE_PARAMETER_BLOCK)((ULONG_PTR)blockDescriptor + sizeof(MODE_PARAMETER_HEADER));
1848
1849 //
1850 // Do some validation.
1851 //
1852
1853 if (modeData->BlockDescriptorLength != sizeof(MODE_PARAMETER_BLOCK)) {
1854
1855 DebugPrint((1,
1856 "DiskDeviceControl: BlockDescriptor length - "
1857 "Expected %x, actual %x\n",
1858 modeData->BlockDescriptorLength,
1859 sizeof(MODE_PARAMETER_BLOCK)));
1860 }
1861
1862 DebugPrint((1,
1863 "DiskDeviceControl: DensityCode %x, MediumType %x\n",
1864 blockDescriptor->DensityCode,
1865 modeData->MediumType));
1866
1867 if (TEST_FLAG(modeData->DeviceSpecificParameter,
1868 MODE_DSP_WRITE_PROTECT)) {
1869 writable = FALSE;
1870 } else {
1871 writable = TRUE;
1872 }
1873
1874 status = DiskDetermineMediaTypes(DeviceObject,
1875 Irp,
1876 modeData->MediumType,
1877 blockDescriptor->DensityCode,
1878 mediaPresent,
1879 writable);
1880
1881 //
1882 // If the buffer was too small, DetermineMediaTypes updated the status and information and the request will fail.
1883 //
1884
1885 } else {
1886 DebugPrint((1,
1887 "DiskDeviceControl: Mode sense for header/bd failed. %lx\n",
1888 status));
1889 }
1890
1891 ExFreePool(modeData);
1892 break;
1893 }
1894
1895 case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
1896
1897 DebugPrint((2, "IOCTL_DISK_GET_DRIVE_GEOMETRY to device %p through irp %p\n",
1898 DeviceObject, Irp));
1899 DebugPrint((2, "Device is a%s.\n",
1900 commonExtension->IsFdo ? "n fdo" : " pdo"));
1901
1902 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1903 sizeof(DISK_GEOMETRY)) {
1904
1905 status = STATUS_BUFFER_TOO_SMALL;
1906 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1907 break;
1908 }
1909
1910 if(!commonExtension->IsFdo) {
1911
1912 //
1913 // Pdo should issue this request to the lower device object
1914 //
1915
1916 ClassReleaseRemoveLock(DeviceObject, Irp);
1917 ExFreePool(srb);
1918 SendToFdo(DeviceObject, Irp, status);
1919 return status;
1920 }
1921
1922 // DiskAcquirePartitioningLock(fdoExtension);
1923
1924 if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
1925
1926 //
1927 // Issue ReadCapacity to update device extension
1928 // with information for current media.
1929 //
1930
1931 status = DiskReadDriveCapacity(
1932 commonExtension->PartitionZeroExtension->DeviceObject);
1933
1934 //
1935 // Note whether the drive is ready.
1936 //
1937
1938 diskData->ReadyStatus = status;
1939
1940 if (!NT_SUCCESS(status)) {
1941 // DiskReleasePartitioningLock(fdoExtension);
1942 break;
1943 }
1944 }
1945
1946 //
1947 // Copy drive geometry information from device extension.
1948 //
1949
1950 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
1951 &(fdoExtension->DiskGeometry),
1952 sizeof(DISK_GEOMETRY));
1953
1954 status = STATUS_SUCCESS;
1955 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1956 // DiskReleasePartitioningLock(fdoExtension);
1957 break;
1958 }
1959
1960 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: {
1961 DebugPrint((1, "IOCTL_DISK_GET_DRIVE_GEOMETRY_EX to device %p through irp %p\n",
1962 DeviceObject, Irp));
1963 DebugPrint((1, "Device Is a%s.\n",
1964 commonExtension->IsFdo ? "n fdo" : " pdo"));
1965
1966
1967 if (!commonExtension->IsFdo) {
1968
1969 //
1970 // Pdo should issue this request to the lower device object
1971 //
1972
1973 ClassReleaseRemoveLock (DeviceObject, Irp);
1974 ExFreePool (srb);
1975 SendToFdo (DeviceObject, Irp, status);
1976 return status;
1977
1978 } else {
1979
1980 status = DiskIoctlGetDriveGeometryEx( DeviceObject, Irp );
1981 }
1982
1983 break;
1984 }
1985
1986 case IOCTL_STORAGE_PREDICT_FAILURE : {
1987
1988 PSTORAGE_PREDICT_FAILURE checkFailure;
1989 STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
1990
1991 DebugPrint((2, "IOCTL_STORAGE_PREDICT_FAILURE to device %p through irp %p\n",
1992 DeviceObject, Irp));
1993 DebugPrint((2, "Device is a%s.\n",
1994 commonExtension->IsFdo ? "n fdo" : " pdo"));
1995
1996 checkFailure = (PSTORAGE_PREDICT_FAILURE)Irp->AssociatedIrp.SystemBuffer;
1997
1998 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1999 sizeof(STORAGE_PREDICT_FAILURE)) {
2000
2001 status = STATUS_BUFFER_TOO_SMALL;
2002 Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE);
2003 break;
2004 }
2005
2006 if(!commonExtension->IsFdo) {
2007
2008 //
2009 // Pdo should issue this request to the lower device object
2010 //
2011
2012 ClassReleaseRemoveLock(DeviceObject, Irp);
2013 ExFreePool(srb);
2014 SendToFdo(DeviceObject, Irp, status);
2015 return status;
2016 }
2017
2018 //
2019 // See if the disk is predicting failure
2020 //
2021
2022 if (diskData->FailurePredictionCapability == FailurePredictionSense) {
2023 ULONG readBufferSize;
2024 PUCHAR readBuffer;
2025 PIRP readIrp;
2026 IO_STATUS_BLOCK ioStatus;
2027 PDEVICE_OBJECT topOfStack;
2028
2029 checkFailure->PredictFailure = 0;
2030
2031 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
2032
2033 topOfStack = IoGetAttachedDeviceReference(DeviceObject);
2034
2035 //
2036 // SCSI disks need to have a read sent down to provoke any
2037 // failures to be reported.
2038 //
2039 // Issue a normal read operation. The error-handling code in
2040 // classpnp will take care of a failure prediction by logging the
2041 // correct event.
2042 //
2043
2044 readBufferSize = fdoExtension->DiskGeometry.BytesPerSector;
2045 readBuffer = ExAllocatePoolWithTag(NonPagedPool,
2046 readBufferSize,
2047 DISK_TAG_SMART);
2048
2049 if (readBuffer != NULL) {
2050 LARGE_INTEGER offset;
2051
2052 offset.QuadPart = 0;
2053 readIrp = IoBuildSynchronousFsdRequest(
2054 IRP_MJ_READ,
2055 topOfStack,
2056 readBuffer,
2057 readBufferSize,
2058 &offset,
2059 &event,
2060 &ioStatus);
2061
2062
2063 if (readIrp != NULL) {
2064 status = IoCallDriver(topOfStack, readIrp);
2065 if (status == STATUS_PENDING) {
2066 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
2067 status = ioStatus.Status;
2068 }
2069 }
2070
2071 ExFreePool(readBuffer);
2072 }
2073 ObDereferenceObject(topOfStack);
2074 }
2075
2076 if ((diskData->FailurePredictionCapability == FailurePredictionSmart) ||
2077 (diskData->FailurePredictionCapability == FailurePredictionSense))
2078 {
2079 status = DiskReadFailurePredictStatus(fdoExtension,
2080 &diskSmartStatus);
2081
2082 if (NT_SUCCESS(status))
2083 {
2084 status = DiskReadFailurePredictData(fdoExtension,
2085 Irp->AssociatedIrp.SystemBuffer);
2086
2087 if (diskSmartStatus.PredictFailure)
2088 {
2089 checkFailure->PredictFailure = 1;
2090 } else {
2091 checkFailure->PredictFailure = 0;
2092 }
2093
2094 Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE);
2095 }
2096 } else {
2097 status = STATUS_INVALID_DEVICE_REQUEST;
2098 }
2099
2100 break;
2101 }
2102
2103 case IOCTL_DISK_VERIFY: {
2104
2105 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
2106 LARGE_INTEGER byteOffset;
2107
2108 DebugPrint((2, "IOCTL_DISK_VERIFY to device %p through irp %p\n",
2109 DeviceObject, Irp));
2110 DebugPrint((2, "Device is a%s.\n",
2111 commonExtension->IsFdo ? "n fdo" : " pdo"));
2112
2113 //
2114 // Validate buffer length.
2115 //
2116
2117 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2118 sizeof(VERIFY_INFORMATION)) {
2119
2120 status = STATUS_INFO_LENGTH_MISMATCH;
2121 break;
2122 }
2123
2124 //
2125 // Add disk offset to starting sector.
2126 //
2127
2128 byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart +
2129 verifyInfo->StartingOffset.QuadPart;
2130
2131 if(!commonExtension->IsFdo) {
2132
2133 //
2134 // Adjust the request and forward it down
2135 //
2136
2137 verifyInfo->StartingOffset.QuadPart = byteOffset.QuadPart;
2138
2139 ClassReleaseRemoveLock(DeviceObject, Irp);
2140 SendToFdo(DeviceObject, Irp, status);
2141 ExFreePool(srb);
2142 return status;
2143 }
2144
2145 //
2146 // Perform a bounds check on the sector range
2147 //
2148
2149 if ((verifyInfo->StartingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
2150 (verifyInfo->StartingOffset.QuadPart < 0))
2151 {
2152 status = STATUS_NONEXISTENT_SECTOR;
2153 break;
2154 }
2155 else
2156 {
2157 ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart;
2158
2159 if ((ULONGLONG)verifyInfo->Length > bytesRemaining)
2160 {
2161 status = STATUS_NONEXISTENT_SECTOR;
2162 break;
2163 }
2164 }
2165
2166 {
2167 PDISK_VERIFY_WORKITEM_CONTEXT Context = NULL;
2168
2169 Context = ExAllocatePoolWithTag(NonPagedPool,
2170 sizeof(DISK_VERIFY_WORKITEM_CONTEXT),
2171 DISK_TAG_WI_CONTEXT);
2172
2173 if (Context)
2174 {
2175 Context->Irp = Irp;
2176 Context->Srb = srb;
2177 Context->WorkItem = IoAllocateWorkItem(DeviceObject);
2178
2179 if (Context->WorkItem)
2180 {
2181 IoMarkIrpPending(Irp);
2182
2183 IoQueueWorkItem(Context->WorkItem,
2184 (PIO_WORKITEM_ROUTINE)DiskIoctlVerify,
2185 DelayedWorkQueue,
2186 Context);
2187
2188 return STATUS_PENDING;
2189 }
2190
2191 ExFreePool(Context);
2192 }
2193
2194 status = STATUS_INSUFFICIENT_RESOURCES;
2195 }
2196
2197 break;
2198 }
2199
2200 case IOCTL_DISK_CREATE_DISK: {
2201
2202 if (!commonExtension->IsFdo) {
2203 ClassReleaseRemoveLock(DeviceObject, Irp);
2204 ExFreePool(srb);
2205 SendToFdo(DeviceObject, Irp, status);
2206 return status;
2207 }
2208
2209 status = DiskIoctlCreateDisk (
2210 DeviceObject,
2211 Irp
2212 );
2213 break;
2214 }
2215
2216 case IOCTL_DISK_GET_DRIVE_LAYOUT: {
2217
2218 DebugPrint((1, "IOCTL_DISK_GET_DRIVE_LAYOUT to device %p through irp %p\n",
2219 DeviceObject, Irp));
2220 DebugPrint((1, "Device is a%s.\n",
2221 commonExtension->IsFdo ? "n fdo" : " pdo"));
2222
2223 if (!commonExtension->IsFdo) {
2224 ClassReleaseRemoveLock(DeviceObject, Irp);
2225 ExFreePool(srb);
2226 SendToFdo(DeviceObject, Irp, status);
2227 return status;
2228 }
2229
2230 status = DiskIoctlGetDriveLayout(
2231 DeviceObject,
2232 Irp);
2233 break;
2234 }
2235
2236 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: {
2237
2238 DebugPrint((1, "IOCTL_DISK_GET_DRIVE_LAYOUT_EX to device %p through irp %p\n",
2239 DeviceObject, Irp));
2240 DebugPrint((1, "Device is a%s.\n",
2241 commonExtension->IsFdo ? "n fdo" : " pdo"));
2242
2243 if (!commonExtension->IsFdo) {
2244 ClassReleaseRemoveLock(DeviceObject, Irp);
2245 ExFreePool(srb);
2246 SendToFdo(DeviceObject, Irp, status);
2247 return status;
2248 }
2249
2250 status = DiskIoctlGetDriveLayoutEx(
2251 DeviceObject,
2252 Irp);
2253 break;
2254
2255 }
2256
2257 case IOCTL_DISK_SET_DRIVE_LAYOUT: {
2258
2259 DebugPrint((1, "IOCTL_DISK_SET_DRIVE_LAYOUT to device %p through irp %p\n",
2260 DeviceObject, Irp));
2261 DebugPrint((1, "Device is a%s.\n",
2262 commonExtension->IsFdo ? "n fdo" : " pdo"));
2263
2264 if(!commonExtension->IsFdo) {
2265 ClassReleaseRemoveLock(DeviceObject, Irp);
2266 ExFreePool(srb);
2267 SendToFdo(DeviceObject, Irp, status);
2268 return status;
2269 }
2270
2271 status = DiskIoctlSetDriveLayout(DeviceObject, Irp);
2272
2273 //
2274 // Notify everyone that the disk layout has changed
2275 //
2276 {
2277 TARGET_DEVICE_CUSTOM_NOTIFICATION Notification;
2278
2279 Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
2280 Notification.Version = 1;
2281 Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
2282 Notification.FileObject = NULL;
2283 Notification.NameBufferOffset = -1;
2284
2285 IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
2286 &Notification,
2287 NULL,
2288 NULL);
2289 }
2290
2291 break;
2292 }
2293
2294 case IOCTL_DISK_SET_DRIVE_LAYOUT_EX: {
2295
2296 DebugPrint((1, "IOCTL_DISK_SET_DRIVE_LAYOUT_EX to device %p through irp %p\n",
2297 DeviceObject, Irp));
2298 DebugPrint((1, "Device is a%s.\n",
2299 commonExtension->IsFdo ? "n fdo" : " pdo"));
2300
2301 if (!commonExtension->IsFdo) {
2302 ClassReleaseRemoveLock(DeviceObject, Irp);
2303 ExFreePool(srb);
2304 SendToFdo(DeviceObject, Irp, status);
2305
2306 return status;
2307 }
2308
2309 status = DiskIoctlSetDriveLayoutEx(
2310 DeviceObject,
2311 Irp);
2312
2313 //
2314 // Notify everyone that the disk layout has changed
2315 //
2316 {
2317 TARGET_DEVICE_CUSTOM_NOTIFICATION Notification;
2318
2319 Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
2320 Notification.Version = 1;
2321 Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
2322 Notification.FileObject = NULL;
2323 Notification.NameBufferOffset = -1;
2324
2325 IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
2326 &Notification,
2327 NULL,
2328 NULL);
2329 }
2330
2331 break;
2332 }
2333
2334 case IOCTL_DISK_GET_PARTITION_INFO: {
2335
2336 DebugPrint((1, "IOCTL_DISK_GET_PARTITION_INFO to device %p through irp %p\n",
2337 DeviceObject, Irp));
2338 DebugPrint((1, "Device is a%s.\n",
2339 commonExtension->IsFdo ? "n fdo" : " pdo"));
2340
2341 status = DiskIoctlGetPartitionInfo(
2342 DeviceObject,
2343 Irp);
2344 break;
2345 }
2346
2347 case IOCTL_DISK_GET_PARTITION_INFO_EX: {
2348
2349 DebugPrint((1, "IOCTL_DISK_GET_PARTITION_INFO to device %p through irp %p\n",
2350 DeviceObject, Irp));
2351 DebugPrint((1, "Device is a%s.\n",
2352 commonExtension->IsFdo ? "n fdo" : " pdo"));
2353
2354 status = DiskIoctlGetPartitionInfoEx(
2355 DeviceObject,
2356 Irp);
2357 break;
2358 }
2359
2360 case IOCTL_DISK_GET_LENGTH_INFO: {
2361 DebugPrint((1, "IOCTL_DISK_GET_LENGTH_INFO to device %p through irp %p\n",
2362 DeviceObject, Irp));
2363 DebugPrint((1, "Device is a%s.\n",
2364 commonExtension->IsFdo ? "n fdo" : " pdo"));
2365
2366 status = DiskIoctlGetLengthInfo(
2367 DeviceObject,
2368 Irp);
2369 break;
2370 }
2371
2372 case IOCTL_DISK_SET_PARTITION_INFO: {
2373
2374 DebugPrint((1, "IOCTL_DISK_SET_PARTITION_INFO to device %p through irp %p\n",
2375 DeviceObject, Irp));
2376 DebugPrint((1, "Device is a%s.\n",
2377 commonExtension->IsFdo ? "n fdo" : " pdo"));
2378
2379
2380 status = DiskIoctlSetPartitionInfo (
2381 DeviceObject,
2382 Irp);
2383 break;
2384 }
2385
2386
2387 case IOCTL_DISK_SET_PARTITION_INFO_EX: {
2388
2389 DebugPrint((1, "IOCTL_DISK_SET_PARTITION_INFO_EX to device %p through irp %p\n",
2390 DeviceObject, Irp));
2391 DebugPrint((1, "Device is a%s.\n",
2392 commonExtension->IsFdo ? "n fdo" : " pdo"));
2393
2394 status = DiskIoctlSetPartitionInfoEx(
2395 DeviceObject,
2396 Irp);
2397 break;
2398 }
2399
2400 case IOCTL_DISK_DELETE_DRIVE_LAYOUT: {
2401
2402 CREATE_DISK CreateDiskInfo;
2403
2404 //
2405 // Update the disk with new partition information.
2406 //
2407
2408 DebugPrint((1, "IOCTL_DISK_DELETE_DRIVE_LAYOUT to device %p through irp %p\n",
2409 DeviceObject, Irp));
2410 DebugPrint((1, "Device is a%s.\n",
2411 commonExtension->IsFdo ? "n fdo" : " pdo"));
2412
2413 if(!commonExtension->IsFdo) {
2414
2415 ClassReleaseRemoveLock(DeviceObject, Irp);
2416 ExFreePool(srb);
2417 SendToFdo(DeviceObject, Irp, status);
2418 return status;
2419 }
2420
2421 DiskAcquirePartitioningLock(fdoExtension);
2422
2423 DiskInvalidatePartitionTable(fdoExtension, TRUE);
2424
2425 //
2426 // IoCreateDisk called with a partition style of raw
2427 // will remove any partition tables from the disk.
2428 //
2429
2430 RtlZeroMemory (&CreateDiskInfo, sizeof (CreateDiskInfo));
2431 CreateDiskInfo.PartitionStyle = PARTITION_STYLE_RAW;
2432
2433 status = IoCreateDisk(
2434 DeviceObject,
2435 &CreateDiskInfo);
2436
2437
2438 DiskReleasePartitioningLock(fdoExtension);
2439 ClassInvalidateBusRelations(DeviceObject);
2440
2441 Irp->IoStatus.Status = status;
2442
2443 break;
2444 }
2445
2446 case IOCTL_DISK_REASSIGN_BLOCKS: {
2447
2448 //
2449 // Map defective blocks to new location on disk.
2450 //
2451
2452 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
2453 ULONG bufferSize;
2454 ULONG blockNumber;
2455 ULONG blockCount;
2456
2457 DebugPrint((2, "IOCTL_DISK_REASSIGN_BLOCKS to device %p through irp %p\n",
2458 DeviceObject, Irp));
2459 DebugPrint((2, "Device is a%s.\n",
2460 commonExtension->IsFdo ? "n fdo" : " pdo"));
2461
2462 //
2463 // Validate buffer length.
2464 //
2465
2466 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2467 sizeof(REASSIGN_BLOCKS)) {
2468
2469 status = STATUS_INFO_LENGTH_MISMATCH;
2470 break;
2471 }
2472
2473 //
2474 // Send to FDO
2475 //
2476
2477 if(!commonExtension->IsFdo) {
2478
2479 ClassReleaseRemoveLock(DeviceObject, Irp);
2480 ExFreePool(srb);
2481 SendToFdo(DeviceObject, Irp, status);
2482 return status;
2483 }
2484
2485 bufferSize = sizeof(REASSIGN_BLOCKS) +
2486 ((badBlocks->Count - 1) * sizeof(ULONG));
2487
2488 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2489 bufferSize) {
2490
2491 status = STATUS_INFO_LENGTH_MISMATCH;
2492 break;
2493 }
2494
2495 //
2496 // Build the data buffer to be transferred in the input buffer.
2497 // The format of the data to the device is:
2498 //
2499 // 2 bytes Reserved
2500 // 2 bytes Length
2501 // x * 4 btyes Block Address
2502 //
2503 // All values are big endian.
2504 //
2505
2506 badBlocks->Reserved = 0;
2507 blockCount = badBlocks->Count;
2508
2509 //
2510 // Convert # of entries to # of bytes.
2511 //
2512
2513 blockCount *= 4;
2514 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
2515 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
2516
2517 //
2518 // Convert back to number of entries.
2519 //
2520
2521 blockCount /= 4;
2522
2523 for (; blockCount > 0; blockCount--) {
2524
2525 blockNumber = badBlocks->BlockNumber[blockCount-1];
2526
2527 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
2528 (PFOUR_BYTE) &blockNumber);
2529 }
2530
2531 srb->CdbLength = 6;
2532
2533 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
2534
2535 //
2536 // Set timeout value.
2537 //
2538
2539 srb->TimeOutValue = fdoExtension->TimeOutValue;
2540
2541 status = ClassSendSrbSynchronous(DeviceObject,
2542 srb,
2543 badBlocks,
2544 bufferSize,
2545 TRUE);
2546
2547 Irp->IoStatus.Status = status;
2548 Irp->IoStatus.Information = 0;
2549 ExFreePool(srb);
2550 ClassReleaseRemoveLock(DeviceObject, Irp);
2551 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
2552
2553 return(status);
2554 }
2555
2556 case IOCTL_DISK_IS_WRITABLE: {
2557
2558 //
2559 // This routine mimics IOCTL_STORAGE_GET_MEDIA_TYPES_EX
2560 //
2561
2562 ULONG modeLength;
2563 ULONG retries = 4;
2564
2565 DebugPrint((3, "Disk.DiskDeviceControl: IOCTL_DISK_IS_WRITABLE\n"));
2566
2567 if (!commonExtension->IsFdo)
2568 {
2569 ClassReleaseRemoveLock(DeviceObject, Irp);
2570 ExFreePool(srb);
2571 SendToFdo(DeviceObject, Irp, status);
2572 return status;
2573 }
2574
2575 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2576
2577 //
2578 // Allocate memory for a mode header and then some
2579 // for port drivers that need to convert to MODE10
2580 // or always return the MODE_PARAMETER_BLOCK (even
2581 // when memory was not allocated for this purpose)
2582 //
2583
2584 modeLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
2585 modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2586 modeLength,
2587 DISK_TAG_MODE_DATA);
2588
2589 if (modeData == NULL)
2590 {
2591 status = STATUS_INSUFFICIENT_RESOURCES;
2592 break;
2593 }
2594
2595 RtlZeroMemory(modeData, modeLength);
2596
2597 //
2598 // Build the MODE SENSE CDB
2599 //
2600
2601 srb->CdbLength = 6;
2602 cdb = (PCDB)srb->Cdb;
2603
2604 //
2605 // Set the timeout value from the device extension
2606 //
2607
2608 srb->TimeOutValue = fdoExtension->TimeOutValue;
2609
2610 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2611 cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL;
2612 cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
2613
2614 while (retries != 0)
2615 {
2616 status = ClassSendSrbSynchronous(DeviceObject,
2617 srb,
2618 modeData,
2619 modeLength,
2620 FALSE);
2621
2622 if (status != STATUS_VERIFY_REQUIRED)
2623 {
2624 if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)
2625 {
2626 status = STATUS_SUCCESS;
2627 }
2628
2629 break;
2630 }
2631
2632 retries--;
2633 }
2634
2635 if (NT_SUCCESS(status))
2636 {
2637 if (TEST_FLAG(modeData->DeviceSpecificParameter, MODE_DSP_WRITE_PROTECT))
2638 {
2639 status = STATUS_MEDIA_WRITE_PROTECTED;
2640 }
2641 }
2642
2643 ExFreePool(modeData);
2644 break;
2645 }
2646
2647 case IOCTL_DISK_INTERNAL_SET_VERIFY: {
2648
2649 //
2650 // If the caller is kernel mode, set the verify bit.
2651 //
2652
2653 if (Irp->RequestorMode == KernelMode) {
2654
2655 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
2656
2657 if(commonExtension->IsFdo) {
2658
2659 Irp->IoStatus.Information = 0;
2660 }
2661 }
2662
2663 DiskInvalidatePartitionTable(fdoExtension, FALSE);
2664
2665 status = STATUS_SUCCESS;
2666 break;
2667 }
2668
2669 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: {
2670
2671 //
2672 // If the caller is kernel mode, clear the verify bit.
2673 //
2674
2675 if (Irp->RequestorMode == KernelMode) {
2676 CLEAR_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
2677 }
2678 status = STATUS_SUCCESS;
2679 break;
2680 }
2681
2682 case IOCTL_DISK_UPDATE_DRIVE_SIZE: {
2683
2684 DebugPrint((2, "IOCTL_DISK_UPDATE_DRIVE_SIZE to device %p "
2685 "through irp %p\n",
2686 DeviceObject, Irp));
2687
2688 DebugPrint((2, "Device is a%s.\n",
2689 commonExtension->IsFdo ? "n fdo" : " pdo"));
2690
2691 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2692 sizeof(DISK_GEOMETRY)) {
2693
2694 status = STATUS_BUFFER_TOO_SMALL;
2695 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
2696 break;
2697 }
2698
2699 if(!commonExtension->IsFdo) {
2700
2701 //
2702 // Pdo should issue this request to the lower device object.
2703 //
2704
2705 ClassReleaseRemoveLock(DeviceObject, Irp);
2706 ExFreePool(srb);
2707 SendToFdo(DeviceObject, Irp, status);
2708 return status;
2709 }
2710
2711 DiskAcquirePartitioningLock(fdoExtension);
2712
2713 //
2714 // Invalidate the cached partition table.
2715 //
2716
2717 DiskInvalidatePartitionTable(fdoExtension, TRUE);
2718
2719 //
2720 // At this point, commonExtension *is* the FDO extension. This
2721 // should be the same as PartitionZeroExtension.
2722 //
2723
2724 ASSERT(commonExtension ==
2725 &(commonExtension->PartitionZeroExtension->CommonExtension));
2726
2727 //
2728 // Issue ReadCapacity to update device extension with information
2729 // for current media.
2730 //
2731
2732 status = DiskReadDriveCapacity(DeviceObject);
2733
2734 //
2735 // Note whether the drive is ready.
2736 //
2737
2738 diskData->ReadyStatus = status;
2739
2740 //
2741 // The disk's partition tables may be invalid after the drive geometry
2742 // has been updated. The call to IoValidatePartitionTable (below) will
2743 // fix it if this is the case.
2744 //
2745
2746 if (NT_SUCCESS(status)) {
2747
2748 status = DiskVerifyPartitionTable (fdoExtension, TRUE);
2749 }
2750
2751
2752 if (NT_SUCCESS(status)) {
2753
2754 //
2755 // Copy drive geometry information from the device extension.
2756 //
2757
2758 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2759 &(fdoExtension->DiskGeometry),
2760 sizeof(DISK_GEOMETRY));
2761
2762 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
2763 status = STATUS_SUCCESS;
2764
2765 }
2766
2767 DiskReleasePartitioningLock(fdoExtension);
2768
2769 break;
2770 }
2771
2772 case IOCTL_DISK_GROW_PARTITION: {
2773
2774 PDISK_GROW_PARTITION inputBuffer;
2775
2776 // PDEVICE_OBJECT pdo;
2777 PCOMMON_DEVICE_EXTENSION pdoExtension;
2778
2779 LARGE_INTEGER bytesPerCylinder;
2780 LARGE_INTEGER newStoppingOffset;
2781 LARGE_INTEGER newPartitionLength;
2782
2783 PPHYSICAL_DEVICE_EXTENSION sibling;
2784
2785 PDRIVE_LAYOUT_INFORMATION_EX layoutInfo;
2786 PPARTITION_INFORMATION_EX pdoPartition;
2787 PPARTITION_INFORMATION_EX containerPartition;
2788 //ULONG partitionIndex;
2789
2790 DebugPrint((2, "IOCTL_DISK_GROW_PARTITION to device %p through "
2791 "irp %p\n",
2792 DeviceObject, Irp));
2793
2794 DebugPrint((2, "Device is a%s.\n",
2795 commonExtension->IsFdo ? "n fdo" : " pdo"));
2796
2797 Irp->IoStatus.Information = 0;
2798
2799 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2800 sizeof(DISK_GROW_PARTITION)) {
2801
2802 status = STATUS_INFO_LENGTH_MISMATCH;
2803 Irp->IoStatus.Information = sizeof(DISK_GROW_PARTITION);
2804 break;
2805 }
2806
2807 if(!commonExtension->IsFdo) {
2808
2809 //
2810 // Pdo should issue this request to the lower device object
2811 //
2812
2813 ClassReleaseRemoveLock(DeviceObject, Irp);
2814 ExFreePool(srb);
2815 SendToFdo(DeviceObject, Irp, status);
2816 return status;
2817 }
2818
2819 DiskAcquirePartitioningLock(fdoExtension);
2820 ClassAcquireChildLock(fdoExtension);
2821
2822 //
2823 // At this point, commonExtension *is* the FDO extension. This should
2824 // be the same as PartitionZeroExtension.
2825 //
2826
2827 ASSERT(commonExtension ==
2828 &(commonExtension->PartitionZeroExtension->CommonExtension));
2829
2830 //
2831 // Get the input parameters
2832 //
2833
2834 inputBuffer = (PDISK_GROW_PARTITION) Irp->AssociatedIrp.SystemBuffer;
2835
2836 ASSERT(inputBuffer);
2837
2838 //
2839 // Make sure that we are actually being asked to grow the partition.
2840 //
2841
2842 if(inputBuffer->BytesToGrow.QuadPart == 0) {
2843
2844 status = STATUS_INVALID_PARAMETER;
2845 ClassReleaseChildLock(fdoExtension);
2846 DiskReleasePartitioningLock(fdoExtension);
2847 break;
2848 }
2849
2850 //
2851 // Find the partition that matches the supplied number
2852 //
2853
2854 pdoExtension = &commonExtension->ChildList->CommonExtension;
2855
2856 while(pdoExtension != NULL) {
2857
2858 //
2859 // Is this the partition we are searching for?
2860 //
2861
2862 if(inputBuffer->PartitionNumber == pdoExtension->PartitionNumber) {
2863 break;
2864 }
2865
2866 pdoExtension = &pdoExtension->ChildList->CommonExtension;
2867 }
2868
2869 // Did we find the partition?
2870
2871 if(pdoExtension == NULL) {
2872 status = STATUS_INVALID_PARAMETER;
2873 ClassReleaseChildLock(fdoExtension);
2874 DiskReleasePartitioningLock(fdoExtension);
2875 break;
2876 }
2877
2878 ASSERT(pdoExtension);
2879
2880 //
2881 // Compute the new values for the partition to grow.
2882 //
2883
2884 newPartitionLength.QuadPart =
2885 (pdoExtension->PartitionLength.QuadPart +
2886 inputBuffer->BytesToGrow.QuadPart);
2887
2888 newStoppingOffset.QuadPart =
2889 (pdoExtension->StartingOffset.QuadPart +
2890 newPartitionLength.QuadPart - 1);
2891
2892 //
2893 // Test the partition alignment before getting to involved.
2894 //
2895 // NOTE:
2896 // All partition stopping offsets should be one byte less
2897 // than a cylinder boundary offset. Also, all first partitions
2898 // (within partition0 and within an extended partition) start
2899 // on the second track while all other partitions start on a
2900 // cylinder boundary.
2901 //
2902 bytesPerCylinder.QuadPart =
2903 ((LONGLONG) fdoExtension->DiskGeometry.TracksPerCylinder *
2904 (LONGLONG) fdoExtension->DiskGeometry.SectorsPerTrack *
2905 (LONGLONG) fdoExtension->DiskGeometry.BytesPerSector);
2906
2907 // Temporarily adjust up to cylinder boundary.
2908
2909 newStoppingOffset.QuadPart += 1;
2910
2911 if(newStoppingOffset.QuadPart % bytesPerCylinder.QuadPart) {
2912
2913 // Adjust the length first...
2914 newPartitionLength.QuadPart -=
2915 (newStoppingOffset.QuadPart % bytesPerCylinder.QuadPart);
2916
2917 // ...and then the stopping offset.
2918 newStoppingOffset.QuadPart -=
2919 (newStoppingOffset.QuadPart % bytesPerCylinder.QuadPart);
2920
2921 DebugPrint((2, "IOCTL_DISK_GROW_PARTITION: "
2922 "Adjusted the requested partition size to cylinder boundary"));
2923 }
2924
2925 // Restore to one byte less than a cylinder boundary.
2926 newStoppingOffset.QuadPart -= 1;
2927
2928 //
2929 // Will the new partition fit within Partition0?
2930 // Remember: commonExtension == &PartitionZeroExtension->CommonExtension
2931 //
2932
2933 if(newStoppingOffset.QuadPart >
2934 (commonExtension->StartingOffset.QuadPart +
2935 commonExtension->PartitionLength.QuadPart - 1)) {
2936
2937 //
2938 // The new partition falls outside Partition0
2939 //
2940
2941 status = STATUS_UNSUCCESSFUL;
2942 ClassReleaseChildLock(fdoExtension);
2943 DiskReleasePartitioningLock(fdoExtension);
2944 break;
2945 }
2946
2947 //
2948 // Search for any partition that will conflict with the new partition.
2949 // This is done before testing for any containing partitions to
2950 // simplify the container handling.
2951 //
2952
2953 sibling = commonExtension->ChildList;
2954
2955 while(sibling != NULL) {
2956 //LARGE_INTEGER sibStoppingOffset;
2957 PCOMMON_DEVICE_EXTENSION siblingExtension;
2958
2959 siblingExtension = &(sibling->CommonExtension);
2960
2961 ASSERT( siblingExtension );
2962
2963 /* sibStoppingOffset.QuadPart =
2964 (siblingExtension->StartingOffset.QuadPart +
2965 siblingExtension->PartitionLength.QuadPart - 1); */
2966
2967 //
2968 // Only check the siblings that start beyond the new partition
2969 // starting offset. Also, assume that since the starting offset
2970 // has not changed, it will not be in conflict with any other
2971 // partitions; only the new stopping offset needs to be tested.
2972 //
2973
2974 if((inputBuffer->PartitionNumber !=
2975 siblingExtension->PartitionNumber) &&
2976
2977 (siblingExtension->StartingOffset.QuadPart >
2978 pdoExtension->StartingOffset.QuadPart) &&
2979
2980 (newStoppingOffset.QuadPart >=
2981 siblingExtension->StartingOffset.QuadPart)) {
2982
2983 //
2984 // We have a conflict; bail out leaving pdoSibling set.
2985 //
2986
2987 break;
2988 }
2989 sibling = siblingExtension->ChildList;
2990 }
2991
2992
2993 //
2994 // If there is a sibling that conflicts, it will be in pdoSibling; there
2995 // could be more than one, but this is the first one detected.
2996 //
2997
2998 if(sibling != NULL) {
2999 //
3000 // Report the conflict and abort the grow request.
3001 //
3002
3003 status = STATUS_UNSUCCESSFUL;
3004 ClassReleaseChildLock(fdoExtension);
3005 DiskReleasePartitioningLock(fdoExtension);
3006 break;
3007 }
3008
3009 //
3010 // Read the partition table. Since we're planning on modifying it
3011 // we should bypass the cache.
3012 //
3013
3014 status = DiskReadPartitionTableEx(fdoExtension, TRUE, &layoutInfo );
3015
3016 if( !NT_SUCCESS(status) ) {
3017 ClassReleaseChildLock(fdoExtension);
3018 DiskReleasePartitioningLock(fdoExtension);
3019 break;
3020 }
3021
3022 ASSERT( layoutInfo );
3023
3024 //
3025 // Search the layout for the partition that matches the
3026 // PDO in hand.
3027 //
3028
3029 pdoPartition =
3030 DiskPdoFindPartitionEntry(
3031 (PPHYSICAL_DEVICE_EXTENSION) pdoExtension,
3032 layoutInfo);
3033
3034 if(pdoPartition == NULL) {
3035 // Looks like something is wrong interally-- error ok?
3036 status = STATUS_DRIVER_INTERNAL_ERROR;
3037 layoutInfo = NULL;
3038 ClassReleaseChildLock(fdoExtension);
3039 DiskReleasePartitioningLock(fdoExtension);
3040 break;
3041 }
3042
3043 //
3044 // Search the on-disk partition information to find the root containing
3045 // partition (top-to-bottom).
3046 //
3047 // Remember: commonExtension == &PartitionZeroExtension->CommonExtension
3048 //
3049
3050 //
3051 // All affected containers will have a new stopping offset
3052 // that is equal to the new partition (logical drive)
3053 // stopping offset. Walk the layout information from
3054 // bottom-to-top searching for logical drive containers and
3055 // propagating the change.
3056 //
3057
3058 containerPartition =
3059 DiskFindContainingPartition(
3060 layoutInfo,
3061 pdoPartition,
3062 FALSE);
3063
3064 //
3065 // This loop should only execute at most 2 times; once for
3066 // the logical drive container, and once for the root
3067 // extended partition container. If the growing partition
3068 // is not contained, the loop does not run.
3069 //
3070
3071 while(containerPartition != NULL) {
3072 LARGE_INTEGER containerStoppingOffset;
3073 PPARTITION_INFORMATION_EX nextContainerPartition;
3074
3075 //
3076 // Plan ahead and get the container's container before
3077 // modifying the current size.
3078 //
3079
3080 nextContainerPartition =
3081 DiskFindContainingPartition(
3082 layoutInfo,
3083 containerPartition,
3084 FALSE);
3085
3086 //
3087 // Figure out where the current container ends and test
3088 // to see if it already encompasses the containee.
3089 //
3090
3091 containerStoppingOffset.QuadPart =
3092 (containerPartition->StartingOffset.QuadPart +
3093 containerPartition->PartitionLength.QuadPart - 1);
3094
3095 if(newStoppingOffset.QuadPart <=
3096 containerStoppingOffset.QuadPart) {
3097
3098 //
3099 // No need to continue since this container fits
3100 //
3101 break;
3102 }
3103
3104 //
3105 // Adjust the container to have a stopping offset that
3106 // matches the grown partition stopping offset.
3107 //
3108
3109 containerPartition->PartitionLength.QuadPart =
3110 newStoppingOffset.QuadPart + 1 -
3111 containerPartition->StartingOffset.QuadPart;
3112
3113 containerPartition->RewritePartition = TRUE;
3114
3115 // Continue with the next container
3116 containerPartition = nextContainerPartition;
3117 }
3118
3119 //
3120 // Wait until after searching the containers to update the
3121 // partition size.
3122 //
3123
3124 pdoPartition->PartitionLength.QuadPart =
3125 newPartitionLength.QuadPart;
3126
3127 pdoPartition->RewritePartition = TRUE;
3128
3129 //
3130 // Commit the changes to disk
3131 //
3132
3133 status = DiskWritePartitionTableEx(fdoExtension, layoutInfo );
3134
3135 if( NT_SUCCESS(status) ) {
3136
3137 //
3138 // Everything looks good so commit the new length to the
3139 // PDO. This has to be done carefully. We may potentially
3140 // grow the partition in three steps:
3141 // * increase the high-word of the partition length
3142 // to be just below the new size - the high word should
3143 // be greater than or equal to the current length.
3144 //
3145 // * change the low-word of the partition length to the
3146 // new value - this value may potentially be lower than
3147 // the current value (if the high part was changed which
3148 // is why we changed that first)
3149 //
3150 // * change the high part to the correct value.
3151 //
3152
3153 if(newPartitionLength.HighPart >
3154 pdoExtension->PartitionLength.HighPart) {
3155
3156 //
3157 // Swap in one less than the high word.
3158 //
3159
3160 InterlockedExchange(
3161 &(pdoExtension->PartitionLength.HighPart),
3162 (newPartitionLength.HighPart - 1));
3163 }
3164
3165 //
3166 // Swap in the low part.
3167 //
3168
3169 InterlockedExchange(
3170 &(pdoExtension->PartitionLength.LowPart),
3171 newPartitionLength.LowPart);
3172
3173 if(newPartitionLength.HighPart !=
3174 pdoExtension->PartitionLength.HighPart) {
3175
3176 //
3177 // Swap in one less than the high word.
3178 //
3179
3180 InterlockedExchange(
3181 &(pdoExtension->PartitionLength.HighPart),
3182 newPartitionLength.HighPart);
3183 }
3184 }
3185
3186 //
3187 // Invalidate and free the cached partition table.
3188 //
3189
3190 DiskInvalidatePartitionTable(fdoExtension, TRUE);
3191
3192 //
3193 // Free the partition buffer regardless of the status
3194 //
3195
3196 ClassReleaseChildLock(fdoExtension);
3197 DiskReleasePartitioningLock(fdoExtension);
3198
3199 break;
3200 }
3201
3202
3203 case IOCTL_DISK_UPDATE_PROPERTIES: {
3204
3205 //
3206 // Invalidate the partition table and re-enumerate the device.
3207 //
3208
3209 if(DiskInvalidatePartitionTable(fdoExtension, FALSE)) {
3210 IoInvalidateDeviceRelations(fdoExtension->LowerPdo, BusRelations);
3211 }
3212 status = STATUS_SUCCESS;
3213
3214 break;
3215 }
3216
3217 case IOCTL_DISK_MEDIA_REMOVAL: {
3218
3219 //
3220 // If the disk is not removable then don't allow this command.
3221 //
3222
3223 DebugPrint((2, "IOCTL_DISK_MEDIA_REMOVAL to device %p through irp %p\n",
3224 DeviceObject, Irp));
3225 DebugPrint((2, "Device is a%s.\n",
3226 commonExtension->IsFdo ? "n fdo" : " pdo"));
3227
3228 if(!commonExtension->IsFdo) {
3229 ClassReleaseRemoveLock(DeviceObject, Irp);
3230 ExFreePool(srb);
3231 SendToFdo(DeviceObject,Irp,status);
3232 return status;
3233 }
3234
3235 if (!TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
3236 status = STATUS_INVALID_DEVICE_REQUEST;
3237 break;
3238 }
3239
3240 //
3241 // Fall through and let the class driver process the request.
3242 //
3243 goto defaultHandler;
3244
3245 }
3246
3247
3248
3249 defaultHandler:
3250 default: {
3251
3252 //
3253 // Free the Srb, since it is not needed.
3254 //
3255
3256 ExFreePool(srb);
3257
3258 //
3259 // Pass the request to the common device control routine.
3260 //
3261
3262 return(ClassDeviceControl(DeviceObject, Irp));
3263
3264 break;
3265 }
3266
3267 } // end switch
3268
3269 Irp->IoStatus.Status = status;
3270
3271 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
3272
3273 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
3274 }
3275
3276 ClassReleaseRemoveLock(DeviceObject, Irp);
3277 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
3278 ExFreePool(srb);
3279 return(status);
3280
3281 } // end DiskDeviceControl()
3282
3283 NTSTATUS
3284 NTAPI
3285 DiskShutdownFlush (
3286 IN PDEVICE_OBJECT DeviceObject,
3287 IN PIRP Irp
3288 )
3289
3290 /*++
3291
3292 Routine Description:
3293
3294 This routine is called for a shutdown and flush IRPs. These are sent by the
3295 system before it actually shuts down or when the file system does a flush.
3296 A synchronize cache command is sent to the device if it is write caching.
3297 If the device is removable an unlock command will be sent. This routine
3298 will sent a shutdown or flush Srb to the port driver.
3299
3300 Arguments:
3301
3302 DriverObject - Pointer to device object to being shutdown by system.
3303
3304 Irp - IRP involved.
3305
3306 Return Value:
3307
3308 NT Status
3309
3310 --*/
3311
3312 {
3313 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3314 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension;
3315
3316 PIO_STACK_LOCATION irpStack;
3317 PSCSI_REQUEST_BLOCK srb;
3318 NTSTATUS status;
3319 PCDB cdb;
3320
3321 //
3322 // Send partition flush requests to the FDO
3323 //
3324
3325 if(!commonExtension->IsFdo) {
3326
3327 PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject;
3328
3329 ClassReleaseRemoveLock(DeviceObject, Irp);
3330 IoMarkIrpPending(Irp);
3331 IoCopyCurrentIrpStackLocationToNext(Irp);
3332 IoCallDriver(lowerDevice, Irp);
3333 return STATUS_PENDING;
3334 }
3335
3336 //
3337 // Allocate SCSI request block.
3338 //
3339
3340 srb = ExAllocatePoolWithTag(NonPagedPool,
3341 sizeof(SCSI_REQUEST_BLOCK),
3342 DISK_TAG_SRB);
3343
3344 if (srb == NULL) {
3345
3346 //
3347 // Set the status and complete the request.
3348 //
3349
3350 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3351 ClassReleaseRemoveLock(DeviceObject, Irp);
3352 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
3353 return(STATUS_INSUFFICIENT_RESOURCES);
3354 }
3355
3356 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
3357
3358 //
3359 // Write length to SRB.
3360 //
3361
3362 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
3363
3364 //
3365 // Set timeout value and mark the request as not being a tagged request.
3366 //
3367
3368 srb->TimeOutValue = fdoExtension->TimeOutValue * 4;
3369 srb->QueueTag = SP_UNTAGGED;
3370 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
3371 srb->SrbFlags = fdoExtension->SrbFlags;
3372
3373 //
3374 // If the write cache is enabled then send a synchronize cache request.
3375 //
3376
3377 if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE)) {
3378
3379 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
3380 srb->CdbLength = 10;
3381
3382 srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
3383
3384 status = ClassSendSrbSynchronous(DeviceObject,
3385 srb,
3386 NULL,
3387 0,
3388 TRUE);
3389
3390 DebugPrint((1, "DiskShutdownFlush: Synchronize cache sent. Status = %lx\n", status ));
3391 }
3392
3393 //
3394 // Unlock the device if it is removable and this is a shutdown.
3395 //
3396
3397 irpStack = IoGetCurrentIrpStackLocation(Irp);
3398
3399 if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA) &&
3400 irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
3401
3402 srb->CdbLength = 6;
3403 cdb = (PVOID) srb->Cdb;
3404 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
3405 cdb->MEDIA_REMOVAL.Prevent = FALSE;
3406
3407 //
3408 // Set timeout value.
3409 //
3410
3411 srb->TimeOutValue = fdoExtension->TimeOutValue;
3412 status = ClassSendSrbSynchronous(DeviceObject,
3413 srb,
3414 NULL,
3415 0,
3416 TRUE);
3417
3418 DebugPrint((1, "DiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
3419 }
3420
3421 srb->CdbLength = 0;
3422
3423 //
3424 // Save a few parameters in the current stack location.
3425 //
3426
3427 srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
3428 SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
3429
3430 //
3431 // Set the retry count to zero.
3432 //
3433
3434 irpStack->Parameters.Others.Argument4 = (PVOID) 0;
3435
3436 //
3437 // Set up IoCompletion routine address.
3438 //
3439
3440 IoSetCompletionRoutine(Irp, ClassIoComplete, srb, TRUE, TRUE, TRUE);
3441
3442 //
3443 // Get next stack location and
3444 // set major function code.
3445 //
3446
3447 irpStack = IoGetNextIrpStackLocation(Irp);
3448
3449 irpStack->MajorFunction = IRP_MJ_SCSI;
3450
3451 //
3452 // Set up SRB for execute scsi request.
3453 // Save SRB address in next stack for port driver.
3454 //
3455
3456 irpStack->Parameters.Scsi.Srb = srb;
3457
3458 //
3459 // Set up Irp Address.
3460 //
3461
3462 srb->OriginalRequest = Irp;
3463
3464 //
3465 // Call the port driver to process the request.
3466 //
3467
3468 IoMarkIrpPending(Irp);
3469 IoCallDriver(commonExtension->LowerDeviceObject, Irp);
3470 return STATUS_PENDING;
3471 } // end DiskShutdown()
3472
3473 NTSTATUS
3474 NTAPI
3475 DiskModeSelect(
3476 IN PDEVICE_OBJECT Fdo,
3477 IN PCHAR ModeSelectBuffer,
3478 IN ULONG Length,
3479 IN BOOLEAN SavePage
3480 )
3481
3482 /*++
3483
3484 Routine Description:
3485
3486 This routine sends a mode select command.
3487
3488 Arguments:
3489
3490 DeviceObject - Supplies the device object associated with this request.
3491
3492 ModeSelectBuffer - Supplies a buffer containing the page data.
3493
3494 Length - Supplies the length in bytes of the mode select buffer.
3495
3496 SavePage - Indicates that parameters should be written to disk.
3497
3498 Return Value:
3499
3500 Length of the transferred data is returned.
3501
3502 --*/
3503
3504 {
3505 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3506 PCDB cdb;
3507 SCSI_REQUEST_BLOCK srb;
3508 ULONG retries = 1;
3509 ULONG length2;
3510 NTSTATUS status;
3511 PULONG buffer;
3512 PMODE_PARAMETER_BLOCK blockDescriptor;
3513
3514 PAGED_CODE();
3515
3516 ASSERT_FDO(Fdo);
3517
3518 length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
3519
3520 //
3521 // Allocate buffer for mode select header, block descriptor, and mode page.
3522 //
3523
3524 buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
3525 length2,
3526 DISK_TAG_MODE_DATA);
3527
3528 if(buffer == NULL) {
3529 return STATUS_INSUFFICIENT_RESOURCES;
3530 }
3531
3532 RtlZeroMemory(buffer, length2);
3533
3534 //
3535 // Set length in header to size of mode page.
3536 //
3537
3538 ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
3539
3540 blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
3541
3542 //
3543 // Set size
3544 //
3545
3546 blockDescriptor->BlockLength[1]=0x02;
3547
3548 //
3549 // Copy mode page to buffer.
3550 //
3551
3552 RtlCopyMemory(buffer + 3, ModeSelectBuffer, Length);
3553
3554 //
3555 // Zero SRB.
3556 //
3557
3558 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3559
3560 //
3561 // Build the MODE SELECT CDB.
3562 //
3563
3564 srb.CdbLength = 6;
3565 cdb = (PCDB)srb.Cdb;
3566
3567 //
3568 // Set timeout value from device extension.
3569 //
3570
3571 srb.TimeOutValue = fdoExtension->TimeOutValue * 2;
3572
3573 cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
3574 cdb->MODE_SELECT.SPBit = SavePage;
3575 cdb->MODE_SELECT.PFBit = 1;
3576 cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
3577
3578 Retry:
3579
3580 status = ClassSendSrbSynchronous(Fdo,
3581 &srb,
3582 buffer,
3583 length2,
3584 TRUE);
3585
3586 if (status == STATUS_VERIFY_REQUIRED) {
3587
3588 //
3589 // Routine ClassSendSrbSynchronous does not retry requests returned with
3590 // this status.
3591 //
3592
3593 if (retries--) {
3594
3595 //
3596 // Retry request.
3597 //
3598
3599 goto Retry;
3600 }
3601
3602 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3603 status = STATUS_SUCCESS;
3604 }
3605
3606 ExFreePool(buffer);
3607
3608 return status;
3609 } // end DiskModeSelect()
3610
3611 //
3612 // This routine is structured as a work-item routine
3613 //
3614 VOID
3615 NTAPI
3616 DisableWriteCache(
3617 IN PDEVICE_OBJECT Fdo,
3618 IN PIO_WORKITEM WorkItem
3619 )
3620
3621 {
3622 ULONG specialFlags = 0;
3623 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
3624 DISK_CACHE_INFORMATION cacheInfo;
3625 NTSTATUS status;
3626
3627 PAGED_CODE();
3628
3629 fdoExtension = Fdo->DeviceExtension;
3630
3631 ASSERT(fdoExtension->CommonExtension.IsFdo);
3632
3633 DebugPrint((1, "Disk.DisableWriteCache: Disabling Write Cache\n"));
3634
3635 ClassGetDeviceParameter(fdoExtension,
3636 DiskDeviceParameterSubkey,
3637 DiskDeviceSpecialFlags,
3638 &specialFlags);
3639
3640 RtlZeroMemory(&cacheInfo, sizeof(DISK_CACHE_INFORMATION));
3641
3642 status = DiskGetCacheInformation(fdoExtension, &cacheInfo);
3643
3644 if (NT_SUCCESS(status) && (cacheInfo.WriteCacheEnabled == TRUE)) {
3645
3646 cacheInfo.WriteCacheEnabled = FALSE;
3647
3648 status = DiskSetCacheInformation(fdoExtension, &cacheInfo);
3649
3650 if (status == STATUS_INVALID_DEVICE_REQUEST)
3651 {
3652 //
3653 // This device does not allow for
3654 // the write cache to be disabled
3655 //
3656 SET_FLAG(specialFlags, HackDisableWriteCacheNotSupported);
3657
3658 SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED);
3659 }
3660
3661 //
3662 // ISSUE ( April 5, 2001 ) : This should happen inside of DiskSetCacheInformation
3663 //
3664 CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3665 }
3666
3667 //
3668 // Set a flag in the registry to help
3669 // identify this device across boots
3670 //
3671 SET_FLAG(specialFlags, HackDisableWriteCache);
3672
3673 SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_WRITE_CACHE);
3674
3675 ClassSetDeviceParameter(fdoExtension,
3676 DiskDeviceParameterSubkey,
3677 DiskDeviceSpecialFlags,
3678 specialFlags);
3679
3680 IoFreeWorkItem(WorkItem);
3681 }
3682
3683 //
3684 // This routine is structured as a work-item routine
3685 //
3686 VOID
3687 NTAPI
3688 DiskIoctlVerify(
3689 IN PDEVICE_OBJECT Fdo,
3690 IN PDISK_VERIFY_WORKITEM_CONTEXT Context
3691 )
3692
3693 {
3694 PIRP Irp = Context->Irp;
3695 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = Fdo->DeviceExtension;
3696 PDISK_DATA DiskData = (PDISK_DATA)FdoExtension->CommonExtension.DriverData;
3697 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
3698 PSCSI_REQUEST_BLOCK Srb = Context->Srb;
3699 PCDB Cdb = (PCDB)Srb->Cdb;
3700 LARGE_INTEGER byteOffset;
3701 ULONG sectorOffset;
3702 USHORT sectorCount;
3703 NTSTATUS status = STATUS_SUCCESS;
3704
3705 PAGED_CODE();
3706
3707 ASSERT(FdoExtension->CommonExtension.IsFdo);
3708
3709 //
3710 // We don't need to hold on to this memory as
3711 // the following operation may take some time
3712 //
3713
3714 IoFreeWorkItem(Context->WorkItem);
3715
3716 DebugPrint((1, "Disk.DiskIoctlVerify: Splitting up the request\n"));
3717
3718 //
3719 // Add disk offset to starting the sector
3720 //
3721
3722 byteOffset.QuadPart = FdoExtension->CommonExtension.StartingOffset.QuadPart +
3723 verifyInfo->StartingOffset.QuadPart;
3724
3725 //
3726 // Convert byte offset to the sector offset
3727 //
3728
3729 sectorOffset = (ULONG)(byteOffset.QuadPart >> FdoExtension->SectorShift);
3730
3731 //
3732 // Convert ULONG byte count to USHORT sector count.
3733 //
3734
3735 sectorCount = (USHORT)(verifyInfo->Length >> FdoExtension->SectorShift);
3736
3737 //
3738 // Make sure that all previous verify requests have indeed completed
3739 // This greatly reduces the possibility of a Denial-of-Service attack
3740 //
3741
3742 KeWaitForMutexObject(&DiskData->VerifyMutex,
3743 Executive,
3744 KernelMode,
3745 FALSE,
3746 NULL);
3747
3748 while (NT_SUCCESS(status) && (sectorCount != 0))
3749 {
3750 USHORT numSectors = min(sectorCount, MAX_SECTORS_PER_VERIFY);
3751
3752 RtlZeroMemory(Srb, SCSI_REQUEST_BLOCK_SIZE);
3753
3754 Srb->CdbLength = 10;
3755
3756 Cdb->CDB10.OperationCode = SCSIOP_VERIFY;
3757
3758 //
3759 // Move little endian values into CDB in big endian format
3760 //
3761
3762 Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
3763 Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
3764 Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
3765 Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
3766
3767 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numSectors)->Byte1;
3768 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numSectors)->Byte0;
3769
3770 //
3771 // Calculate the request timeout value based
3772 // on the number of sectors being verified
3773 //
3774
3775 Srb->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue;
3776
3777 status = ClassSendSrbSynchronous(Fdo,
3778 Srb,
3779 NULL,
3780 0,
3781 FALSE);
3782
3783 ASSERT(status != STATUS_NONEXISTENT_SECTOR);
3784
3785 sectorCount -= numSectors;
3786 sectorOffset += numSectors;
3787 }
3788
3789 KeReleaseMutex(&DiskData->VerifyMutex, FALSE);
3790
3791 Irp->IoStatus.Status = status;
3792 Irp->IoStatus.Information = 0;
3793
3794 ClassReleaseRemoveLock(Fdo, Irp);
3795 ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT);
3796
3797 ExFreePool(Srb);
3798 ExFreePool(Context);
3799 }
3800
3801 VOID
3802 NTAPI
3803 DiskFdoProcessError(
3804 PDEVICE_OBJECT Fdo,
3805 PSCSI_REQUEST_BLOCK Srb,
3806 NTSTATUS *Status,
3807 BOOLEAN *Retry
3808 )
3809
3810 /*++
3811
3812 Routine Description:
3813
3814 This routine checks the type of error. If the error indicates an underrun
3815 then indicate the request should be retried.
3816
3817 Arguments:
3818
3819 Fdo - Supplies a pointer to the functional device object.
3820
3821 Srb - Supplies a pointer to the failing Srb.
3822
3823 Status - Status with which the IRP will be completed.
3824
3825 Retry - Indication of whether the request will be retried.
3826
3827 Return Value:
3828
3829 None.
3830
3831 --*/
3832
3833 {
3834 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3835 PCDB cdb = (PCDB)(Srb->Cdb);
3836
3837 ASSERT(fdoExtension->CommonExtension.IsFdo);
3838
3839 if (*Status == STATUS_DATA_OVERRUN &&
3840 ( cdb->CDB10.OperationCode == SCSIOP_WRITE ||
3841 cdb->CDB10.OperationCode == SCSIOP_READ)) {
3842
3843 *Retry = TRUE;
3844
3845 //
3846 // Update the error count for the device.
3847 //
3848
3849 fdoExtension->ErrorCount++;
3850
3851 } else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
3852 Srb->ScsiStatus == SCSISTAT_BUSY) {
3853
3854 //
3855 // a disk drive should never be busy this long. Reset the scsi bus
3856 // maybe this will clear the condition.
3857 //
3858
3859 ResetBus(Fdo);
3860
3861 //
3862 // Update the error count for the device.
3863 //
3864
3865 fdoExtension->ErrorCount++;
3866
3867 } else {
3868
3869 BOOLEAN invalidatePartitionTable = FALSE;
3870
3871 //
3872 // See if this might indicate that something on the drive has changed.
3873 //
3874
3875 if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
3876 (Srb->SenseInfoBufferLength >=
3877 FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation))) {
3878
3879 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
3880 ULONG senseKey = senseBuffer->SenseKey & 0xf;
3881 ULONG asc = senseBuffer->AdditionalSenseCode;
3882 ULONG ascq = senseBuffer->AdditionalSenseCodeQualifier;
3883
3884 switch (senseKey) {
3885
3886 case SCSI_SENSE_ILLEGAL_REQUEST: {
3887
3888 switch (asc) {
3889
3890 case SCSI_ADSENSE_INVALID_CDB: {
3891
3892 if (((cdb->CDB10.OperationCode == SCSIOP_READ) ||
3893 (cdb->CDB10.OperationCode == SCSIOP_WRITE)) &&
3894 (cdb->CDB10.ForceUnitAccess) &&
3895 TEST_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE)) {
3896
3897 //
3898 // This device does not permit FUA while
3899 // the DEV_WRITE_CACHE flag is turned on
3900 //
3901
3902 PIO_WORKITEM workItem = IoAllocateWorkItem(Fdo);
3903 if (workItem) {
3904
3905 IoQueueWorkItem(workItem,
3906 (PIO_WORKITEM_ROUTINE)DisableWriteCache,
3907 CriticalWorkQueue,
3908 workItem);
3909 }
3910
3911 cdb->CDB10.ForceUnitAccess = FALSE;
3912 *Retry = TRUE;
3913 }
3914
3915 break;
3916 }
3917 } // end switch(asc)
3918 break;
3919 }
3920
3921 case SCSI_SENSE_NOT_READY: {
3922
3923 switch (asc) {
3924 case SCSI_ADSENSE_LUN_NOT_READY: {
3925 switch (ascq) {
3926 case SCSI_SENSEQ_BECOMING_READY:
3927 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
3928 case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: {
3929 invalidatePartitionTable = TRUE;
3930 break;
3931 }
3932 } // end switch(ascq)
3933 break;
3934 }
3935
3936 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: {
3937 invalidatePartitionTable = TRUE;
3938 break;
3939 }
3940 } // end switch(asc)
3941 break;
3942 }
3943
3944 case SCSI_SENSE_MEDIUM_ERROR: {
3945 invalidatePartitionTable = TRUE;
3946 break;
3947 }
3948
3949 case SCSI_SENSE_HARDWARE_ERROR: {
3950 invalidatePartitionTable = TRUE;
3951 break;
3952 }
3953
3954 case SCSI_SENSE_UNIT_ATTENTION: {
3955 switch (senseBuffer->AdditionalSenseCode) {
3956 case SCSI_ADSENSE_MEDIUM_CHANGED: {
3957 invalidatePartitionTable = TRUE;
3958 break;
3959 }
3960 }
3961 break;
3962 }
3963
3964 case SCSI_SENSE_RECOVERED_ERROR: {
3965 invalidatePartitionTable = TRUE;
3966 break;
3967 }
3968
3969 } // end switch(senseKey)
3970 } else {
3971
3972 //
3973 // On any exceptional scsi condition which might indicate that the
3974 // device was changed we will flush out the state of the partition
3975 // table.
3976 //
3977
3978 switch (SRB_STATUS(Srb->SrbStatus)) {
3979 case SRB_STATUS_INVALID_LUN:
3980 case SRB_STATUS_INVALID_TARGET_ID:
3981 case SRB_STATUS_NO_DEVICE:
3982 case SRB_STATUS_NO_HBA:
3983 case SRB_STATUS_INVALID_PATH_ID:
3984 case SRB_STATUS_COMMAND_TIMEOUT:
3985 case SRB_STATUS_TIMEOUT:
3986 case SRB_STATUS_SELECTION_TIMEOUT:
3987 case SRB_STATUS_REQUEST_FLUSHED:
3988 case SRB_STATUS_UNEXPECTED_BUS_FREE:
3989 case SRB_STATUS_PARITY_ERROR:
3990 case SRB_STATUS_ERROR: {
3991 invalidatePartitionTable = TRUE;
3992 break;
3993 }
3994 } // end switch(Srb->SrbStatus)
3995 }
3996
3997 if(invalidatePartitionTable) {
3998 if(DiskInvalidatePartitionTable(fdoExtension, FALSE)) {
3999 IoInvalidateDeviceRelations(fdoExtension->LowerPdo,
4000 BusRelations);
4001 }
4002 }
4003 }
4004 return;
4005 }
4006
4007 VOID
4008 NTAPI
4009 DiskSetSpecialHacks(
4010 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
4011 IN ULONG_PTR Data
4012 )
4013
4014 /*++
4015
4016 Routine Description:
4017
4018 This function checks to see if an SCSI logical unit requires special
4019 flags to be set.
4020
4021 Arguments:
4022
4023 Fdo - Supplies the device object to be tested.
4024
4025 InquiryData - Supplies the inquiry data returned by the device of interest.
4026
4027 AdapterDescriptor - Supplies the capabilities of the device object.
4028
4029 Return Value:
4030
4031 None.
4032
4033 --*/
4034
4035 {
4036 PDEVICE_OBJECT fdo = FdoExtension->DeviceObject;
4037
4038 PAGED_CODE();
4039
4040 DebugPrint((1, "Disk SetSpecialHacks, Setting Hacks %p\n", Data));
4041
4042 //
4043 // Found a listed controller. Determine what must be done.
4044 //
4045
4046 if (TEST_FLAG(Data, HackDisableTaggedQueuing)) {
4047
4048 //
4049 // Disable tagged queuing.
4050 //
4051
4052 CLEAR_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
4053 }
4054
4055 if (TEST_FLAG(Data, HackDisableSynchronousTransfers)) {
4056
4057 //
4058 // Disable synchronous data transfers.
4059 //
4060
4061 SET_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
4062
4063 }
4064
4065 if (TEST_FLAG(Data, HackDisableSpinDown)) {
4066
4067 //
4068 // Disable spinning down of drives.
4069 //
4070
4071 SET_FLAG(FdoExtension->ScanForSpecialFlags,
4072 CLASS_SPECIAL_DISABLE_SPIN_DOWN);
4073
4074 }
4075
4076 if (TEST_FLAG(Data, HackDisableWriteCache)) {
4077
4078 //
4079 // Disable the drive's write cache
4080 //
4081
4082 SET_FLAG(FdoExtension->ScanForSpecialFlags,
4083 CLASS_SPECIAL_DISABLE_WRITE_CACHE);
4084
4085 }
4086
4087 if (TEST_FLAG(Data, HackCauseNotReportableHack)) {
4088
4089 SET_FLAG(FdoExtension->ScanForSpecialFlags,
4090 CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK);
4091 }
4092
4093 if (TEST_FLAG(fdo->Characteristics, FILE_REMOVABLE_MEDIA) &&
4094 TEST_FLAG(Data, HackRequiresStartUnitCommand)
4095 ) {
4096
4097 //
4098 // this is a list of vendors who require the START_UNIT command
4099 //
4100
4101 DebugPrint((1, "DiskScanForSpecial (%p) => This unit requires "
4102 " START_UNITS\n", fdo));
4103 SET_FLAG(FdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
4104
4105 }
4106
4107 return;
4108 }
4109
4110 VOID
4111 NTAPI
4112 DiskScanRegistryForSpecial(
4113 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
4114 )
4115
4116 /*++
4117
4118 Routine Description:
4119
4120 This function checks the registry to see if the SCSI logical unit
4121 requires special attention.
4122
4123 Arguments:
4124
4125 Fdo - Supplies the device object to be tested.
4126
4127 Return Value:
4128
4129 None.
4130
4131 --*/
4132
4133 {
4134 ULONG specialFlags = 0;
4135
4136 PAGED_CODE();
4137
4138 ClassGetDeviceParameter(FdoExtension, DiskDeviceParameterSubkey, DiskDeviceSpecialFlags, &specialFlags);
4139
4140 if (TEST_FLAG(specialFlags, HackDisableWriteCache))
4141 {
4142 //
4143 // This device had previously failed to perform an FUA with the DEV_WRITE_CACHE
4144 // flag turned on. Set a bit to inform DiskStartFdo() to disable the write cache
4145 //
4146
4147 SET_FLAG(FdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_WRITE_CACHE);
4148 }
4149
4150 if (TEST_FLAG(specialFlags, HackDisableWriteCacheNotSupported))
4151 {
4152 //
4153 // This device does not permit disabling of the write cache
4154 //
4155
4156 SET_FLAG(FdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED);
4157 }
4158 }
4159
4160 VOID
4161 NTAPI
4162 ResetBus(
4163 IN PDEVICE_OBJECT Fdo
4164 )
4165
4166 /*++
4167
4168 Routine Description:
4169
4170 This command sends a reset bus command to the SCSI port driver.
4171
4172 Arguments:
4173
4174 Fdo - The functional device object for the logical unit with hardware problem.
4175
4176 Return Value:
4177
4178 None.
4179
4180 --*/
4181
4182 {
4183 PIO_STACK_LOCATION irpStack;
4184 PIRP irp;
4185
4186 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
4187 PSCSI_REQUEST_BLOCK srb;
4188 PCOMPLETION_CONTEXT context;
4189
4190 DebugPrint((1, "Disk ResetBus: Sending reset bus request to port driver.\n"));
4191
4192 //
4193 // Allocate Srb from nonpaged pool.
4194 //
4195
4196 context = ExAllocatePoolWithTag(NonPagedPool,
4197 sizeof(COMPLETION_CONTEXT),
4198 DISK_TAG_CCONTEXT);
4199
4200 if(context == NULL) {
4201 return;
4202 }
4203
4204 //
4205 // Save the device object in the context for use by the completion
4206 // routine.
4207 //
4208
4209 context->DeviceObject = Fdo;
4210 srb = &context->Srb;
4211
4212 //
4213 // Zero out srb.
4214 //
4215
4216 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
4217
4218 //
4219 // Write length to SRB.
4220 //
4221
4222 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4223
4224 srb->Function = SRB_FUNCTION_RESET_BUS;
4225
4226 //
4227 // Build the asynchronous request to be sent to the port driver.
4228 // Since this routine is called from a DPC the IRP should always be
4229 // available.
4230 //
4231
4232 irp = IoAllocateIrp(Fdo->StackSize, FALSE);
4233
4234 if(irp == NULL) {
4235 ExFreePool(context);
4236 return;
4237 }
4238
4239 ClassAcquireRemoveLock(Fdo, irp);
4240
4241 IoSetCompletionRoutine(irp,
4242 (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
4243 context,
4244 TRUE,
4245 TRUE,
4246 TRUE);
4247
4248 irpStack = IoGetNextIrpStackLocation(irp);
4249
4250 irpStack->MajorFunction = IRP_MJ_SCSI;
4251
4252 srb->OriginalRequest = irp;
4253
4254 //
4255 // Store the SRB address in next stack for port driver.
4256 //
4257
4258 irpStack->Parameters.Scsi.Srb = srb;
4259
4260 //
4261 // Call the port driver with the IRP.
4262 //
4263
4264 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
4265
4266 return;
4267
4268 } // end ResetBus()
4269
4270 NTSTATUS
4271 NTAPI
4272 DiskQueryPnpCapabilities(
4273 IN PDEVICE_OBJECT DeviceObject,
4274 IN PDEVICE_CAPABILITIES Capabilities
4275 )
4276
4277 {
4278 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4279 //PDISK_DATA diskData = commonExtension->DriverData;
4280
4281 PAGED_CODE();
4282
4283 ASSERT(DeviceObject);
4284 ASSERT(Capabilities);
4285
4286 if(commonExtension->IsFdo) {
4287 return STATUS_NOT_IMPLEMENTED;
4288 } else {
4289
4290 //PPHYSICAL_DEVICE_EXTENSION physicalExtension = DeviceObject->DeviceExtension;
4291
4292 Capabilities->SilentInstall = 1;
4293 Capabilities->RawDeviceOK = 1;
4294 Capabilities->Address = commonExtension->PartitionNumber;
4295
4296 if(!TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
4297
4298 //
4299 // Media's not removable, deviceId/DeviceInstance should be
4300 // globally unique.
4301 //
4302
4303 Capabilities->UniqueID = 1;
4304 } else {
4305 Capabilities->UniqueID = 0;
4306 }
4307 }
4308
4309 return STATUS_SUCCESS;
4310 }
4311
4312 NTSTATUS
4313 NTAPI
4314 DiskGetCacheInformation(
4315 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
4316 IN PDISK_CACHE_INFORMATION CacheInfo
4317 )
4318
4319 {
4320 PMODE_PARAMETER_HEADER modeData;
4321 PMODE_CACHING_PAGE pageData;
4322
4323 ULONG length;
4324
4325 //NTSTATUS status;
4326
4327 PAGED_CODE();
4328
4329 modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
4330 MODE_DATA_SIZE,
4331 DISK_TAG_DISABLE_CACHE);
4332
4333 if (modeData == NULL) {
4334
4335 DebugPrint((1, "DiskGetSetCacheInformation: Unable to allocate mode "
4336 "data buffer\n"));
4337 return STATUS_INSUFFICIENT_RESOURCES;
4338 }
4339
4340 RtlZeroMemory(modeData, MODE_DATA_SIZE);
4341
4342 length = ClassModeSense(FdoExtension->DeviceObject,
4343 (PUCHAR) modeData,
4344 MODE_DATA_SIZE,
4345 MODE_SENSE_RETURN_ALL);
4346
4347 if (length < sizeof(MODE_PARAMETER_HEADER)) {
4348
4349 //
4350 // Retry the request in case of a check condition.
4351 //
4352
4353 length = ClassModeSense(FdoExtension->DeviceObject,
4354 (PUCHAR) modeData,
4355 MODE_DATA_SIZE,
4356 MODE_SENSE_RETURN_ALL);
4357
4358 if (length < sizeof(MODE_PARAMETER_HEADER)) {
4359
4360
4361 DebugPrint((1, "Disk.DisableWriteCache: Mode Sense failed\n"));
4362
4363 ExFreePool(modeData);
4364 return STATUS_IO_DEVICE_ERROR;
4365 }
4366 }
4367
4368 //
4369 // If the length is greater than length indicated by the mode data reset
4370 // the data to the mode data.
4371 //
4372
4373 if (length > (ULONG) (modeData->ModeDataLength + 1)) {
4374 length = modeData->ModeDataLength + 1;
4375 }
4376
4377 //
4378 // Check to see if the write cache is enabled.
4379 //
4380
4381 pageData = ClassFindModePage((PUCHAR) modeData,
4382 length,
4383 MODE_PAGE_CACHING,
4384 TRUE);
4385
4386 //
4387 // Check if valid caching page exists.
4388 //
4389
4390 if (pageData == NULL) {
4391 ExFreePool(modeData);
4392 return STATUS_NOT_SUPPORTED;
4393 }
4394
4395 //
4396 // Copy the parameters over.
4397 //
4398
4399 RtlZeroMemory(CacheInfo, sizeof(DISK_CACHE_INFORMATION));
4400
4401 CacheInfo->ParametersSavable = pageData->PageSavable;
4402
4403 CacheInfo->ReadCacheEnabled = !(pageData->ReadDisableCache);
4404 CacheInfo->WriteCacheEnabled = pageData->WriteCacheEnable;
4405
4406 CacheInfo->ReadRetentionPriority = pageData->ReadRetensionPriority;
4407 CacheInfo->WriteRetentionPriority = pageData->WriteRetensionPriority;
4408
4409 CacheInfo->DisablePrefetchTransferLength =
4410 ((pageData->DisablePrefetchTransfer[0] << 8) +
4411 pageData->DisablePrefetchTransfer[1]);
4412
4413 CacheInfo->ScalarPrefetch.Minimum =
4414 ((pageData->MinimumPrefetch[0] << 8) + pageData->MinimumPrefetch[1]);
4415
4416 CacheInfo->ScalarPrefetch.Maximum =
4417 ((pageData->MaximumPrefetch[0] << 8) + pageData->MaximumPrefetch[1]);
4418
4419 if(pageData->MultiplicationFactor) {
4420 CacheInfo->PrefetchScalar = TRUE;
4421 CacheInfo->ScalarPrefetch.MaximumBlocks =
4422 ((pageData->MaximumPrefetchCeiling[0] << 8) +
4423 pageData->MaximumPrefetchCeiling[1]);
4424 }
4425
4426 ExFreePool(modeData);
4427 return STATUS_SUCCESS;
4428 }
4429
4430 NTSTATUS
4431 NTAPI
4432 DiskSetCacheInformation(
4433 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
4434 IN PDISK_CACHE_INFORMATION CacheInfo
4435 )
4436
4437 {
4438 PMODE_PARAMETER_HEADER modeData;
4439 ULONG length;
4440
4441 PMODE_CACHING_PAGE pageData;
4442
4443 ULONG i;
4444
4445 ULONG errorCode;
4446 NTSTATUS status;
4447
4448 PAGED_CODE();
4449
4450 modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
4451 MODE_DATA_SIZE,
4452 DISK_TAG_DISABLE_CACHE);
4453
4454 if (modeData == NULL) {
4455
4456 DebugPrint((1, "DiskSetCacheInformation: Unable to allocate mode "
4457 "data buffer\n"));
4458 return STATUS_INSUFFICIENT_RESOURCES;
4459 }
4460
4461 RtlZeroMemory(modeData, MODE_DATA_SIZE);
4462
4463 length = ClassModeSense(FdoExtension->DeviceObject,
4464 (PUCHAR) modeData,
4465 MODE_DATA_SIZE,
4466 MODE_PAGE_CACHING);
4467
4468 if (length < sizeof(MODE_PARAMETER_HEADER)) {
4469
4470 //
4471 // Retry the request in case of a check condition.
4472 //
4473
4474 length = ClassModeSense(FdoExtension->DeviceObject,
4475 (PUCHAR) modeData,
4476 MODE_DATA_SIZE,
4477 MODE_PAGE_CACHING);
4478
4479 if (length < sizeof(MODE_PARAMETER_HEADER)) {
4480
4481
4482 DebugPrint((1, "Disk.DisableWriteCache: Mode Sense failed\n"));
4483
4484 ExFreePool(modeData);
4485 return STATUS_IO_DEVICE_ERROR;
4486 }
4487 }
4488
4489 //
4490 // If the length is greater than length indicated by the mode data reset
4491 // the data to the mode data.
4492 //
4493
4494 if (length > (ULONG) (modeData->ModeDataLength + 1)) {
4495 length = modeData->ModeDataLength + 1;
4496 }
4497
4498 //
4499 // Check to see if the write cache is enabled.
4500 //
4501
4502 pageData = ClassFindModePage((PUCHAR) modeData,
4503 length,
4504 MODE_PAGE_CACHING,
4505 TRUE);
4506
4507 //
4508 // Check if valid caching page exists.
4509 //
4510
4511 if (pageData == NULL) {
4512 ExFreePool(modeData);
4513 return STATUS_NOT_SUPPORTED;
4514 }
4515
4516 //
4517 // Don't touch any of the normal parameters - not all drives actually
4518 // use the correct size of caching mode page. Just change the things
4519 // which the user could have modified.
4520 //
4521
4522 pageData->PageSavable = FALSE;
4523
4524 pageData->ReadDisableCache = !(CacheInfo->ReadCacheEnabled);
4525 pageData->MultiplicationFactor = CacheInfo->PrefetchScalar;
4526 pageData->WriteCacheEnable = CacheInfo->WriteCacheEnabled;
4527
4528 pageData->WriteRetensionPriority = (UCHAR) CacheInfo->WriteRetentionPriority;
4529 pageData->ReadRetensionPriority = (UCHAR) CacheInfo->ReadRetentionPriority;
4530
4531 pageData->DisablePrefetchTransfer[0] =
4532 (UCHAR) (CacheInfo->DisablePrefetchTransferLength >> 8);
4533 pageData->DisablePrefetchTransfer[1] =
4534 (UCHAR) (CacheInfo->DisablePrefetchTransferLength & 0x00ff);
4535
4536 pageData->MinimumPrefetch[0] =
4537 (UCHAR) (CacheInfo->ScalarPrefetch.Minimum >> 8);
4538 pageData->MinimumPrefetch[1] =
4539 (UCHAR) (CacheInfo->ScalarPrefetch.Minimum & 0x00ff);
4540
4541 pageData->MaximumPrefetch[0] =
4542 (UCHAR) (CacheInfo->ScalarPrefetch.Maximum >> 8);
4543 pageData->MaximumPrefetch[1] =
4544 (UCHAR) (CacheInfo->ScalarPrefetch.Maximum & 0x00ff);
4545
4546 if(pageData->MultiplicationFactor) {
4547
4548 pageData->MaximumPrefetchCeiling[0] =
4549 (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks >> 8);
4550 pageData->MaximumPrefetchCeiling[1] =
4551 (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks & 0x00ff);
4552 }
4553
4554 //
4555 // We will attempt (twice) to issue the mode select with the page.
4556 //
4557
4558 //
4559 // First save away the current state of the disk cache so we know what to
4560 // log if the request fails.
4561 //
4562
4563 if(TEST_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE)) {
4564 errorCode = IO_WRITE_CACHE_ENABLED;
4565 } else {
4566 errorCode = IO_WRITE_CACHE_DISABLED;
4567 }
4568
4569 for(i = 0; i < 2; i++) {
4570 status = DiskModeSelect(FdoExtension->DeviceObject,
4571 (PUCHAR) pageData,
4572 (pageData->PageLength + 2),
4573 CacheInfo->ParametersSavable);
4574
4575 if(NT_SUCCESS(status)) {
4576 if(CacheInfo->WriteCacheEnabled) {
4577 SET_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
4578 errorCode = IO_WRITE_CACHE_ENABLED;
4579 } else {
4580 CLEAR_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
4581 errorCode = IO_WRITE_CACHE_DISABLED;
4582 }
4583
4584 break;
4585 }
4586 }
4587
4588 {
4589 PIO_ERROR_LOG_PACKET logEntry;
4590
4591 //
4592 // Log the appropriate informational or error entry.
4593 //
4594
4595 logEntry = IoAllocateErrorLogEntry(
4596 FdoExtension->DeviceObject,
4597 sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG)));
4598
4599 if (logEntry != NULL) {
4600
4601 PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
4602
4603 logEntry->FinalStatus = status;
4604 logEntry->ErrorCode = errorCode;
4605 logEntry->SequenceNumber = 0;
4606 logEntry->MajorFunctionCode = IRP_MJ_SCSI;
4607 logEntry->IoControlCode = 0;
4608 logEntry->RetryCount = 0;
4609 logEntry->UniqueErrorValue = 0x1;
4610 logEntry->DumpDataSize = 4;
4611
4612 logEntry->DumpData[0] = diskData->ScsiAddress.PathId;
4613 logEntry->DumpData[1] = diskData->ScsiAddress.TargetId;
4614 logEntry->DumpData[2] = diskData->ScsiAddress.Lun;
4615 logEntry->DumpData[3] = CacheInfo->WriteCacheEnabled;
4616
4617 //
4618 // Write the error log packet.
4619 //
4620
4621 IoWriteErrorLogEntry(logEntry);
4622 }
4623 }
4624
4625 ExFreePool(modeData);
4626 return status;
4627 }
4628
4629 PPARTITION_INFORMATION_EX
4630 NTAPI
4631 DiskPdoFindPartitionEntry(
4632 IN PPHYSICAL_DEVICE_EXTENSION Pdo,
4633 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
4634 )
4635
4636 {
4637 PCOMMON_DEVICE_EXTENSION commonExtension= &(Pdo->CommonExtension);
4638 ULONG partitionIndex;
4639
4640 PAGED_CODE();
4641
4642
4643 DebugPrint((1, "DiskPdoFindPartitionEntry: Searching layout for "
4644 "matching partition.\n"));
4645
4646 for(partitionIndex = 0;
4647 partitionIndex < LayoutInfo->PartitionCount;
4648 partitionIndex++) {
4649
4650 PPARTITION_INFORMATION_EX partitionInfo;
4651
4652 //
4653 // Get the partition entry
4654 //
4655
4656 partitionInfo = &LayoutInfo->PartitionEntry[partitionIndex];
4657
4658 //
4659 // See if it is the one we are looking for...
4660 //
4661
4662 if( LayoutInfo->PartitionStyle == PARTITION_STYLE_MBR &&
4663 (partitionInfo->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
4664 IsContainerPartition(partitionInfo->Mbr.PartitionType)) ) {
4665
4666 continue;
4667 }
4668
4669 if( LayoutInfo->PartitionStyle == PARTITION_STYLE_GPT &&
4670 DiskCompareGuid (&partitionInfo->Gpt.PartitionType, &GUID_NULL) == 00) {
4671
4672 continue;
4673 }
4674
4675 if( (commonExtension->StartingOffset.QuadPart ==
4676 partitionInfo->StartingOffset.QuadPart) &&
4677 (commonExtension->PartitionLength.QuadPart ==
4678 partitionInfo->PartitionLength.QuadPart)) {
4679
4680 //
4681 // Found it!
4682 //
4683
4684 DebugPrint((1, "DiskPdoFindPartitionEntry: Found matching "
4685 "partition.\n"));
4686 return partitionInfo;
4687 }
4688 }
4689
4690 return NULL;
4691 }
4692
4693 PPARTITION_INFORMATION_EX
4694 NTAPI
4695 DiskFindAdjacentPartition(
4696 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
4697 IN PPARTITION_INFORMATION_EX BasePartition
4698 )
4699 {
4700 ULONG partitionIndex;
4701 LONGLONG baseStoppingOffset;
4702 LONGLONG adjacentStartingOffset;
4703 PPARTITION_INFORMATION_EX adjacentPartition = 0;
4704
4705 ASSERT(LayoutInfo && BasePartition);
4706
4707 PAGED_CODE();
4708
4709 DebugPrint((1, "DiskPdoFindAdjacentPartition: Searching layout for adjacent partition.\n"));
4710
4711 //
4712 // Construct the base stopping offset for comparison
4713 //
4714
4715 baseStoppingOffset = (BasePartition->StartingOffset.QuadPart +
4716 BasePartition->PartitionLength.QuadPart -
4717 1);
4718
4719 adjacentStartingOffset = MAXLONGLONG;
4720
4721 for(partitionIndex = 0;
4722 partitionIndex < LayoutInfo->PartitionCount;
4723 partitionIndex++) {
4724
4725 PPARTITION_INFORMATION_EX partitionInfo;
4726
4727 //
4728 // Get the partition entry
4729 //
4730
4731 partitionInfo = &LayoutInfo->PartitionEntry[partitionIndex];
4732
4733 //
4734 // See if it is the one we are looking for...
4735 //
4736
4737 if( LayoutInfo->PartitionStyle == PARTITION_STYLE_MBR &&
4738 partitionInfo->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ) {
4739
4740 continue;
4741 }
4742
4743 if( LayoutInfo->PartitionStyle == PARTITION_STYLE_GPT &&
4744 DiskCompareGuid (&partitionInfo->Gpt.PartitionType, &GUID_NULL) == 00 ) {
4745
4746 continue;
4747 }
4748
4749
4750 if((partitionInfo->StartingOffset.QuadPart > baseStoppingOffset) &&
4751 (partitionInfo->StartingOffset.QuadPart < adjacentStartingOffset)) {
4752
4753 // Found a closer neighbor...update and remember.
4754 adjacentPartition = partitionInfo;
4755
4756 adjacentStartingOffset = adjacentPartition->StartingOffset.QuadPart;
4757
4758 DebugPrint((1, "DiskPdoFindAdjacentPartition: Found adjacent "
4759 "partition.\n"));
4760 }
4761 }
4762 return adjacentPartition;
4763 }
4764
4765 PPARTITION_INFORMATION_EX
4766 NTAPI
4767 DiskFindContainingPartition(
4768 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
4769 IN PPARTITION_INFORMATION_EX BasePartition,
4770 IN BOOLEAN SearchTopToBottom
4771 )
4772
4773 {
4774
4775 LONG partitionIndex;
4776 LONG startIndex;
4777 LONG stopIndex;
4778 LONG stepIndex;
4779
4780 LONGLONG baseStoppingOffset;
4781 LONGLONG containerStoppingOffset;
4782
4783 PPARTITION_INFORMATION_EX partitionInfo = 0;
4784 PPARTITION_INFORMATION_EX containerPartition = 0;
4785
4786 PAGED_CODE();
4787
4788 ASSERT( LayoutInfo && BasePartition);
4789
4790 DebugPrint((1, "DiskFindContainingPartition: Searching for extended partition.\n"));
4791
4792 if( LayoutInfo->PartitionCount != 0) {
4793
4794 baseStoppingOffset = (BasePartition->StartingOffset.QuadPart +
4795 BasePartition->PartitionLength.QuadPart - 1);
4796
4797 //
4798 // Determine the search direction and setup the loop
4799 //
4800 if(SearchTopToBottom == TRUE) {
4801
4802 startIndex = 0;
4803 stopIndex = LayoutInfo->PartitionCount;
4804 stepIndex = +1;
4805 } else {
4806 startIndex = LayoutInfo->PartitionCount - 1;
4807 stopIndex = -1;
4808 stepIndex = -1;
4809 }
4810
4811 //
4812 // Using the loop parameters, walk the layout information and
4813 // return the first containing partition.
4814 //
4815
4816 for(partitionIndex = startIndex;
4817 partitionIndex != stopIndex;
4818 partitionIndex += stepIndex) {
4819
4820 //
4821 // Get the next partition entry
4822 //
4823
4824 partitionInfo = &LayoutInfo->PartitionEntry[partitionIndex];
4825
4826 containerStoppingOffset = (partitionInfo->StartingOffset.QuadPart +
4827 partitionInfo->PartitionLength.QuadPart -
4828 1);
4829
4830 //
4831 // Search for a containing partition without detecting the
4832 // same partition as a container of itself. The starting
4833 // offset of a partition and its container should never be
4834 // the same; however, the stopping offset can be the same.
4835 //
4836
4837 //
4838 // NOTE: Container partitions are MBR only.
4839 //
4840
4841 if((LayoutInfo->PartitionStyle == PARTITION_STYLE_MBR) &&
4842 (IsContainerPartition(partitionInfo->Mbr.PartitionType)) &&
4843 (BasePartition->StartingOffset.QuadPart >
4844 partitionInfo->StartingOffset.QuadPart) &&
4845 (baseStoppingOffset <= containerStoppingOffset)) {
4846
4847 containerPartition = partitionInfo;
4848
4849 DebugPrint((1, "DiskFindContainingPartition: Found a "
4850 "containing extended partition.\n"));
4851
4852 break;
4853 }
4854 }
4855 }
4856
4857 return containerPartition;
4858 }
4859
4860 NTSTATUS
4861 NTAPI
4862 DiskGetInfoExceptionInformation(
4863 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
4864 IN PMODE_INFO_EXCEPTIONS ReturnPageData
4865 )
4866 {
4867 PMODE_PARAMETER_HEADER modeData;
4868 PMODE_INFO_EXCEPTIONS pageData;
4869 ULONG length;
4870
4871 NTSTATUS status;
4872
4873 PAGED_CODE();
4874
4875 //
4876 // ReturnPageData is allocated by the caller
4877 //
4878
4879 modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
4880 MODE_DATA_SIZE,
4881 DISK_TAG_INFO_EXCEPTION);
4882
4883 if (modeData == NULL) {
4884
4885 DebugPrint((1, "DiskGetInfoExceptionInformation: Unable to allocate mode "
4886 "data buffer\n"));
4887 return STATUS_INSUFFICIENT_RESOURCES;
4888 }
4889
4890 RtlZeroMemory(modeData, MODE_DATA_SIZE);
4891
4892 length = ClassModeSense(FdoExtension->DeviceObject,
4893 (PUCHAR) modeData,
4894 MODE_DATA_SIZE,
4895 MODE_PAGE_FAULT_REPORTING);
4896
4897 if (length < sizeof(MODE_PARAMETER_HEADER)) {
4898
4899 //
4900 // Retry the request in case of a check condition.
4901 //
4902
4903 length = ClassModeSense(FdoExtension->DeviceObject,
4904 (PUCHAR) modeData,
4905 MODE_DATA_SIZE,
4906 MODE_PAGE_FAULT_REPORTING);
4907
4908 if (length < sizeof(MODE_PARAMETER_HEADER)) {
4909
4910
4911 DebugPrint((1, "Disk.DisableWriteCache: Mode Sense failed\n"));
4912
4913 ExFreePool(modeData);
4914 return STATUS_IO_DEVICE_ERROR;
4915 }
4916 }
4917
4918 //
4919 // If the length is greater than length indicated by the mode data reset
4920 // the data to the mode data.
4921 //
4922
4923 if (length > (ULONG) (modeData->ModeDataLength + 1)) {
4924 length = modeData->ModeDataLength + 1;
4925 }
4926
4927 //
4928 // Find the mode page for info exceptions
4929 //
4930
4931 pageData = ClassFindModePage((PUCHAR) modeData,
4932 length,
4933 MODE_PAGE_FAULT_REPORTING,
4934 TRUE);
4935
4936 if (pageData != NULL) {
4937 RtlCopyMemory(ReturnPageData, pageData, sizeof(MODE_INFO_EXCEPTIONS));
4938 status = STATUS_SUCCESS;
4939 } else {
4940 status = STATUS_NOT_SUPPORTED;
4941 }
4942
4943 DebugPrint((3, "DiskGetInfoExceptionInformation: %s support SMART for device %x\n",
4944 NT_SUCCESS(status) ? "does" : "does not",
4945 FdoExtension->DeviceObject));
4946
4947
4948 ExFreePool(modeData);
4949 return(status);
4950 }
4951
4952 NTSTATUS
4953 NTAPI
4954 DiskSetInfoExceptionInformation(
4955 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
4956 IN PMODE_INFO_EXCEPTIONS PageData
4957 )
4958
4959 {
4960 ULONG i;
4961 NTSTATUS status;
4962
4963 PAGED_CODE();
4964
4965 //
4966 // We will attempt (twice) to issue the mode select with the page.
4967 // Make the setting persistent so that we don't have to turn it back
4968 // on after a bus reset.
4969 //
4970
4971 for (i = 0; i < 2; i++)
4972 {
4973 status = DiskModeSelect(FdoExtension->DeviceObject,
4974 (PUCHAR) PageData,
4975 sizeof(MODE_INFO_EXCEPTIONS),
4976 TRUE);
4977
4978 }
4979
4980 DebugPrint((3, "DiskSetInfoExceptionInformation: %s for device %p\n",
4981 NT_SUCCESS(status) ? "succeeded" : "failed",
4982 FdoExtension->DeviceObject));
4983
4984 return status;
4985 }
4986
4987
4988 #if 0
4989 #if defined(_X86_)
4990
4991 NTSTATUS
4992 DiskQuerySuggestedLinkName(
4993 IN PDEVICE_OBJECT DeviceObject,
4994 IN PIRP Irp
4995 )
4996
4997 /*++
4998
4999 Routine Description:
5000
5001 The routine try to find a suggested link name from registry for Removable
5002 using device object names of NT4 and NT3.51.
5003
5004 Arguments:
5005
5006 DeviceObject - Pointer to driver object created by system.
5007 Irp - IRP involved.
5008
5009 Return Value:
5010
5011 NTSTATUS
5012
5013 --*/
5014
5015 {
5016 PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName;
5017 WCHAR driveLetterNameBuffer[10];
5018 RTL_QUERY_REGISTRY_TABLE queryTable[2];
5019 PWSTR valueName;
5020 UNICODE_STRING driveLetterName;
5021 NTSTATUS status;
5022 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
5023 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5024 PFUNCTIONAL_DEVICE_EXTENSION p0Extension = commonExtension->PartitionZeroExtension;
5025 ULONG i, diskCount;
5026 PCONFIGURATION_INFORMATION configurationInformation;
5027
5028 PAGED_CODE();
5029
5030 DebugPrint((1, "DISK: IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME to device %#08lx"
5031 " through irp %#08lx\n",
5032 DeviceObject, Irp));
5033
5034 DebugPrint((1, " - DeviceNumber %d, - PartitionNumber %d\n",
5035 p0Extension->DeviceNumber,
5036 commonExtension->PartitionNumber));
5037
5038 if (!TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
5039
5040 status = STATUS_NOT_FOUND;
5041 return status;
5042 }
5043
5044 if (commonExtension->PartitionNumber == 0) {
5045
5046 status = STATUS_NOT_FOUND;
5047 return status;
5048 }
5049
5050 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
5051 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) {
5052
5053 status = STATUS_INVALID_PARAMETER;
5054 return status;
5055 }
5056
5057 valueName = ExAllocatePoolWithTag(PagedPool,
5058 sizeof(WCHAR) * 64,
5059 DISK_TAG_NEC_98);
5060
5061 if (!valueName) {
5062 status = STATUS_INSUFFICIENT_RESOURCES;
5063 return status;
5064 }
5065
5066 //
5067 // Look for a device object name of NT4.
5068 //
5069 swprintf(valueName, L"\\Device\\Harddisk%d\\Partition%d",
5070 p0Extension->DeviceNumber,
5071 commonExtension->PartitionNumber);
5072
5073 driveLetterName.Buffer = driveLetterNameBuffer;
5074 driveLetterName.MaximumLength = 20;
5075 driveLetterName.Length = 0;
5076
5077 RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
5078 queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED |
5079 RTL_QUERY_REGISTRY_DIRECT;
5080 queryTable[0].Name = valueName;
5081 queryTable[0].EntryContext = &driveLetterName;
5082
5083 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
5084 L"\\Registry\\Machine\\System\\DISK",
5085 queryTable, NULL, NULL);
5086
5087 if (!NT_SUCCESS(status)) {
5088
5089 //
5090 // Look for a device object name of NT3.51.
5091 // scsimo.sys on NT3.51 created it as \Device\OpticalDiskX.
5092 // The number X were a serial number from zero on only Removable,
5093 // so we look for it serially without above DeviceNumber and PartitionNumber.
5094 //
5095
5096 configurationInformation = IoGetConfigurationInformation();
5097 diskCount = configurationInformation->DiskCount;
5098
5099 for (i = 0; i < diskCount; i++) {
5100 swprintf(valueName, L"\\Device\\OpticalDisk%d",i);
5101
5102 driveLetterName.Buffer = driveLetterNameBuffer;
5103 driveLetterName.MaximumLength = 20;
5104 driveLetterName.Length = 0;
5105
5106 RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
5107 queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED |
5108 RTL_QUERY_REGISTRY_DIRECT;
5109 queryTable[0].Name = valueName;
5110 queryTable[0].EntryContext = &driveLetterName;
5111
5112 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
5113 L"\\Registry\\Machine\\System\\DISK",
5114 queryTable, NULL, NULL);
5115
5116 if (NT_SUCCESS(status)) {
5117 break;
5118 }
5119 }
5120
5121 if (!NT_SUCCESS(status)) {
5122 ExFreePool(valueName);
5123 return status;
5124 }
5125 }
5126
5127 if (driveLetterName.Length != 4 ||
5128 driveLetterName.Buffer[0] < 'A' ||
5129 driveLetterName.Buffer[0] > 'Z' ||
5130 driveLetterName.Buffer[1] != ':') {
5131
5132 status = STATUS_NOT_FOUND;
5133 ExFreePool(valueName);
5134 return status;
5135 }
5136
5137 suggestedName = Irp->AssociatedIrp.SystemBuffer;
5138 suggestedName->UseOnlyIfThereAreNoOtherLinks = TRUE;
5139 suggestedName->NameLength = 28;
5140
5141 Irp->IoStatus.Information =
5142 FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name) + 28;
5143
5144 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
5145 Irp->IoStatus.Information) {
5146
5147 Irp->IoStatus.Information =
5148 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
5149 status = STATUS_BUFFER_OVERFLOW;
5150 ExFreePool(valueName);
5151 return status;
5152 }
5153
5154 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE,
5155 L"\\Registry\\Machine\\System\\DISK",
5156 valueName);
5157
5158 ExFreePool(valueName);
5159
5160 RtlCopyMemory(suggestedName->Name, L"\\DosDevices\\", 24);
5161 suggestedName->Name[12] = driveLetterName.Buffer[0];
5162 suggestedName->Name[13] = ':';
5163
5164 return status;
5165 }
5166 #endif
5167 #endif
5168
5169 NTSTATUS
5170 NTAPI
5171 DiskIoctlCreateDisk(
5172 IN OUT PDEVICE_OBJECT DeviceObject,
5173 IN OUT PIRP Irp
5174 )
5175
5176 /*++
5177
5178 Routine Description:
5179
5180 Handler for IOCTL_DISK_CREATE_DISK ioctl.
5181
5182 Arguments:
5183
5184 DeviceObject - Device object representing a disk that will be created or
5185 erased.
5186
5187 Irp - The IRP for this request.
5188
5189 Return Values:
5190
5191 NTSTATUS code.
5192
5193 --*/
5194
5195 {
5196 NTSTATUS status;
5197 PCOMMON_DEVICE_EXTENSION commonExtension;
5198 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
5199 PIO_STACK_LOCATION irpStack;
5200 //PDISK_DATA diskData;
5201 PCREATE_DISK createDiskInfo;
5202
5203
5204 PAGED_CODE ();
5205
5206 ASSERT ( DeviceObject != NULL );
5207 ASSERT ( Irp != NULL );
5208
5209 //
5210 // Initialization
5211 //
5212
5213 commonExtension = DeviceObject->DeviceExtension;
5214 fdoExtension = DeviceObject->DeviceExtension;
5215
5216 irpStack = IoGetCurrentIrpStackLocation(Irp);
5217 //diskData = (PDISK_DATA)(commonExtension->DriverData);
5218
5219
5220 ASSERT (commonExtension->IsFdo);
5221
5222 //
5223 // Check the input buffer size.
5224 //
5225
5226 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
5227 sizeof (CREATE_DISK) ) {
5228
5229 return STATUS_INFO_LENGTH_MISMATCH;
5230 }
5231
5232 //
5233 // If we are being asked to create a GPT disk on a system that doesn't
5234 // support GPT, fail.
5235 //
5236
5237 createDiskInfo = (PCREATE_DISK)Irp->AssociatedIrp.SystemBuffer;
5238
5239 if (DiskDisableGpt &&
5240 createDiskInfo->PartitionStyle == PARTITION_STYLE_GPT) {
5241
5242 return STATUS_INVALID_PARAMETER;
5243 }
5244
5245 //
5246 // Call the lower level Io routine to do the dirty work of writing a
5247 // new partition table.
5248 //
5249
5250 DiskAcquirePartitioningLock(fdoExtension);
5251
5252 DiskInvalidatePartitionTable(fdoExtension, TRUE);
5253
5254 status = IoCreateDisk (
5255 commonExtension->PartitionZeroExtension->CommonExtension.DeviceObject,
5256 Irp->AssociatedIrp.SystemBuffer
5257 );
5258 DiskReleasePartitioningLock(fdoExtension);
5259 ClassInvalidateBusRelations(DeviceObject);
5260
5261 Irp->IoStatus.Status = status;
5262
5263 return status;
5264 }
5265
5266 NTSTATUS
5267 NTAPI
5268 DiskIoctlGetDriveLayout(
5269 IN OUT PDEVICE_OBJECT DeviceObject,
5270 IN OUT PIRP Irp
5271 )
5272
5273 /*++
5274
5275 Routine Description:
5276
5277 Handler for IOCTL_DISK_GET_DRIVE_LAYOUT ioctl.
5278
5279 This ioctl has been replace by IOCTL_DISK_GET_DRIVE_LAYOUT_EX.
5280
5281 Arguments:
5282
5283 DeviceObject - Device object representing a disk the layout information
5284 will be obtained for.
5285
5286 Irp - The IRP for this request.
5287
5288
5289 Return Values:
5290
5291 NTSTATUS code.
5292
5293 --*/
5294
5295 {
5296 NTSTATUS status;
5297 ULONG size;
5298 PDRIVE_LAYOUT_INFORMATION partitionList;
5299 PDRIVE_LAYOUT_INFORMATION_EX partitionListEx;
5300 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
5301 //PPHYSICAL_DEVICE_EXTENSION pdoExtension;
5302 PCOMMON_DEVICE_EXTENSION commonExtension;
5303 PIO_STACK_LOCATION irpStack;
5304 PDISK_DATA diskData;
5305 //BOOLEAN invalidateBusRelations;
5306
5307
5308 PAGED_CODE ();
5309
5310 ASSERT ( DeviceObject );
5311 ASSERT ( Irp );
5312
5313 //
5314 // Initialization
5315 //
5316
5317 partitionListEx = NULL;
5318 partitionList = NULL;
5319 fdoExtension = DeviceObject->DeviceExtension;
5320 commonExtension = DeviceObject->DeviceExtension;
5321
5322 irpStack = IoGetCurrentIrpStackLocation(Irp);
5323 diskData = (PDISK_DATA)(commonExtension->DriverData);
5324
5325 //
5326 // Issue a read capacity to update the apparent size of the disk.
5327 //
5328
5329 DiskReadDriveCapacity(fdoExtension->DeviceObject);
5330
5331 DiskAcquirePartitioningLock(fdoExtension);
5332
5333 status = DiskReadPartitionTableEx(fdoExtension, FALSE, &partitionListEx);
5334
5335 if (!NT_SUCCESS(status)) {
5336 DiskReleasePartitioningLock(fdoExtension);
5337 return status;
5338 }
5339
5340 //
5341 // This ioctl is only supported on MBR partitioned disks. Fail the
5342 // call otherwise.
5343 //
5344
5345 if (partitionListEx->PartitionStyle != PARTITION_STYLE_MBR) {
5346 DiskReleasePartitioningLock(fdoExtension);
5347 return STATUS_INVALID_DEVICE_REQUEST;
5348 }
5349
5350
5351 //
5352 // The disk layout has been returned in the partitionListEx
5353 // buffer. Determine its size and, if the data will fit
5354 // into the intermediate buffer, return it.
5355 //
5356
5357 size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]);
5358 size += partitionListEx->PartitionCount * sizeof(PARTITION_INFORMATION);
5359
5360 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
5361 size) {
5362
5363 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
5364 Irp->IoStatus.Information = size;
5365
5366 DiskReleasePartitioningLock(fdoExtension);
5367 return STATUS_BUFFER_TOO_SMALL;
5368 }
5369
5370 //
5371 // Update the partition device objects and set valid partition
5372 // numbers
5373 //
5374
5375 ASSERT(diskData->UpdatePartitionRoutine != NULL);
5376 diskData->UpdatePartitionRoutine(DeviceObject, partitionListEx);
5377
5378 //
5379 // Convert the extended drive layout structure to a regular drive layout
5380 // structure to return. DiskConvertExtendedToLayout() allocates pool
5381 // that we must free.
5382 //
5383
5384 partitionList = DiskConvertExtendedToLayout(partitionListEx);
5385
5386 if (partitionList == NULL) {
5387 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
5388 DiskReleasePartitioningLock (fdoExtension);
5389 return STATUS_INSUFFICIENT_RESOURCES;
5390 }
5391
5392 //
5393 // We're done with the extended partition list now.
5394 //
5395
5396 partitionListEx = NULL;
5397
5398 //
5399 // Copy partition information to system buffer.
5400 //
5401
5402 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
5403 partitionList,
5404 size);
5405
5406 Irp->IoStatus.Information = size;
5407 Irp->IoStatus.Status = status;
5408
5409 //
5410 // Finally, free the buffer allocated by reading the
5411 // partition table.
5412 //
5413
5414 ExFreePool(partitionList);
5415 DiskReleasePartitioningLock(fdoExtension);
5416 ClassInvalidateBusRelations(DeviceObject);
5417
5418 return status;
5419 }
5420
5421 NTSTATUS
5422 NTAPI
5423 DiskIoctlGetDriveLayoutEx(
5424 IN OUT PDEVICE_OBJECT DeviceObject,
5425 IN OUT PIRP Irp
5426 )
5427
5428 /*++
5429
5430 Routine Description:
5431
5432 Handler for IOCTL_DISK_GET_DRIVE_LAYOUT_EX ioctl.
5433
5434 This ioctl replaces IOCTL_DISK_GET_DRIVE_LAYOUT.
5435
5436 Arguments:
5437
5438 DeviceObject - Device object representing a disk the layout information
5439 will be obtained for.
5440
5441 Irp - The IRP for this request.
5442
5443
5444 Return Values:
5445
5446 NTSTATUS code.
5447
5448 --*/
5449
5450 {
5451 NTSTATUS status;
5452 ULONG size;
5453 PDRIVE_LAYOUT_INFORMATION_EX partitionList;
5454 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
5455 //PPHYSICAL_DEVICE_EXTENSION pdoExtension;
5456 PCOMMON_DEVICE_EXTENSION commonExtension;
5457 PIO_STACK_LOCATION irpStack;
5458 PDISK_DATA diskData;
5459 BOOLEAN invalidateBusRelations;
5460
5461
5462 PAGED_CODE ();
5463
5464 ASSERT ( DeviceObject );
5465 ASSERT ( Irp );
5466
5467 //
5468 // Initialization
5469 //
5470
5471 fdoExtension = DeviceObject->DeviceExtension;
5472 //pdoExtension = DeviceObject->DeviceExtension;
5473 commonExtension = DeviceObject->DeviceExtension;
5474
5475 irpStack = IoGetCurrentIrpStackLocation(Irp);
5476 diskData = (PDISK_DATA)(commonExtension->DriverData);
5477
5478 //
5479 // Issue a read capacity to update the apparent size of the disk.
5480 //
5481
5482 DiskReadDriveCapacity(fdoExtension->DeviceObject);
5483
5484 //
5485 // Get the drive layout information.
5486 //
5487
5488 DiskAcquirePartitioningLock (fdoExtension);
5489
5490 status = DiskReadPartitionTableEx (fdoExtension, FALSE, &partitionList);
5491
5492 if ( !NT_SUCCESS (status) ) {
5493 DiskReleasePartitioningLock (fdoExtension);
5494 return status;
5495 }
5496
5497 //
5498 // Update the partition device objects and set valid partition
5499 // numbers.
5500 //
5501
5502 ASSERT(diskData->UpdatePartitionRoutine != NULL);
5503 diskData->UpdatePartitionRoutine(DeviceObject, partitionList);
5504
5505
5506 size = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) +
5507 partitionList->PartitionCount * sizeof (PARTITION_INFORMATION_EX);
5508
5509
5510 //
5511 // If the output buffer is large enough, copy data to the output buffer,
5512 // otherwise, fail.
5513 //
5514
5515 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
5516 size ) {
5517
5518 RtlCopyMemory (Irp->AssociatedIrp.SystemBuffer,
5519 partitionList,
5520 size
5521 );
5522
5523 Irp->IoStatus.Information = size;
5524 Irp->IoStatus.Status = status;
5525 invalidateBusRelations = TRUE;
5526
5527 } else {
5528
5529 Irp->IoStatus.Information = size;
5530 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
5531 status = STATUS_BUFFER_TOO_SMALL;
5532 invalidateBusRelations = FALSE;
5533 }
5534
5535 DiskReleasePartitioningLock(fdoExtension);
5536
5537 if ( invalidateBusRelations ) {
5538 ClassInvalidateBusRelations(DeviceObject);
5539 }
5540
5541 return status;
5542 }
5543
5544 NTSTATUS
5545 NTAPI
5546 DiskIoctlSetDriveLayout(
5547 IN OUT PDEVICE_OBJECT DeviceObject,
5548 IN OUT PIRP Irp
5549 )
5550
5551 /*++
5552
5553 Routine Description:
5554
5555 Handler for IOCTL_DISK_SET_DRIVE_LAYOUT ioctl.
5556
5557 This ioctl has been replaced by IOCTL_DISK_SET_DRIVE_LAYOUT_EX.
5558
5559 Arguments:
5560
5561 DeviceObject - Device object for which partition table should be written.
5562
5563 Irp - IRP involved.
5564
5565 Return Values:
5566
5567 NTSTATUS code.
5568
5569 --*/
5570
5571 {
5572 NTSTATUS status;
5573 PDRIVE_LAYOUT_INFORMATION partitionList;
5574 PDRIVE_LAYOUT_INFORMATION_EX partitionListEx;
5575 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
5576 //PPHYSICAL_DEVICE_EXTENSION pdoExtension;
5577 PCOMMON_DEVICE_EXTENSION commonExtension;
5578 PIO_STACK_LOCATION irpStack;
5579 PDISK_DATA diskData;
5580 //BOOLEAN invalidateBusRelations;
5581 SIZE_T listSize;
5582 SIZE_T inputBufferLength;
5583 SIZE_T outputBufferLength;
5584
5585 PAGED_CODE ();
5586
5587 ASSERT ( DeviceObject );
5588 ASSERT ( Irp );
5589
5590 //
5591 // Initialization
5592 //
5593
5594 partitionListEx = NULL;
5595 partitionList = NULL;
5596 fdoExtension = DeviceObject->DeviceExtension;
5597 //pdoExtension = DeviceObject->DeviceExtension;
5598 commonExtension = DeviceObject->DeviceExtension;
5599
5600 irpStack = IoGetCurrentIrpStackLocation(Irp);
5601 diskData = (PDISK_DATA)(commonExtension->DriverData);
5602 partitionList = Irp->AssociatedIrp.SystemBuffer;
5603
5604 inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
5605 outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
5606
5607 //
5608 // Update the partition table.
5609 //
5610
5611 if (inputBufferLength < sizeof (DRIVE_LAYOUT_INFORMATION)) {
5612
5613 status = STATUS_INFO_LENGTH_MISMATCH;
5614 Irp->IoStatus.Information = sizeof (DRIVE_LAYOUT_INFORMATION);
5615 return status;
5616 }
5617
5618 DiskAcquirePartitioningLock(fdoExtension);
5619
5620 listSize = (partitionList->PartitionCount - 1);
5621 listSize *= sizeof(PARTITION_INFORMATION);
5622 listSize += sizeof(DRIVE_LAYOUT_INFORMATION);
5623
5624 if (inputBufferLength < listSize) {
5625
5626 //
5627 // The remaining size of the input buffer not big enough to
5628 // hold the additional partition entries
5629 //
5630
5631 status = STATUS_INFO_LENGTH_MISMATCH;
5632 Irp->IoStatus.Information = listSize;
5633 DiskReleasePartitioningLock(fdoExtension);
5634 return status;
5635 }
5636
5637 //
5638 // Convert the partition information structure into an extended
5639 // structure.
5640 //
5641
5642 partitionListEx = DiskConvertLayoutToExtended (partitionList);
5643
5644 if ( partitionListEx == NULL ) {
5645
5646 status = STATUS_INSUFFICIENT_RESOURCES;
5647 Irp->IoStatus.Status = status;
5648 DiskReleasePartitioningLock(fdoExtension);
5649 return status;
5650 }
5651
5652 //
5653 // Redo all the partition numbers in the partition information
5654 //
5655
5656 ASSERT(diskData->UpdatePartitionRoutine != NULL);
5657 diskData->UpdatePartitionRoutine(DeviceObject, partitionListEx);
5658
5659 //
5660 // Write changes to disk.
5661 //
5662
5663 status = DiskWritePartitionTableEx(fdoExtension, partitionListEx);
5664
5665 //
5666 // Update IRP with bytes returned. Make sure we don't claim to be
5667 // returning more bytes than the caller is expecting to get back.
5668 //
5669
5670 if (NT_SUCCESS (status)) {
5671 if (outputBufferLength < listSize) {
5672 Irp->IoStatus.Information = outputBufferLength;
5673 } else {
5674 ULONG i;
5675
5676 Irp->IoStatus.Information = listSize;
5677
5678 //
5679 // Also update the partition numbers.
5680 //
5681
5682 for (i = 0; i < partitionList->PartitionCount; i++) {
5683
5684 PPARTITION_INFORMATION partition;
5685 PPARTITION_INFORMATION_EX partitionEx;
5686
5687 partition = &partitionList->PartitionEntry[i];
5688 partitionEx = &partitionListEx->PartitionEntry[i];
5689 partition->PartitionNumber = partitionEx->PartitionNumber;
5690
5691 }
5692 }
5693 }
5694
5695 ExFreePool (partitionListEx);
5696 DiskReleasePartitioningLock(fdoExtension);
5697 ClassInvalidateBusRelations(DeviceObject);
5698
5699 Irp->IoStatus.Status = status;
5700 return status;
5701 }
5702
5703 NTSTATUS
5704 NTAPI
5705 DiskIoctlSetDriveLayoutEx(
5706 IN OUT PDEVICE_OBJECT DeviceObject,
5707 IN OUT PIRP Irp
5708 )
5709
5710 /*++
5711
5712 Routine Description:
5713
5714 Handler for IOCTL_DISK_SET_DRIVE_LAYOUT_EX ioctl.
5715
5716 This ioctl replaces IOCTL_DISK_SET_DRIVE_LAYOUT.
5717
5718 Arguments:
5719
5720 DeviceObject - Device object for which partition table should be written.
5721
5722 Irp - IRP involved.
5723
5724 Return Values:
5725
5726 NTSTATUS code.
5727
5728 --*/
5729
5730 {
5731
5732 NTSTATUS status;
5733 PDRIVE_LAYOUT_INFORMATION_EX partitionListEx;
5734 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
5735 PCOMMON_DEVICE_EXTENSION commonExtension;
5736
5737 PIO_STACK_LOCATION irpStack;
5738 PDISK_DATA diskData;
5739 //BOOLEAN invalidateBusRelations;
5740 SIZE_T listSize;
5741 SIZE_T inputBufferLength;
5742 SIZE_T outputBufferLength;
5743
5744 PAGED_CODE ();
5745
5746 ASSERT ( DeviceObject );
5747 ASSERT ( Irp );
5748
5749 //
5750 // Initialization
5751 //
5752
5753 partitionListEx = NULL;
5754 fdoExtension = DeviceObject->DeviceExtension;
5755 commonExtension = DeviceObject->DeviceExtension;
5756
5757 irpStack = IoGetCurrentIrpStackLocation(Irp);
5758 diskData = (PDISK_DATA)(commonExtension->DriverData);
5759 partitionListEx = Irp->AssociatedIrp.SystemBuffer;
5760
5761 inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
5762 outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
5763
5764 //
5765 // Update the partition table.
5766 //
5767
5768 if (inputBufferLength <
5769 FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry)) {
5770 status = STATUS_INFO_LENGTH_MISMATCH;
5771 Irp->IoStatus.Information =
5772 FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry);
5773 return status;
5774 }
5775
5776 DiskAcquirePartitioningLock(fdoExtension);
5777
5778 listSize = partitionListEx->PartitionCount;
5779 listSize *= sizeof(PARTITION_INFORMATION_EX);
5780 listSize += FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry);
5781
5782 if (inputBufferLength < listSize) {
5783
5784 //
5785 // The remaining size of the input buffer not big enough to
5786 // hold the additional partition entries
5787 //
5788
5789 status = STATUS_INFO_LENGTH_MISMATCH;
5790 Irp->IoStatus.Information = listSize;
5791 DiskReleasePartitioningLock(fdoExtension);
5792 return status;
5793 }
5794
5795
5796 //
5797 // If the partition count is zero, this is a request to clear
5798 // the partition table.
5799 //
5800
5801 if (partitionListEx->PartitionCount == 0) {
5802
5803 CREATE_DISK CreateDiskInfo;
5804
5805 RtlZeroMemory (&CreateDiskInfo, sizeof (CreateDiskInfo));
5806 CreateDiskInfo.PartitionStyle = diskData->PartitionStyle;
5807 if (diskData->PartitionStyle == PARTITION_STYLE_MBR) {
5808 CreateDiskInfo.Mbr.Signature = partitionListEx->Mbr.Signature;
5809 } else {
5810 ASSERT (diskData->PartitionStyle == PARTITION_STYLE_GPT);
5811 CreateDiskInfo.Gpt.DiskId = partitionListEx->Gpt.DiskId;
5812 //
5813 // NB: Setting MaxPartitionCount to zero will
5814 // force the GPT partition table writing code
5815 // to use the default minimum for this value.
5816 //
5817 CreateDiskInfo.Gpt.MaxPartitionCount = 0;
5818 }
5819 DiskInvalidatePartitionTable(fdoExtension, TRUE);
5820
5821
5822 status = IoCreateDisk(DeviceObject, &CreateDiskInfo);
5823
5824 } else {
5825
5826 //
5827 // Redo all the partition numbers in the partition information
5828 //
5829
5830 ASSERT(diskData->UpdatePartitionRoutine != NULL);
5831 diskData->UpdatePartitionRoutine(DeviceObject, partitionListEx);
5832
5833 //
5834 // Write changes to disk.
5835 //
5836
5837 status = DiskWritePartitionTableEx(fdoExtension, partitionListEx);
5838 }
5839
5840 //
5841 // Update IRP with bytes returned. Make sure we don't claim to be
5842 // returning more bytes than the caller is expecting to get back.
5843 //
5844
5845 if (NT_SUCCESS(status)) {
5846 if (outputBufferLength < listSize) {
5847 Irp->IoStatus.Information = outputBufferLength;
5848 } else {
5849 Irp->IoStatus.Information = listSize;
5850 }
5851 }
5852
5853 DiskReleasePartitioningLock(fdoExtension);
5854 ClassInvalidateBusRelations(DeviceObject);
5855
5856 Irp->IoStatus.Status = status;
5857 return status;
5858 }
5859
5860 NTSTATUS
5861 NTAPI
5862 DiskIoctlGetPartitionInfo(
5863 IN OUT PDEVICE_OBJECT DeviceObject,
5864 IN OUT PIRP Irp
5865 )
5866
5867 /*++
5868
5869 Routine Description:
5870
5871 Handle the IOCTL_DISK_GET_PARTITION_INFO ioctl. Return the information
5872 about the partition specified by the device object. Note that no
5873 information is ever returned about the size or partition type of the
5874 physical disk, as this doesn't make any sense.
5875
5876 This ioctl has been replaced by IOCTL_DISK_GET_PARTITION_INFO_EX.
5877
5878 Arguments:
5879
5880 DeviceObject -
5881
5882 Irp -
5883
5884 Return Values:
5885
5886 NTSTATUS code.
5887
5888 --*/
5889
5890 {
5891 NTSTATUS status;
5892 PIO_STACK_LOCATION irpStack;
5893 PDISK_DATA diskData;
5894 PPARTITION_INFORMATION partitionInfo;
5895 PFUNCTIONAL_DEVICE_EXTENSION p0Extension;
5896 PCOMMON_DEVICE_EXTENSION commonExtension;
5897 PDISK_DATA partitionZeroData;
5898 NTSTATUS oldReadyStatus;
5899
5900
5901 PAGED_CODE ();
5902
5903 ASSERT ( DeviceObject );
5904 ASSERT ( Irp );
5905
5906
5907 //
5908 // Initialization
5909 //
5910
5911 commonExtension = DeviceObject->DeviceExtension;
5912 irpStack = IoGetCurrentIrpStackLocation(Irp);
5913 diskData = (PDISK_DATA)(commonExtension->DriverData);
5914 p0Extension = commonExtension->PartitionZeroExtension;
5915 partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData);
5916
5917
5918 //
5919 // Check that the buffer is large enough.
5920 //
5921
5922 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
5923 sizeof(PARTITION_INFORMATION)) {
5924
5925 status = STATUS_BUFFER_TOO_SMALL;
5926 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
5927 return status;
5928 }
5929
5930 //
5931 // Update the geometry in case it has changed
5932 //
5933
5934 status = DiskReadDriveCapacity(p0Extension->DeviceObject);
5935
5936 //
5937 // Note whether the drive is ready. If the status has changed then
5938 // notify pnp.
5939 //
5940
5941 oldReadyStatus = InterlockedExchange(
5942 &(partitionZeroData->ReadyStatus),
5943 status);
5944
5945 if(partitionZeroData->ReadyStatus != oldReadyStatus) {
5946 IoInvalidateDeviceRelations(p0Extension->LowerPdo,
5947 BusRelations);
5948 }
5949
5950 if(!NT_SUCCESS(status)) {
5951 return status;
5952 }
5953
5954
5955 //
5956 // Partition zero, the partition representing the entire disk, is
5957 // special cased. The logic below allows for sending this ioctl to
5958 // a GPT disk only for partition zero. This allows us to obtain
5959 // the size of a GPT disk using Win2k compatible IOCTLs.
5960 //
5961
5962 if (commonExtension->PartitionNumber == 0) {
5963
5964 partitionInfo = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
5965
5966 partitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
5967 partitionInfo->StartingOffset = commonExtension->StartingOffset;
5968 partitionInfo->PartitionLength = commonExtension->PartitionLength;
5969 partitionInfo->HiddenSectors = 0;
5970 partitionInfo->PartitionNumber = commonExtension->PartitionNumber;
5971 partitionInfo->BootIndicator = FALSE;
5972 partitionInfo->RewritePartition = FALSE;
5973 partitionInfo->RecognizedPartition = FALSE;
5974
5975 } else {
5976
5977 //
5978 // We do not support this IOCTL on an EFI partitioned disk
5979 // for any partition other than partition zero.
5980 //
5981
5982 if (diskData->PartitionStyle != PARTITION_STYLE_MBR) {
5983 status = STATUS_INVALID_DEVICE_REQUEST;
5984 Irp->IoStatus.Status = status;
5985 return status;
5986 }
5987
5988 DiskEnumerateDevice(p0Extension->DeviceObject);
5989 DiskAcquirePartitioningLock(p0Extension);
5990
5991
5992 partitionInfo = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
5993
5994 partitionInfo->PartitionType = diskData->Mbr.PartitionType;
5995 partitionInfo->StartingOffset = commonExtension->StartingOffset;
5996 partitionInfo->PartitionLength = commonExtension->PartitionLength;
5997 partitionInfo->HiddenSectors = diskData->Mbr.HiddenSectors;
5998 partitionInfo->PartitionNumber = commonExtension->PartitionNumber;
5999 partitionInfo->BootIndicator = diskData->Mbr.BootIndicator;
6000 partitionInfo->RewritePartition = FALSE;
6001 partitionInfo->RecognizedPartition =
6002 IsRecognizedPartition(diskData->Mbr.PartitionType);
6003
6004 DiskReleasePartitioningLock(p0Extension);
6005 }
6006
6007 status = STATUS_SUCCESS;
6008 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
6009
6010 return status;
6011 }
6012
6013 NTSTATUS
6014 NTAPI
6015 DiskIoctlGetPartitionInfoEx(
6016 IN OUT PDEVICE_OBJECT DeviceObject,
6017 IN OUT PIRP Irp
6018 )
6019 {
6020 NTSTATUS status;
6021 PIO_STACK_LOCATION irpStack;
6022 PDISK_DATA diskData;
6023 PPARTITION_INFORMATION_EX partitionInfo;
6024 PFUNCTIONAL_DEVICE_EXTENSION p0Extension;
6025 PCOMMON_DEVICE_EXTENSION commonExtension;
6026 PDISK_DATA partitionZeroData;
6027 NTSTATUS oldReadyStatus;
6028
6029
6030 PAGED_CODE ();
6031
6032 ASSERT ( DeviceObject );
6033 ASSERT ( Irp );
6034
6035
6036 //
6037 // Initialization
6038 //
6039
6040 commonExtension = DeviceObject->DeviceExtension;
6041 irpStack = IoGetCurrentIrpStackLocation(Irp);
6042 diskData = (PDISK_DATA)(commonExtension->DriverData);
6043 p0Extension = commonExtension->PartitionZeroExtension;
6044 partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData);
6045
6046
6047 //
6048 // Check that the buffer is large enough.
6049 //
6050
6051 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
6052 sizeof(PARTITION_INFORMATION_EX)) {
6053
6054 status = STATUS_BUFFER_TOO_SMALL;
6055 Irp->IoStatus.Status = status;
6056 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
6057 return status;
6058 }
6059
6060 //
6061 // Update the geometry in case it has changed
6062 //
6063
6064 status = DiskReadDriveCapacity(p0Extension->DeviceObject);
6065
6066 //
6067 // Note whether the drive is ready. If the status has changed then
6068 // notify pnp.
6069 //
6070
6071 oldReadyStatus = InterlockedExchange(
6072 &(partitionZeroData->ReadyStatus),
6073 status);
6074
6075 if(partitionZeroData->ReadyStatus != oldReadyStatus) {
6076 IoInvalidateDeviceRelations(p0Extension->LowerPdo,
6077 BusRelations);
6078 }
6079
6080 if(!NT_SUCCESS(status)) {
6081 return status;
6082 }
6083
6084 //
6085 // If this is something other than partition 0 then do a
6086 // re-enumeration to make sure we've got up-to-date information.
6087 //
6088
6089 if(commonExtension->PartitionNumber != 0) {
6090 DiskEnumerateDevice(p0Extension->DeviceObject);
6091 DiskAcquirePartitioningLock(p0Extension);
6092 }
6093
6094 partitionInfo = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer;
6095
6096 partitionInfo->StartingOffset = commonExtension->StartingOffset;
6097 partitionInfo->PartitionLength = commonExtension->PartitionLength;
6098 partitionInfo->RewritePartition = FALSE;
6099 partitionInfo->PartitionNumber = commonExtension->PartitionNumber;
6100 partitionInfo->PartitionStyle = diskData->PartitionStyle;
6101
6102 if ( diskData->PartitionStyle == PARTITION_STYLE_MBR ) {
6103
6104 partitionInfo->Mbr.PartitionType = diskData->Mbr.PartitionType;
6105 partitionInfo->Mbr.HiddenSectors = diskData->Mbr.HiddenSectors;
6106 partitionInfo->Mbr.BootIndicator = diskData->Mbr.BootIndicator;
6107 partitionInfo->Mbr.RecognizedPartition =
6108 IsRecognizedPartition(diskData->Mbr.PartitionType);
6109
6110 } else {
6111
6112 //
6113 // ISSUE - 2000/02/09 - math: Review for Partition0.
6114 // Is this correct for Partition0?
6115 //
6116
6117 partitionInfo->Gpt.PartitionType = diskData->Efi.PartitionType;
6118 partitionInfo->Gpt.PartitionId = diskData->Efi.PartitionId;
6119 partitionInfo->Gpt.Attributes = diskData->Efi.Attributes;
6120 RtlCopyMemory (
6121 partitionInfo->Gpt.Name,
6122 diskData->Efi.PartitionName,
6123 sizeof (partitionInfo->Gpt.Name)
6124 );
6125 }
6126
6127 status = STATUS_SUCCESS;
6128 Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
6129
6130 if(commonExtension->PartitionNumber != 0) {
6131 DiskReleasePartitioningLock(p0Extension);
6132 }
6133
6134 return status;
6135 }
6136
6137 NTSTATUS
6138 NTAPI
6139 DiskIoctlGetLengthInfo(
6140 IN OUT PDEVICE_OBJECT DeviceObject,
6141 IN OUT PIRP Irp
6142 )
6143 {
6144 NTSTATUS status;
6145 PIO_STACK_LOCATION irpStack;
6146 //PDISK_DATA diskData;
6147 PGET_LENGTH_INFORMATION lengthInfo;
6148 PFUNCTIONAL_DEVICE_EXTENSION p0Extension;
6149 PCOMMON_DEVICE_EXTENSION commonExtension;
6150 PDISK_DATA partitionZeroData;
6151 NTSTATUS oldReadyStatus;
6152
6153
6154 PAGED_CODE ();
6155
6156 ASSERT ( DeviceObject );
6157 ASSERT ( Irp );
6158
6159
6160 //
6161 // Initialization
6162 //
6163
6164 commonExtension = DeviceObject->DeviceExtension;
6165 irpStack = IoGetCurrentIrpStackLocation(Irp);
6166 //diskData = (PDISK_DATA)(commonExtension->DriverData);
6167 p0Extension = commonExtension->PartitionZeroExtension;
6168 partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData);
6169
6170
6171 //
6172 // Check that the buffer is large enough.
6173 //
6174
6175 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
6176 sizeof(GET_LENGTH_INFORMATION)) {
6177
6178 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
6179 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
6180 return STATUS_BUFFER_TOO_SMALL;
6181 }
6182
6183 //
6184 // Update the geometry in case it has changed
6185 //
6186
6187 status = DiskReadDriveCapacity(p0Extension->DeviceObject);
6188
6189 //
6190 // Note whether the drive is ready. If the status has changed then
6191 // notify pnp.
6192 //
6193
6194 oldReadyStatus = InterlockedExchange(
6195 &(partitionZeroData->ReadyStatus),
6196 status);
6197
6198 if(partitionZeroData->ReadyStatus != oldReadyStatus) {
6199 IoInvalidateDeviceRelations(p0Extension->LowerPdo,
6200 BusRelations);
6201 }
6202
6203 if(!NT_SUCCESS(status)) {
6204 return status;
6205 }
6206
6207 //
6208 // If this is something other than partition 0 then do a
6209 // re-enumeration to make sure we've got up-to-date information.
6210 //
6211
6212 if(commonExtension->PartitionNumber != 0) {
6213 DiskEnumerateDevice(p0Extension->DeviceObject);
6214 DiskAcquirePartitioningLock(p0Extension);
6215 }
6216
6217 lengthInfo = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
6218
6219 lengthInfo->Length = commonExtension->PartitionLength;
6220
6221 status = STATUS_SUCCESS;
6222 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
6223
6224 if(commonExtension->PartitionNumber != 0) {
6225 DiskReleasePartitioningLock(p0Extension);
6226 }
6227
6228 return status;
6229 }
6230
6231 NTSTATUS
6232 NTAPI
6233 DiskIoctlSetPartitionInfo(
6234 IN OUT PDEVICE_OBJECT DeviceObject,
6235 IN OUT PIRP Irp
6236 )
6237 {
6238 NTSTATUS status;
6239 PSET_PARTITION_INFORMATION inputBuffer;
6240 PDISK_DATA diskData;
6241 PIO_STACK_LOCATION irpStack;
6242 PCOMMON_DEVICE_EXTENSION commonExtension;
6243
6244
6245 PAGED_CODE ();
6246
6247 ASSERT ( DeviceObject != NULL );
6248 ASSERT ( Irp != NULL );
6249
6250
6251 //
6252 // Initialization
6253 //
6254
6255 commonExtension = DeviceObject->DeviceExtension;
6256 irpStack = IoGetCurrentIrpStackLocation(Irp);
6257 diskData = (PDISK_DATA)(commonExtension->DriverData);
6258 inputBuffer = (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
6259
6260 if(commonExtension->IsFdo) {
6261
6262 return STATUS_UNSUCCESSFUL;
6263 }
6264
6265
6266 if (diskData->PartitionStyle != PARTITION_STYLE_MBR) {
6267 return STATUS_INVALID_DEVICE_REQUEST;
6268 }
6269
6270 //
6271 // Validate buffer length
6272 //
6273
6274 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
6275 sizeof(SET_PARTITION_INFORMATION)) {
6276
6277 return STATUS_INFO_LENGTH_MISMATCH;
6278 }
6279
6280 DiskAcquirePartitioningLock(commonExtension->PartitionZeroExtension);
6281
6282 //
6283 // The HAL routines IoGet- and IoSetPartitionInformation were
6284 // developed before support of dynamic partitioning and therefore
6285 // don't distinguish between partition ordinal (that is the order
6286 // of a partition on a disk) and the partition number. (The
6287 // partition number is assigned to a partition to identify it to
6288 // the system.) Use partition ordinals for these legacy calls.
6289 //
6290
6291 status = DiskSetPartitionInformation(
6292 commonExtension->PartitionZeroExtension,
6293 commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector,
6294 diskData->PartitionOrdinal,
6295 inputBuffer->PartitionType);
6296
6297 if(NT_SUCCESS(status)) {
6298
6299 diskData->Mbr.PartitionType = inputBuffer->PartitionType;
6300 }
6301
6302 DiskReleasePartitioningLock(commonExtension->PartitionZeroExtension);
6303
6304 return status;
6305 }
6306
6307 NTSTATUS
6308 NTAPI
6309 DiskIoctlSetPartitionInfoEx(
6310 IN OUT PDEVICE_OBJECT DeviceObject,
6311 IN OUT PIRP Irp
6312 )
6313 {
6314 NTSTATUS status;
6315 PSET_PARTITION_INFORMATION_EX inputBuffer;
6316 PDISK_DATA diskData;
6317 PIO_STACK_LOCATION irpStack;
6318 PCOMMON_DEVICE_EXTENSION commonExtension;
6319
6320
6321 PAGED_CODE ();
6322
6323 ASSERT ( DeviceObject != NULL );
6324 ASSERT ( Irp != NULL );
6325
6326
6327 //
6328 // Initialization
6329 //
6330
6331 commonExtension = DeviceObject->DeviceExtension;
6332 irpStack = IoGetCurrentIrpStackLocation(Irp);
6333 diskData = (PDISK_DATA)(commonExtension->DriverData);
6334 inputBuffer = (PSET_PARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
6335
6336 if(commonExtension->IsFdo) {
6337
6338 return STATUS_UNSUCCESSFUL;
6339 }
6340
6341 //
6342 // Validate buffer length
6343 //
6344
6345 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
6346 sizeof(SET_PARTITION_INFORMATION_EX)) {
6347
6348 return STATUS_INFO_LENGTH_MISMATCH;
6349 }
6350
6351 DiskAcquirePartitioningLock(commonExtension->PartitionZeroExtension);
6352
6353 //
6354 // The HAL routines IoGet- and IoSetPartitionInformation were
6355 // developed before support of dynamic partitioning and therefore
6356 // don't distinguish between partition ordinal (that is the order
6357 // of a partition on a disk) and the partition number. (The
6358 // partition number is assigned to a partition to identify it to
6359 // the system.) Use partition ordinals for these legacy calls.
6360 //
6361
6362 status = DiskSetPartitionInformationEx(
6363 commonExtension->PartitionZeroExtension,
6364 diskData->PartitionOrdinal,
6365 inputBuffer
6366 );
6367
6368 if(NT_SUCCESS(status)) {
6369
6370 if (diskData->PartitionStyle == PARTITION_STYLE_MBR) {
6371
6372 diskData->Mbr.PartitionType = inputBuffer->Mbr.PartitionType;
6373
6374 } else {
6375
6376 ASSERT ( diskData->PartitionStyle == PARTITION_STYLE_MBR );
6377
6378 diskData->Efi.PartitionType = inputBuffer->Gpt.PartitionType;
6379 diskData->Efi.PartitionId = inputBuffer->Gpt.PartitionId;
6380 diskData->Efi.Attributes = inputBuffer->Gpt.Attributes;
6381
6382 RtlCopyMemory (
6383 diskData->Efi.PartitionName,
6384 inputBuffer->Gpt.Name,
6385 sizeof (diskData->Efi.PartitionName)
6386 );
6387 }
6388 }
6389
6390 DiskReleasePartitioningLock(commonExtension->PartitionZeroExtension);
6391
6392 return status;
6393 }
6394
6395 typedef struct _DISK_GEOMETRY_EX_INTERNAL {
6396 DISK_GEOMETRY Geometry;
6397 LARGE_INTEGER DiskSize;
6398 DISK_PARTITION_INFO Partition;
6399 DISK_DETECTION_INFO Detection;
6400 } DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL;
6401
6402
6403 NTSTATUS
6404 NTAPI
6405 DiskIoctlGetDriveGeometryEx(
6406 IN PDEVICE_OBJECT DeviceObject,
6407 IN OUT PIRP Irp
6408 )
6409
6410 /*++
6411
6412 Routine Description:
6413
6414 Obtain the extended geometry information for the drive.
6415
6416 Arguments:
6417
6418 DeviceObject - The device object to obtain the geometry for.
6419
6420 Irp - IRP with a return buffer large enough to receive the
6421 extended geometry information.
6422
6423 Return Value:
6424
6425 NTSTATUS code
6426
6427 --*/
6428
6429 {
6430 NTSTATUS status;
6431 PIO_STACK_LOCATION irpStack;
6432 PCOMMON_DEVICE_EXTENSION commonExtension;
6433 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
6434 PDISK_DATA diskData;
6435 PDISK_GEOMETRY_EX_INTERNAL geometryEx;
6436 ULONG OutputBufferLength;
6437
6438 //
6439 // Verification
6440 //
6441
6442 PAGED_CODE ();
6443
6444 ASSERT ( DeviceObject != NULL );
6445 ASSERT ( Irp != NULL );
6446
6447 //
6448 // Setup parameters
6449 //
6450
6451 commonExtension = DeviceObject->DeviceExtension;
6452 fdoExtension = DeviceObject->DeviceExtension;
6453 diskData = (PDISK_DATA)(commonExtension->DriverData);
6454 irpStack = IoGetCurrentIrpStackLocation ( Irp );
6455 geometryEx = NULL;
6456 OutputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
6457
6458 //
6459 // This is only valid for the FDO.
6460 //
6461
6462 ASSERT ( commonExtension->IsFdo );
6463
6464 //
6465 // Check that the buffer is large enough. It must be large enough
6466 // to hold at lest the Geometry and DiskSize fields of of the
6467 // DISK_GEOMETRY_EX structure.
6468 //
6469
6470 if ( OutputBufferLength < FIELD_OFFSET (DISK_GEOMETRY_EX, Data) ) {
6471
6472 //
6473 // Buffer too small. Bail out, telling the caller the required
6474 // size.
6475 //
6476
6477 status = STATUS_BUFFER_TOO_SMALL;
6478 Irp->IoStatus.Status = FIELD_OFFSET (DISK_GEOMETRY_EX, Data);
6479 return status;
6480 }
6481
6482 if (TEST_FLAG (DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
6483
6484 //
6485 // Issue a ReadCapacity to update device extension
6486 // with information for the current media.
6487 //
6488
6489 status = DiskReadDriveCapacity (
6490 commonExtension->PartitionZeroExtension->DeviceObject);
6491
6492 diskData->ReadyStatus = status;
6493
6494 if (!NT_SUCCESS (status)) {
6495 return status;
6496 }
6497 }
6498
6499 //
6500 // Copy drive geometry.
6501 //
6502
6503 geometryEx = (PDISK_GEOMETRY_EX_INTERNAL)Irp->AssociatedIrp.SystemBuffer;
6504 geometryEx->Geometry = fdoExtension->DiskGeometry;
6505 geometryEx->DiskSize = commonExtension->PartitionZeroExtension->CommonExtension.PartitionLength;
6506
6507 //
6508 // If the user buffer is large enough to hold the partition information
6509 // then add that as well.
6510 //
6511
6512 if (OutputBufferLength >= FIELD_OFFSET (DISK_GEOMETRY_EX_INTERNAL, Detection)) {
6513
6514 geometryEx->Partition.SizeOfPartitionInfo = sizeof (geometryEx->Partition);
6515 geometryEx->Partition.PartitionStyle = diskData->PartitionStyle;
6516
6517 switch ( diskData->PartitionStyle ) {
6518
6519 case PARTITION_STYLE_GPT:
6520
6521 //
6522 // Copy GPT signature.
6523 //
6524
6525 geometryEx->Partition.Gpt.DiskId = diskData->Efi.DiskId;
6526 break;
6527
6528 case PARTITION_STYLE_MBR:
6529
6530 //
6531 // Copy MBR signature and checksum.
6532 //
6533
6534 geometryEx->Partition.Mbr.Signature = diskData->Mbr.Signature;
6535 geometryEx->Partition.Mbr.CheckSum = diskData->Mbr.MbrCheckSum;
6536 break;
6537
6538 default:
6539
6540 //
6541 // This is a raw disk. Zero out the signature area so
6542 // nobody gets confused.
6543 //
6544
6545 RtlZeroMemory (
6546 &geometryEx->Partition,
6547 sizeof (geometryEx->Partition));
6548 }
6549 }
6550
6551 //
6552 // If the buffer is large enough to hold the detection information,
6553 // then also add that.
6554 //
6555
6556 if (OutputBufferLength >= sizeof (DISK_GEOMETRY_EX_INTERNAL)) {
6557
6558 geometryEx->Detection.SizeOfDetectInfo =
6559 sizeof (geometryEx->Detection);
6560
6561 status = DiskGetDetectInfo (
6562 fdoExtension,
6563 &geometryEx->Detection);
6564
6565 //
6566 // Failed to obtain detection information, set to none.
6567 //
6568
6569 if (!NT_SUCCESS (status)) {
6570 geometryEx->Detection.DetectionType = DetectNone;
6571 }
6572 }
6573
6574
6575 status = STATUS_SUCCESS;
6576 Irp->IoStatus.Information = min (OutputBufferLength,
6577 sizeof (DISK_GEOMETRY_EX_INTERNAL));
6578
6579 return status;
6580 }