[USB]
[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 "ntddstor.h"
31 #include "ioevent.h"
32
33 NTSTATUS
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 DiskPdoFindPartitionEntry(
45 IN PPHYSICAL_DEVICE_EXTENSION Pdo,
46 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo
47 );
48
49 PPARTITION_INFORMATION_EX
50 DiskFindAdjacentPartition(
51 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
52 IN PPARTITION_INFORMATION_EX BasePartition
53 );
54
55 PPARTITION_INFORMATION_EX
56 DiskFindContainingPartition(
57 IN PDRIVE_LAYOUT_INFORMATION_EX LayoutInfo,
58 IN PPARTITION_INFORMATION_EX BasePartition,
59 IN BOOLEAN SearchTopToBottom
60 );
61
62 NTSTATUS
63 DiskIoctlCreateDisk(
64 IN PDEVICE_OBJECT DeviceObject,
65 IN PIRP Irp
66 );
67
68 NTSTATUS
69 DiskIoctlGetDriveLayout(
70 IN PDEVICE_OBJECT DeviceObject,
71 IN PIRP Irp
72 );
73
74 NTSTATUS
75 DiskIoctlGetDriveLayoutEx(
76 IN PDEVICE_OBJECT DeviceObject,
77 IN PIRP Irp
78 );
79
80 NTSTATUS
81 DiskIoctlSetDriveLayout(
82 IN PDEVICE_OBJECT DeviceObject,
83 IN PIRP Irp
84 );
85
86 NTSTATUS
87 DiskIoctlSetDriveLayoutEx(
88 IN PDEVICE_OBJECT DeviceObject,
89 IN PIRP Irp
90 );
91
92 NTSTATUS
93 DiskIoctlGetPartitionInfo(
94 IN PDEVICE_OBJECT DeviceObject,
95 IN PIRP Irp
96 );
97
98 NTSTATUS
99 DiskIoctlGetPartitionInfoEx(
100 IN PDEVICE_OBJECT DeviceObject,
101 IN PIRP Irp
102 );
103
104 NTSTATUS
105 DiskIoctlGetLengthInfo(
106 IN PDEVICE_OBJECT DeviceObject,
107 IN PIRP Irp
108 );
109
110 NTSTATUS
111 DiskIoctlSetPartitionInfo(
112 IN PDEVICE_OBJECT DeviceObject,
113 IN PIRP Irp
114 );
115
116 NTSTATUS
117 DiskIoctlSetPartitionInfoEx(
118 IN PDEVICE_OBJECT DeviceObject,
119 IN PIRP Irp
120 );
121
122 NTSTATUS
123 DiskIoctlSetPartitionInfoEx(
124 IN PDEVICE_OBJECT DeviceObject,
125 IN PIRP Irp
126 );
127
128 NTSTATUS
129 DiskIoctlGetDriveGeometryEx(
130 IN PDEVICE_OBJECT DeviceObject,
131 IN PIRP Irp
132 );
133
134 #ifdef ALLOC_PRAGMA
135
136 #pragma alloc_text(INIT, DriverEntry)
137 #pragma alloc_text(PAGE, DiskUnload)
138 #pragma alloc_text(PAGE, DiskCreateFdo)
139 #pragma alloc_text(PAGE, DiskDetermineMediaTypes)
140 #pragma alloc_text(PAGE, DiskModeSelect)
141 #pragma alloc_text(PAGE, DisableWriteCache)
142 #pragma alloc_text(PAGE, DiskIoctlVerify)
143 #pragma alloc_text(PAGE, DiskSetSpecialHacks)
144 #pragma alloc_text(PAGE, DiskScanRegistryForSpecial)
145 #pragma alloc_text(PAGE, DiskQueryPnpCapabilities)
146 #pragma alloc_text(PAGE, DiskGetCacheInformation)
147 #pragma alloc_text(PAGE, DiskSetCacheInformation)
148 #pragma alloc_text(PAGE, DiskSetInfoExceptionInformation)
149 #pragma alloc_text(PAGE, DiskGetInfoExceptionInformation)
150
151 #pragma alloc_text(PAGE, DiskPdoFindPartitionEntry)
152 #pragma alloc_text(PAGE, DiskFindAdjacentPartition)
153 #pragma alloc_text(PAGE, DiskFindContainingPartition)
154
155 #pragma alloc_text(PAGE, DiskIoctlCreateDisk)
156 #pragma alloc_text(PAGE, DiskIoctlGetDriveLayout)
157 #pragma alloc_text(PAGE, DiskIoctlGetDriveLayoutEx)
158 #pragma alloc_text(PAGE, DiskIoctlSetDriveLayout)
159 #pragma alloc_text(PAGE, DiskIoctlSetDriveLayoutEx)
160 #pragma alloc_text(PAGE, DiskIoctlGetPartitionInfo)
161 #pragma alloc_text(PAGE, DiskIoctlGetPartitionInfoEx)
162 #pragma alloc_text(PAGE, DiskIoctlGetLengthInfo)
163 #pragma alloc_text(PAGE, DiskIoctlSetPartitionInfo)
164 #pragma alloc_text(PAGE, DiskIoctlSetPartitionInfoEx)
165 #pragma alloc_text(PAGE, DiskIoctlGetDriveGeometryEx)
166 #endif
167
168 extern ULONG DiskDisableGpt;
169
170 const GUID GUID_NULL = { 0 };
171 #define DiskCompareGuid(_First,_Second) \
172 (memcmp ((_First),(_Second), sizeof (GUID)))
173
174 \f
175 NTSTATUS
176 NTAPI
177 DriverEntry(
178 IN PDRIVER_OBJECT DriverObject,
179 IN PUNICODE_STRING RegistryPath
180 )
181
182 /*++
183
184 Routine Description:
185
186 This routine initializes the SCSI hard disk class driver.
187
188 Arguments:
189
190 DriverObject - Pointer to driver object created by system.
191
192 RegistryPath - Pointer to the name of the services node for this driver.
193
194 Return Value:
195
196 The function value is the final status from the initialization operation.
197
198 --*/
199
200 {
201 CLASS_INIT_DATA InitializationData;
202 CLASS_QUERY_WMI_REGINFO_EX_LIST classQueryWmiRegInfoExList;
203 GUID guidQueryRegInfoEx = GUID_CLASSPNP_QUERY_REGINFOEX;
204
205 NTSTATUS status;
206
207 #if defined(_X86_)
208 //
209 // Read the information NtDetect squirreled away about the disks in this
210 // system.
211 //
212
213 status = DiskSaveDetectInfo(DriverObject);
214
215 if(!NT_SUCCESS(status)) {
216 DebugPrint((1, "Disk: couldn't save NtDetect information (%#08lx)\n",
217 status));
218 }
219 #endif
220
221 //
222 // Zero InitData
223 //
224
225 RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
226
227 InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
228
229 //
230 // Setup sizes and entry points for functional device objects
231 //
232
233 InitializationData.FdoData.DeviceExtensionSize = FUNCTIONAL_EXTENSION_SIZE;
234 InitializationData.FdoData.DeviceType = FILE_DEVICE_DISK;
235 InitializationData.FdoData.DeviceCharacteristics = FILE_DEVICE_SECURE_OPEN;
236
237 InitializationData.FdoData.ClassInitDevice = DiskInitFdo;
238 InitializationData.FdoData.ClassStartDevice = DiskStartFdo;
239 InitializationData.FdoData.ClassStopDevice = DiskStopDevice;
240 InitializationData.FdoData.ClassRemoveDevice = DiskRemoveDevice;
241 InitializationData.FdoData.ClassPowerDevice = ClassSpinDownPowerHandler;
242
243 InitializationData.FdoData.ClassError = DiskFdoProcessError;
244 InitializationData.FdoData.ClassReadWriteVerification = DiskReadWriteVerification;
245 InitializationData.FdoData.ClassDeviceControl = DiskDeviceControl;
246 InitializationData.FdoData.ClassShutdownFlush = DiskShutdownFlush;
247 InitializationData.FdoData.ClassCreateClose = NULL;
248
249 //
250 // Setup sizes and entry points for physical device objects
251 //
252
253 InitializationData.PdoData.DeviceExtensionSize = PHYSICAL_EXTENSION_SIZE;
254 InitializationData.PdoData.DeviceType = FILE_DEVICE_DISK;
255 InitializationData.PdoData.DeviceCharacteristics = FILE_DEVICE_SECURE_OPEN;
256
257 InitializationData.PdoData.ClassInitDevice = DiskInitPdo;
258 InitializationData.PdoData.ClassStartDevice = DiskStartPdo;
259 InitializationData.PdoData.ClassStopDevice = DiskStopDevice;
260 InitializationData.PdoData.ClassRemoveDevice = DiskRemoveDevice;
261
262 //
263 // Use default power routine for PDOs
264 //
265
266 InitializationData.PdoData.ClassPowerDevice = NULL;
267
268 InitializationData.PdoData.ClassError = NULL;
269 InitializationData.PdoData.ClassReadWriteVerification = DiskReadWriteVerification;
270 InitializationData.PdoData.ClassDeviceControl = DiskDeviceControl;
271 InitializationData.PdoData.ClassShutdownFlush = DiskShutdownFlush;
272 InitializationData.PdoData.ClassCreateClose = NULL;
273
274 InitializationData.PdoData.ClassDeviceControl = DiskDeviceControl;
275
276 InitializationData.PdoData.ClassQueryPnpCapabilities = DiskQueryPnpCapabilities;
277
278 InitializationData.ClassAddDevice = DiskAddDevice;
279 InitializationData.ClassEnumerateDevice = DiskEnumerateDevice;
280
281 InitializationData.ClassQueryId = DiskQueryId;
282
283
284 InitializationData.FdoData.ClassWmiInfo.GuidCount = 7;
285 InitializationData.FdoData.ClassWmiInfo.GuidRegInfo = DiskWmiFdoGuidList;
286 InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiRegInfo = DiskFdoQueryWmiRegInfo;
287 InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiDataBlock = DiskFdoQueryWmiDataBlock;
288 InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataBlock = DiskFdoSetWmiDataBlock;
289 InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataItem = DiskFdoSetWmiDataItem;
290 InitializationData.FdoData.ClassWmiInfo.ClassExecuteWmiMethod = DiskFdoExecuteWmiMethod;
291 InitializationData.FdoData.ClassWmiInfo.ClassWmiFunctionControl = DiskWmiFunctionControl;
292
293
294 #if 0
295 //
296 // Enable this to add WMI support for PDOs
297 InitializationData.PdoData.ClassWmiInfo.GuidCount = 1;
298 InitializationData.PdoData.ClassWmiInfo.GuidRegInfo = DiskWmiPdoGuidList;
299 InitializationData.PdoData.ClassWmiInfo.ClassQueryWmiRegInfo = DiskPdoQueryWmiRegInfo;
300 InitializationData.PdoData.ClassWmiInfo.ClassQueryWmiDataBlock = DiskPdoQueryWmiDataBlock;
301 InitializationData.PdoData.ClassWmiInfo.ClassSetWmiDataBlock = DiskPdoSetWmiDataBlock;
302 InitializationData.PdoData.ClassWmiInfo.ClassSetWmiDataItem = DiskPdoSetWmiDataItem;
303 InitializationData.PdoData.ClassWmiInfo.ClassExecuteWmiMethod = DiskPdoExecuteWmiMethod;
304 InitializationData.PdoData.ClassWmiInfo.ClassWmiFunctionControl = DiskWmiFunctionControl;
305 #endif
306
307 InitializationData.ClassUnload = DiskUnload;
308
309 //
310 // Initialize regregistration data structures
311 //
312
313 DiskInitializeReregistration();
314
315 //
316 // Call the class init routine
317 //
318
319 status = ClassInitialize( DriverObject, RegistryPath, &InitializationData);
320
321 #if defined(_X86_)
322 if(NT_SUCCESS(status)) {
323 IoRegisterBootDriverReinitialization(DriverObject,
324 DiskDriverReinitialization,
325 NULL);
326 }
327 #endif
328
329 //
330 // Call class init Ex routine to register a
331 // PCLASS_QUERY_WMI_REGINFO_EX routine
332 //
333 RtlZeroMemory(&classQueryWmiRegInfoExList, sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST));
334 classQueryWmiRegInfoExList.Size = sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST);
335 classQueryWmiRegInfoExList.ClassFdoQueryWmiRegInfoEx = DiskFdoQueryWmiRegInfoEx;
336
337 ClassInitializeEx(DriverObject,
338 &guidQueryRegInfoEx,
339 &classQueryWmiRegInfoExList);
340
341 return status;
342
343 } // end DriverEntry()
344
345 \f
346 VOID
347 DiskUnload(
348 IN PDRIVER_OBJECT DriverObject
349 )
350 {
351 PAGED_CODE();
352
353 #if defined(_X86_)
354 DiskCleanupDetectInfo(DriverObject);
355 #endif
356 return;
357 }
358
359 \f
360 NTSTATUS
361 DiskCreateFdo(
362 IN PDRIVER_OBJECT DriverObject,
363 IN PDEVICE_OBJECT PhysicalDeviceObject,
364 IN PULONG DeviceCount,
365 IN BOOLEAN DasdAccessOnly
366 )
367
368 /*++
369
370 Routine Description:
371
372 This routine creates an object for the functional device
373
374 Arguments:
375
376 DriverObject - Pointer to driver object created by system.
377
378 PhysicalDeviceObject - Lower level driver we should attach to
379
380 DeviceCount - Number of previously installed devices.
381
382 DasdAccessOnly - indicates whether or not a file system is allowed to mount
383 on this device object. Used to avoid double-mounting of
384 file systems on super-floppies (which can unfortunately be
385 fixed disks). If set the i/o system will only allow rawfs
386 to be mounted.
387
388 Return Value:
389
390 NTSTATUS
391
392 --*/
393
394 {
395 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
396 STRING ntNameString;
397 UNICODE_STRING ntUnicodeString;
398
399 PUCHAR deviceName = NULL;
400
401 OBJECT_ATTRIBUTES objectAttributes;
402 HANDLE handle;
403
404 NTSTATUS status;
405
406 PDEVICE_OBJECT lowerDevice = NULL;
407 PDEVICE_OBJECT deviceObject = NULL;
408
409 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
410 STORAGE_PROPERTY_ID propertyId;
411 PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
412
413 PAGED_CODE();
414
415 *DeviceCount = 0;
416
417 //
418 // Set up an object directory to contain the objects for this
419 // device and all its partitions.
420 //
421
422 do {
423
424 WCHAR buffer[64];
425 UNICODE_STRING unicodeDirectoryName;
426
427 swprintf(buffer, L"\\Device\\Harddisk%d", *DeviceCount);
428
429 RtlInitUnicodeString(&unicodeDirectoryName, buffer);
430
431 InitializeObjectAttributes(&objectAttributes,
432 &unicodeDirectoryName,
433 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
434 NULL,
435 NULL);
436
437 status = ZwCreateDirectoryObject(&handle,
438 DIRECTORY_ALL_ACCESS,
439 &objectAttributes);
440
441 (*DeviceCount)++;
442
443 } while((status == STATUS_OBJECT_NAME_COLLISION) ||
444 (status == STATUS_OBJECT_NAME_EXISTS));
445
446 if (!NT_SUCCESS(status)) {
447
448 DebugPrint((1, "DiskCreateFdo: Could not create directory - %lx\n",
449 status));
450
451 return(status);
452 }
453
454 //
455 // When this loop exits the count is inflated by one - fix that.
456 //
457
458 (*DeviceCount)--;
459
460 //
461 // Claim the device.
462 //
463
464 lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
465
466 status = ClassClaimDevice(lowerDevice, FALSE);
467
468 if (!NT_SUCCESS(status)) {
469 ZwMakeTemporaryObject(handle);
470 ZwClose(handle);
471 ObDereferenceObject(lowerDevice);
472 return status;
473 }
474
475 //
476 // Create a device object for this device. Each physical disk will
477 // have at least one device object. The required device object
478 // describes the entire device. Its directory path is
479 // \Device\HarddiskN\Partition0, where N = device number.
480 //
481
482 status = DiskGenerateDeviceName(TRUE,
483 *DeviceCount,
484 0,
485 NULL,
486 NULL,
487 &deviceName);
488
489 if(!NT_SUCCESS(status)) {
490 DebugPrint((1, "DiskCreateFdo - couldn't create name %lx\n",
491 status));
492
493 goto DiskCreateFdoExit;
494
495 }
496
497 status = ClassCreateDeviceObject(DriverObject,
498 deviceName,
499 PhysicalDeviceObject,
500 TRUE,
501 &deviceObject);
502
503 if (!NT_SUCCESS(status)) {
504
505 DebugPrint((1,
506 "DiskCreateFdo: Can not create device object %s\n",
507 ntNameBuffer));
508
509 goto DiskCreateFdoExit;
510 }
511
512 //
513 // Indicate that IRPs should include MDLs for data transfers.
514 //
515
516 SET_FLAG(deviceObject->Flags, DO_DIRECT_IO);
517
518 fdoExtension = deviceObject->DeviceExtension;
519
520 if(DasdAccessOnly) {
521
522 //
523 // Inidicate that only RAW should be allowed to mount on the root
524 // partition object. This ensures that a file system can't doubly
525 // mount on a super-floppy by mounting once on P0 and once on P1.
526 //
527
528 SET_FLAG(deviceObject->Vpb->Flags, VPB_RAW_MOUNT);
529 }
530
531 //
532 // Initialize lock count to zero. The lock count is used to
533 // disable the ejection mechanism on devices that support
534 // removable media. Only the lock count in the physical
535 // device extension is used.
536 //
537
538 fdoExtension->LockCount = 0;
539
540 //
541 // Save system disk number.
542 //
543
544 fdoExtension->DeviceNumber = *DeviceCount;
545
546 //
547 // Set the alignment requirements for the device based on the
548 // host adapter requirements
549 //
550
551 if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
552 deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
553 }
554
555 //
556 // Finally, attach to the pdo
557 //
558
559 fdoExtension->LowerPdo = PhysicalDeviceObject;
560
561 fdoExtension->CommonExtension.LowerDeviceObject =
562 IoAttachDeviceToDeviceStack(
563 deviceObject,
564 PhysicalDeviceObject);
565
566 if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
567
568 //
569 // Uh - oh, we couldn't attach
570 // cleanup and return
571 //
572
573 status = STATUS_UNSUCCESSFUL;
574 goto DiskCreateFdoExit;
575 }
576
577 {
578 PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
579
580 //
581 // Initialize the partitioning lock as it may be used in the remove
582 // code.
583 //
584
585 KeInitializeEvent(&(diskData->PartitioningEvent),
586 SynchronizationEvent,
587 TRUE);
588 }
589
590
591 //
592 // Clear the init flag.
593 //
594
595 CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING);
596
597 //
598 // Store a handle to the device object directory for this disk
599 //
600
601 fdoExtension->DeviceDirectory = handle;
602
603 ObDereferenceObject(lowerDevice);
604
605 return STATUS_SUCCESS;
606
607 DiskCreateFdoExit:
608
609 //
610 // Release the device since an error occurred.
611 //
612
613 if (deviceObject != NULL) {
614 IoDeleteDevice(deviceObject);
615 }
616
617 //
618 // Delete directory and return.
619 //
620
621 if (!NT_SUCCESS(status)) {
622 ZwMakeTemporaryObject(handle);
623 ZwClose(handle);
624 }
625
626 ObDereferenceObject(lowerDevice);
627
628 return(status);
629 }
630
631 \f
632 NTSTATUS
633 DiskReadWriteVerification(
634 IN PDEVICE_OBJECT DeviceObject,
635 IN PIRP Irp
636 )
637
638 /*++
639
640 Routine Description:
641
642 I/O System entry for read and write requests to SCSI disks.
643
644 Arguments:
645
646 DeviceObject - Pointer to driver object created by system.
647 Irp - IRP involved.
648
649 Return Value:
650
651 NT Status
652
653 --*/
654
655 {
656 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
657
658 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
659 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
660 LARGE_INTEGER startingOffset;
661
662 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
663 commonExtension->PartitionZeroExtension;
664
665 ULONG residualBytes;
666 NTSTATUS status;
667
668 //
669 // Verify parameters of this request.
670 // Check that ending sector is within partition and
671 // that number of bytes to transfer is a multiple of
672 // the sector size.
673 //
674
675 startingOffset.QuadPart =
676 (currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
677 transferByteCount);
678
679 residualBytes = transferByteCount &
680 (fdoExtension->DiskGeometry.BytesPerSector - 1);
681
682
683 if ((startingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
684 (residualBytes != 0)) {
685
686 //
687 // This error may be caused by the fact that the drive is not ready.
688 //
689
690 status = ((PDISK_DATA) commonExtension->DriverData)->ReadyStatus;
691
692 if (!NT_SUCCESS(status)) {
693
694 //
695 // Flag this as a user errror so that a popup is generated.
696 //
697
698 DebugPrint((1, "DiskReadWriteVerification: ReadyStatus is %lx\n",
699 status));
700
701 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
702
703 //
704 // status will keep the current error
705 //
706
707 ASSERT( status != STATUS_INSUFFICIENT_RESOURCES );
708
709 } else if((commonExtension->IsFdo == TRUE) && (residualBytes == 0)) {
710
711 //
712 // This failed because we think the physical disk is too small.
713 // Send it down to the drive and let the hardware decide for
714 // itself.
715 //
716
717 status = STATUS_SUCCESS;
718
719 } else {
720
721 //
722 // Note fastfat depends on this parameter to determine when to
723 // remount due to a sector size change.
724 //
725
726 status = STATUS_INVALID_PARAMETER;
727
728 }
729
730 } else {
731
732 //
733 // the drive is ready, so ok the read/write
734 //
735
736 status = STATUS_SUCCESS;
737
738 }
739
740 Irp->IoStatus.Status = status;
741 return status;
742
743 } // end DiskReadWrite()
744
745
746 \f
747 NTSTATUS
748 DiskDetermineMediaTypes(
749 IN PDEVICE_OBJECT Fdo,
750 IN PIRP Irp,
751 IN UCHAR MediumType,
752 IN UCHAR DensityCode,
753 IN BOOLEAN MediaPresent,
754 IN BOOLEAN IsWritable
755 )
756
757 /*++
758
759 Routine Description:
760
761 Determines number of types based on the physical device, validates the user buffer
762 and builds the MEDIA_TYPE information.
763
764 Arguments:
765
766 DeviceObject - Pointer to functional device object created by system.
767 Irp - IOCTL_STORAGE_GET_MEDIA_TYPES_EX Irp.
768 MediumType - byte returned in mode data header.
769 DensityCode - byte returned in mode data block descriptor.
770 NumberOfTypes - pointer to be updated based on actual device.
771
772 Return Value:
773
774 Status is returned.
775
776 --*/
777
778 {
779 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
780 PPHYSICAL_DEVICE_EXTENSION pdoExtension = Fdo->DeviceExtension;
781 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
782 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
783
784 PGET_MEDIA_TYPES mediaTypes = Irp->AssociatedIrp.SystemBuffer;
785 PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
786 BOOLEAN deviceMatched = FALSE;
787
788 PAGED_CODE();
789
790 //
791 // this should be checked prior to calling into this routine
792 // as we use the buffer as mediaTypes
793 //
794 ASSERT(irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
795 sizeof(GET_MEDIA_TYPES));
796
797
798 //
799 // Determine if this device is removable or fixed.
800 //
801
802 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
803
804 //
805 // Fixed disk.
806 //
807
808 mediaTypes->DeviceType = FILE_DEVICE_DISK;
809 mediaTypes->MediaInfoCount = 1;
810
811 mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
812 mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
813 mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
814 mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
815 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
816
817 mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE);
818
819 if (!IsWritable) {
820 SET_FLAG(mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics,
821 MEDIA_WRITE_PROTECTED);
822 }
823
824 mediaInfo->DeviceSpecific.DiskInfo.MediaType = FixedMedia;
825
826
827 } else {
828
829 PUCHAR vendorId = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->VendorIdOffset;
830 PUCHAR productId = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductIdOffset;
831 PUCHAR productRevision = (PUCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductRevisionOffset;
832 DISK_MEDIA_TYPES_LIST const *mediaListEntry;
833 ULONG currentMedia;
834 ULONG i;
835 ULONG j;
836 ULONG sizeNeeded;
837
838 DebugPrint((1,
839 "DiskDetermineMediaTypes: Vendor %s, Product %s\n",
840 vendorId,
841 productId));
842
843 //
844 // Run through the list until we find the entry with a NULL Vendor Id.
845 //
846
847 for (i = 0; DiskMediaTypes[i].VendorId != NULL; i++) {
848
849 mediaListEntry = &DiskMediaTypes[i];
850
851 if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) {
852 continue;
853 }
854
855 if ((mediaListEntry->ProductId != NULL) &&
856 strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) {
857 continue;
858 }
859
860 if ((mediaListEntry->Revision != NULL) &&
861 strncmp(mediaListEntry->Revision, productRevision, strlen(mediaListEntry->Revision))) {
862 continue;
863 }
864
865 deviceMatched = TRUE;
866
867 mediaTypes->DeviceType = FILE_DEVICE_DISK;
868 mediaTypes->MediaInfoCount = mediaListEntry->NumberOfTypes;
869
870 //
871 // Ensure that buffer is large enough.
872 //
873
874 sizeNeeded = FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) +
875 (mediaListEntry->NumberOfTypes *
876 sizeof(DEVICE_MEDIA_INFO)
877 );
878
879 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
880 sizeNeeded) {
881
882 //
883 // Buffer too small
884 //
885
886 Irp->IoStatus.Information = sizeNeeded;
887 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
888 return STATUS_BUFFER_TOO_SMALL;
889 }
890
891 for (j = 0; j < mediaListEntry->NumberOfTypes; j++) {
892
893 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
894 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
895 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
896 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
897 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = mediaListEntry->NumberOfSides;
898
899 //
900 // Set the type.
901 //
902
903 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = mediaListEntry->MediaTypes[j];
904
905 if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == MO_5_WO) {
906 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_WRITE_ONCE;
907 } else {
908 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
909 }
910
911 //
912 // Status will either be success, if media is present, or no media.
913 // It would be optimal to base from density code and medium type, but not all devices
914 // have values for these fields.
915 //
916
917 if (MediaPresent) {
918
919 //
920 // The usage of MediumType and DensityCode is device specific, so this may need
921 // to be extended to further key off of product/vendor ids.
922 // Currently, the MO units are the only devices that return this information.
923 //
924
925 if (MediumType == 2) {
926 currentMedia = MO_5_WO;
927 } else if (MediumType == 3) {
928 currentMedia = MO_5_RW;
929
930 if (DensityCode == 0x87) {
931
932 //
933 // Indicate that the pinnacle 4.6 G media
934 // is present. Other density codes will default to normal
935 // RW MO media.
936 //
937
938 currentMedia = PINNACLE_APEX_5_RW;
939 }
940 } else {
941 currentMedia = 0;
942 }
943
944 if (currentMedia) {
945 if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == (STORAGE_MEDIA_TYPE)currentMedia) {
946 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
947 }
948
949 } else {
950 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
951 }
952 }
953
954 if (!IsWritable) {
955 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED);
956 }
957
958 //
959 // Advance to next entry.
960 //
961
962 mediaInfo++;
963 }
964 }
965
966 if (!deviceMatched) {
967
968 DebugPrint((1,
969 "DiskDetermineMediaTypes: Unknown device. Vendor: %s Product: %s Revision: %s\n",
970 vendorId,
971 productId,
972 productRevision));
973 //
974 // Build an entry for unknown.
975 //
976
977 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
978 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
979 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
980 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
981
982 //
983 // Set the type.
984 //
985
986 mediaTypes->DeviceType = FILE_DEVICE_DISK;
987 mediaTypes->MediaInfoCount = 1;
988
989 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia;
990 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
991
992 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
993 if (MediaPresent) {
994 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
995 }
996
997 if (!IsWritable) {
998 SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED);
999 }
1000 }
1001 }
1002
1003 Irp->IoStatus.Information =
1004 FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) +
1005 (mediaTypes->MediaInfoCount * sizeof(DEVICE_MEDIA_INFO));
1006
1007 return STATUS_SUCCESS;
1008
1009 }
1010
1011 \f
1012 NTSTATUS
1013 DiskDeviceControl(
1014 PDEVICE_OBJECT DeviceObject,
1015 PIRP Irp
1016 )
1017
1018 /*++
1019
1020 Routine Description:
1021
1022 I/O system entry for device controls to SCSI disks.
1023
1024 Arguments:
1025
1026 Fdo - Pointer to functional device object created by system.
1027 Irp - IRP involved.
1028
1029 Return Value:
1030
1031 Status is returned.
1032
1033 --*/
1034
1035 #define SendToFdo(Dev, Irp, Rval) { \
1036 PCOMMON_DEVICE_EXTENSION ce = Dev->DeviceExtension; \
1037 ASSERT_PDO(Dev); \
1038 IoCopyCurrentIrpStackLocationToNext(Irp); \
1039 Rval = IoCallDriver(ce->LowerDeviceObject, Irp); \
1040 }
1041
1042 {
1043 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1044 PPHYSICAL_DEVICE_EXTENSION pdoExtension = DeviceObject->DeviceExtension;
1045 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1046
1047 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1048 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
1049 PSCSI_REQUEST_BLOCK srb;
1050 PCDB cdb;
1051 PMODE_PARAMETER_HEADER modeData;
1052 PIRP irp2;
1053 ULONG length;
1054 NTSTATUS status;
1055 KEVENT event;
1056 IO_STATUS_BLOCK ioStatus;
1057
1058 BOOLEAN b = FALSE;
1059
1060 srb = ExAllocatePoolWithTag(NonPagedPool,
1061 SCSI_REQUEST_BLOCK_SIZE,
1062 DISK_TAG_SRB);
1063 Irp->IoStatus.Information = 0;
1064
1065 if (srb == NULL) {
1066
1067 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1068 ClassReleaseRemoveLock(DeviceObject, Irp);
1069 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1070 return(STATUS_INSUFFICIENT_RESOURCES);
1071 }
1072
1073 //
1074 // Write zeros to Srb.
1075 //
1076
1077 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1078
1079 cdb = (PCDB)srb->Cdb;
1080
1081 switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
1082
1083 case IOCTL_DISK_GET_CACHE_INFORMATION:
1084 b = TRUE;
1085 case IOCTL_DISK_SET_CACHE_INFORMATION: {
1086
1087 BOOLEAN getCaching = b;
1088 PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer;
1089
1090 if(!commonExtension->IsFdo) {
1091
1092 ClassReleaseRemoveLock(DeviceObject, Irp);
1093 ExFreePool(srb);
1094 SendToFdo(DeviceObject, Irp, status);
1095 return status;
1096 }
1097
1098 //
1099 // Validate the request.
1100 //
1101
1102 if((getCaching) &&
1103 (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1104 sizeof(DISK_CACHE_INFORMATION))
1105 ) {
1106 status = STATUS_BUFFER_TOO_SMALL;
1107 Irp->IoStatus.Information = sizeof(DISK_CACHE_INFORMATION);
1108 break;
1109 }
1110
1111 if ((!getCaching) &&
1112 (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1113 sizeof(DISK_CACHE_INFORMATION))
1114 ) {
1115
1116 status = STATUS_INFO_LENGTH_MISMATCH;
1117 break;
1118 }
1119
1120 ASSERT(Irp->AssociatedIrp.SystemBuffer != NULL);
1121
1122 if (getCaching) {
1123
1124 status = DiskGetCacheInformation(fdoExtension, cacheInfo);
1125
1126 if (NT_SUCCESS(status)) {
1127 Irp->IoStatus.Information = sizeof(DISK_CACHE_INFORMATION);
1128 }
1129
1130 } else {
1131
1132 if (!cacheInfo->WriteCacheEnabled)
1133 {
1134 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags,
1135 CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED))
1136 {
1137 //
1138 // This request wants to disable write cache, which is
1139 // not supported on this device. Instead of sending it
1140 // down only to see it fail, return the error code now
1141 //
1142 status = STATUS_INVALID_DEVICE_REQUEST;
1143 break;
1144 }
1145 }
1146 else
1147 {
1148 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags,
1149 CLASS_SPECIAL_DISABLE_WRITE_CACHE))
1150 {
1151 //
1152 // This request wants to enable write cache, which
1153 // has been disabled to protect data integrity. So
1154 // fail this request with access denied
1155 //
1156 status = STATUS_ACCESS_DENIED;
1157 break;
1158 }
1159 }
1160
1161 status = DiskSetCacheInformation(fdoExtension, cacheInfo);
1162
1163 if (NT_SUCCESS(status))
1164 {
1165 //
1166 // Store the user-defined override in the registry
1167 //
1168 ClassSetDeviceParameter(fdoExtension,
1169 DiskDeviceParameterSubkey,
1170 DiskDeviceUserWriteCacheSetting,
1171 (cacheInfo->WriteCacheEnabled) ? DiskWriteCacheEnable : DiskWriteCacheDisable);
1172 }
1173 else if (status == STATUS_INVALID_DEVICE_REQUEST)
1174 {
1175 if (cacheInfo->WriteCacheEnabled == FALSE)
1176 {
1177 //
1178 // This device does not allow for
1179 // the write cache to be disabled
1180 //
1181 ULONG specialFlags = 0;
1182
1183 ClassGetDeviceParameter(fdoExtension,
1184 DiskDeviceParameterSubkey,
1185 DiskDeviceSpecialFlags,
1186 &specialFlags);
1187
1188 SET_FLAG(specialFlags, HackDisableWriteCacheNotSupported);
1189
1190 SET_FLAG(fdoExtension->ScanForSpecialFlags,
1191 CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED);
1192
1193 ClassSetDeviceParameter(fdoExtension,
1194 DiskDeviceParameterSubkey,
1195 DiskDeviceSpecialFlags,
1196 specialFlags);
1197 }
1198 }
1199 }
1200
1201 break;
1202 }
1203
1204 #if(_WIN32_WINNT >= 0x0500)
1205 case IOCTL_DISK_GET_WRITE_CACHE_STATE: {
1206
1207 PDISK_WRITE_CACHE_STATE writeCacheState = (PDISK_WRITE_CACHE_STATE)Irp->AssociatedIrp.SystemBuffer;
1208
1209 if(!commonExtension->IsFdo) {
1210
1211 ClassReleaseRemoveLock(DeviceObject, Irp);
1212 ExFreePool(srb);
1213 SendToFdo(DeviceObject, Irp, status);
1214 return status;
1215 }
1216
1217 //
1218 // Validate the request.
1219 //
1220
1221 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_WRITE_CACHE_STATE)) {
1222
1223 status = STATUS_BUFFER_TOO_SMALL;
1224 Irp->IoStatus.Information = sizeof(DISK_WRITE_CACHE_STATE);
1225 break;
1226 }
1227
1228 *writeCacheState = DiskWriteCacheNormal;
1229
1230 //
1231 // Determine whether it is possible to disable the write cache
1232 //
1233
1234 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_WRITE_CACHE_NOT_SUPPORTED))
1235 {
1236 *writeCacheState = DiskWriteCacheDisableNotSupported;
1237 }
1238
1239 //
1240 // Determine whether it is safe to toggle the write cache
1241 //
1242
1243 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_DISABLE_WRITE_CACHE))
1244 {
1245 *writeCacheState = DiskWriteCacheForceDisable;
1246 }
1247
1248 Irp->IoStatus.Information = sizeof(DISK_WRITE_CACHE_STATE);
1249 status = STATUS_SUCCESS;
1250 break;
1251 }
1252 #endif
1253
1254 case SMART_GET_VERSION: {
1255
1256 PUCHAR buffer;
1257 PSRB_IO_CONTROL srbControl;
1258 PGETVERSIONINPARAMS versionParams;
1259
1260 if(!commonExtension->IsFdo) {
1261 ClassReleaseRemoveLock(DeviceObject, Irp);
1262 ExFreePool(srb);
1263 SendToFdo(DeviceObject, Irp, status);
1264 return status;
1265 }
1266
1267 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1268 sizeof(GETVERSIONINPARAMS)) {
1269 status = STATUS_BUFFER_TOO_SMALL;
1270 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
1271 break;
1272 }
1273
1274 //
1275 // Create notification event object to be used to signal the
1276 // request completion.
1277 //
1278
1279 KeInitializeEvent(&event, NotificationEvent, FALSE);
1280
1281 srbControl = ExAllocatePoolWithTag(NonPagedPool,
1282 sizeof(SRB_IO_CONTROL) +
1283 sizeof(GETVERSIONINPARAMS),
1284 DISK_TAG_SMART);
1285
1286 if (!srbControl) {
1287 status = STATUS_INSUFFICIENT_RESOURCES;
1288 break;
1289 }
1290
1291 RtlZeroMemory(srbControl,
1292 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS)
1293 );
1294
1295 //
1296 // fill in srbControl fields
1297 //
1298
1299 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1300 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1301 srbControl->Timeout = fdoExtension->TimeOutValue;
1302 srbControl->Length = sizeof(GETVERSIONINPARAMS);
1303 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
1304
1305 //
1306 // Point to the 'buffer' portion of the SRB_CONTROL
1307 //
1308
1309 buffer = (PUCHAR)srbControl;
1310 buffer += srbControl->HeaderLength;
1311
1312 //
1313 // Ensure correct target is set in the cmd parameters.
1314 //
1315
1316 versionParams = (PGETVERSIONINPARAMS)buffer;
1317 versionParams->bIDEDeviceMap = diskData->ScsiAddress.TargetId;
1318
1319 //
1320 // Copy the IOCTL parameters to the srb control buffer area.
1321 //
1322
1323 RtlMoveMemory(buffer,
1324 Irp->AssociatedIrp.SystemBuffer,
1325 sizeof(GETVERSIONINPARAMS));
1326
1327 ClassSendDeviceIoControlSynchronous(
1328 IOCTL_SCSI_MINIPORT,
1329 commonExtension->LowerDeviceObject,
1330 srbControl,
1331 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1332 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
1333 FALSE,
1334 &ioStatus);
1335
1336 status = ioStatus.Status;
1337
1338 //
1339 // If successful, copy the data received into the output buffer.
1340 // This should only fail in the event that the IDE driver is older
1341 // than this driver.
1342 //
1343
1344 if (NT_SUCCESS(status)) {
1345
1346 buffer = (PUCHAR)srbControl;
1347 buffer += srbControl->HeaderLength;
1348
1349 RtlMoveMemory (Irp->AssociatedIrp.SystemBuffer, buffer,
1350 sizeof(GETVERSIONINPARAMS));
1351 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
1352 }
1353
1354 ExFreePool(srbControl);
1355 break;
1356 }
1357
1358 case SMART_RCV_DRIVE_DATA: {
1359
1360 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1361 ULONG controlCode = 0;
1362 PSRB_IO_CONTROL srbControl;
1363 PUCHAR buffer;
1364
1365 if(!commonExtension->IsFdo) {
1366 ClassReleaseRemoveLock(DeviceObject, Irp);
1367 ExFreePool(srb);
1368 SendToFdo(DeviceObject, Irp, status);
1369 return status;
1370 }
1371
1372 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1373 (sizeof(SENDCMDINPARAMS) - 1)) {
1374 status = STATUS_INVALID_PARAMETER;
1375 Irp->IoStatus.Information = 0;
1376 break;
1377
1378 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1379 (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
1380 status = STATUS_BUFFER_TOO_SMALL;
1381 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) + 512 - 1;
1382 break;
1383 }
1384
1385 //
1386 // Create notification event object to be used to signal the
1387 // request completion.
1388 //
1389
1390 KeInitializeEvent(&event, NotificationEvent, FALSE);
1391
1392 //
1393 // use controlCode as a sort of 'STATUS_SUCCESS' to see if it's
1394 // a valid request type
1395 //
1396
1397 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
1398
1399 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1400 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
1401
1402 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1403 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1404 case READ_ATTRIBUTES:
1405 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
1406 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1407 break;
1408 case READ_THRESHOLDS:
1409 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
1410 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
1411 break;
1412 default:
1413 status = STATUS_INVALID_PARAMETER;
1414 break;
1415 }
1416 } else {
1417
1418 status = STATUS_INVALID_PARAMETER;
1419 }
1420
1421 if (controlCode == 0) {
1422 status = STATUS_INVALID_PARAMETER;
1423 break;
1424 }
1425
1426 srbControl = ExAllocatePoolWithTag(NonPagedPool,
1427 sizeof(SRB_IO_CONTROL) + length,
1428 DISK_TAG_SMART);
1429
1430 if (!srbControl) {
1431 status = STATUS_INSUFFICIENT_RESOURCES;
1432 break;
1433 }
1434
1435 //
1436 // fill in srbControl fields
1437 //
1438
1439 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1440 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1441 srbControl->Timeout = fdoExtension->TimeOutValue;
1442 srbControl->Length = length;
1443 srbControl->ControlCode = controlCode;
1444
1445 //
1446 // Point to the 'buffer' portion of the SRB_CONTROL
1447 //
1448
1449 buffer = (PUCHAR)srbControl;
1450 buffer += srbControl->HeaderLength;
1451
1452 //
1453 // Ensure correct target is set in the cmd parameters.
1454 //
1455
1456 cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
1457
1458 //
1459 // Copy the IOCTL parameters to the srb control buffer area.
1460 //
1461
1462 RtlMoveMemory(buffer,
1463 Irp->AssociatedIrp.SystemBuffer,
1464 sizeof(SENDCMDINPARAMS) - 1);
1465
1466 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1467 commonExtension->LowerDeviceObject,
1468 srbControl,
1469 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1470 srbControl,
1471 sizeof(SRB_IO_CONTROL) + length,
1472 FALSE,
1473 &event,
1474 &ioStatus);
1475
1476 if (irp2 == NULL) {
1477 status = STATUS_INSUFFICIENT_RESOURCES;
1478 ExFreePool(srbControl);
1479 break;
1480 }
1481
1482 //
1483 // Call the port driver with the request and wait for it to complete.
1484 //
1485
1486 status = IoCallDriver(commonExtension->LowerDeviceObject, irp2);
1487
1488 if (status == STATUS_PENDING) {
1489 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
1490 status = ioStatus.Status;
1491 }
1492
1493 //
1494 // Copy the data received into the output buffer. Since the status buffer
1495 // contains error information also, always perform this copy. IO will will
1496 // either pass this back to the app, or zero it, in case of error.
1497 //
1498
1499 buffer = (PUCHAR)srbControl;
1500 buffer += srbControl->HeaderLength;
1501
1502 if (NT_SUCCESS(status)) {
1503
1504 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length - 1);
1505 Irp->IoStatus.Information = length - 1;
1506
1507 } else {
1508
1509 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
1510 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
1511
1512 }
1513
1514 ExFreePool(srbControl);
1515 break;
1516
1517 }
1518
1519 case SMART_SEND_DRIVE_COMMAND: {
1520
1521 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
1522 PSRB_IO_CONTROL srbControl;
1523 ULONG controlCode = 0;
1524 PUCHAR buffer;
1525
1526 if(!commonExtension->IsFdo) {
1527 ClassReleaseRemoveLock(DeviceObject, Irp);
1528 ExFreePool(srb);
1529 SendToFdo(DeviceObject, Irp, status);
1530 return status;
1531 }
1532
1533 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1534 (sizeof(SENDCMDINPARAMS) - 1)) {
1535 status = STATUS_INVALID_PARAMETER;
1536 Irp->IoStatus.Information = 0;
1537 break;
1538
1539 } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1540 (sizeof(SENDCMDOUTPARAMS) - 1)) {
1541 status = STATUS_BUFFER_TOO_SMALL;
1542 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
1543 break;
1544 }
1545
1546 //
1547 // Create notification event object to be used to signal the
1548 // request completion.
1549 //
1550
1551 KeInitializeEvent(&event, NotificationEvent, FALSE);
1552
1553 length = 0;
1554
1555 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1556 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1557
1558 case ENABLE_SMART:
1559 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
1560 break;
1561
1562 case DISABLE_SMART:
1563 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
1564 break;
1565
1566 case RETURN_SMART_STATUS:
1567
1568 //
1569 // Ensure bBuffer is at least 2 bytes (to hold the values of
1570 // cylinderLow and cylinderHigh).
1571 //
1572
1573 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1574 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
1575
1576 status = STATUS_BUFFER_TOO_SMALL;
1577 Irp->IoStatus.Information =
1578 sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
1579 break;
1580 }
1581
1582 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
1583 length = sizeof(IDEREGS);
1584 break;
1585
1586 case ENABLE_DISABLE_AUTOSAVE:
1587 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
1588 break;
1589
1590 case SAVE_ATTRIBUTE_VALUES:
1591 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
1592 break;
1593
1594 case EXECUTE_OFFLINE_DIAGS:
1595 //
1596 // Validate that this is an ok self test command
1597 //
1598 if (DiskIsValidSmartSelfTest(cmdInParameters->irDriveRegs.bSectorNumberReg))
1599 {
1600 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
1601 }
1602 break;
1603
1604 case ENABLE_DISABLE_AUTO_OFFLINE:
1605 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE;
1606 break;
1607
1608 default:
1609 status = STATUS_INVALID_PARAMETER;
1610 break;
1611 }
1612 } else {
1613
1614 status = STATUS_INVALID_PARAMETER;
1615 }
1616
1617 if (controlCode == 0) {
1618 status = STATUS_INVALID_PARAMETER;
1619 break;
1620 }
1621
1622 length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);;
1623 srbControl = ExAllocatePoolWithTag(NonPagedPool,
1624 sizeof(SRB_IO_CONTROL) + length,
1625 DISK_TAG_SMART);
1626
1627 if (!srbControl) {
1628 status = STATUS_INSUFFICIENT_RESOURCES;
1629 break;
1630 }
1631
1632 //
1633 // fill in srbControl fields
1634 //
1635
1636 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
1637 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
1638 srbControl->Timeout = fdoExtension->TimeOutValue;
1639 srbControl->Length = length;
1640
1641 //
1642 // Point to the 'buffer' portion of the SRB_CONTROL
1643 //
1644
1645 buffer = (PUCHAR)srbControl;
1646 buffer += srbControl->HeaderLength;
1647
1648 //
1649 // Ensure correct target is set in the cmd parameters.
1650 //
1651
1652 cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
1653
1654 //
1655 // Copy the IOCTL parameters to the srb control buffer area.
1656 //
1657
1658 RtlMoveMemory(buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
1659
1660 srbControl->ControlCode = controlCode;
1661
1662 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
1663 commonExtension->LowerDeviceObject,
1664 srbControl,
1665 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
1666 srbControl,
1667 sizeof(SRB_IO_CONTROL) + length,
1668 FALSE,
1669 &event,
1670 &ioStatus);
1671
1672 if (irp2 == NULL) {
1673 status = STATUS_INSUFFICIENT_RESOURCES;
1674 ExFreePool(srbControl);
1675 break;
1676 }
1677
1678 //
1679 // Call the port driver with the request and wait for it to complete.
1680 //
1681
1682 status = IoCallDriver(commonExtension->LowerDeviceObject, irp2);
1683
1684 if (status == STATUS_PENDING) {
1685 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
1686 status = ioStatus.Status;
1687 }
1688
1689 //
1690 // Copy the data received into the output buffer. Since the status buffer
1691 // contains error information also, always perform this copy. IO will will
1692 // either pass this back to the app, or zero it, in case of error.
1693 //
1694
1695 buffer = (PUCHAR)srbControl;
1696 buffer += srbControl->HeaderLength;
1697
1698 //
1699 // Update the return buffer size based on the sub-command.
1700 //
1701
1702 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
1703 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
1704 } else {
1705 length = sizeof(SENDCMDOUTPARAMS) - 1;
1706 }
1707
1708 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length);
1709 Irp->IoStatus.Information = length;
1710
1711 ExFreePool(srbControl);
1712 break;
1713
1714 }
1715
1716 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {
1717
1718 PMODE_PARAMETER_BLOCK blockDescriptor;
1719 ULONG modeLength;
1720 ULONG retries = 4;
1721 BOOLEAN writable = FALSE;
1722 BOOLEAN mediaPresent = FALSE;
1723
1724 DebugPrint((3,
1725 "Disk.DiskDeviceControl: GetMediaTypes\n"));
1726
1727 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1728 sizeof(GET_MEDIA_TYPES)) {
1729 status = STATUS_BUFFER_TOO_SMALL;
1730 Irp->IoStatus.Information = sizeof(GET_MEDIA_TYPES);
1731 break;
1732 }
1733
1734 if(!commonExtension->IsFdo) {
1735 ClassReleaseRemoveLock(DeviceObject, Irp);
1736 ExFreePool(srb);
1737 SendToFdo(DeviceObject, Irp, status);
1738 return status;
1739 }
1740
1741 //
1742 // Send a TUR to determine if media is present.
1743 //
1744
1745 srb->CdbLength = 6;
1746 cdb = (PCDB)srb->Cdb;
1747 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
1748
1749 //
1750 // Set timeout value.
1751 //
1752
1753 srb->TimeOutValue = fdoExtension->TimeOutValue;
1754
1755 status = ClassSendSrbSynchronous(DeviceObject,
1756 srb,
1757 NULL,
1758 0,
1759 FALSE);
1760
1761
1762 if (NT_SUCCESS(status)) {
1763 mediaPresent = TRUE;
1764 }
1765
1766 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1767
1768 //
1769 // Allocate memory for mode header and block descriptor.
1770 //
1771
1772 modeLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
1773 modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
1774 modeLength,
1775 DISK_TAG_MODE_DATA);
1776
1777 if (modeData == NULL) {
1778 status = STATUS_INSUFFICIENT_RESOURCES;
1779 break;
1780 }
1781
1782 RtlZeroMemory(modeData, modeLength);
1783
1784 //
1785 // Build the MODE SENSE CDB.
1786 //
1787
1788 srb->CdbLength = 6;
1789 cdb = (PCDB)srb->Cdb;
1790
1791 //
1792 // Set timeout value from device extension.
1793 //
1794
1795 srb->TimeOutValue = fdoExtension->TimeOutValue;
1796
1797 //
1798 // Page code of 0 will return header and block descriptor only.
1799 //
1800
1801 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1802 cdb->MODE_SENSE.PageCode = 0;
1803 cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
1804
1805 Retry:
1806 status = ClassSendSrbSynchronous(DeviceObject,
1807 srb,
1808 modeData,
1809 modeLength,
1810 FALSE);
1811
1812
1813 if (status == STATUS_VERIFY_REQUIRED) {
1814
1815 if (retries--) {
1816
1817 //
1818 // Retry request.
1819 //
1820
1821 goto Retry;
1822 }
1823 } else if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
1824 status = STATUS_SUCCESS;
1825 }
1826
1827 if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) {
1828
1829 //
1830 // Get the block descriptor.
1831 //
1832
1833 blockDescriptor = (PMODE_PARAMETER_BLOCK)modeData;
1834 blockDescriptor = (PMODE_PARAMETER_BLOCK)((ULONG_PTR)blockDescriptor + sizeof(MODE_PARAMETER_HEADER));
1835
1836 //
1837 // Do some validation.
1838 //
1839
1840 if (modeData->BlockDescriptorLength != sizeof(MODE_PARAMETER_BLOCK)) {
1841
1842 DebugPrint((1,
1843 "DiskDeviceControl: BlockDescriptor length - "
1844 "Expected %x, actual %x\n",
1845 modeData->BlockDescriptorLength,
1846 sizeof(MODE_PARAMETER_BLOCK)));
1847 }
1848
1849 DebugPrint((1,
1850 "DiskDeviceControl: DensityCode %x, MediumType %x\n",
1851 blockDescriptor->DensityCode,
1852 modeData->MediumType));
1853
1854 if (TEST_FLAG(modeData->DeviceSpecificParameter,
1855 MODE_DSP_WRITE_PROTECT)) {
1856 writable = FALSE;
1857 } else {
1858 writable = TRUE;
1859 }
1860
1861 status = DiskDetermineMediaTypes(DeviceObject,
1862 Irp,
1863 modeData->MediumType,
1864 blockDescriptor->DensityCode,
1865 mediaPresent,
1866 writable);
1867
1868 //
1869 // If the buffer was too small, DetermineMediaTypes updated the status and information and the request will fail.
1870 //
1871
1872 } else {
1873 DebugPrint((1,
1874 "DiskDeviceControl: Mode sense for header/bd failed. %lx\n",
1875 status));
1876 }
1877
1878 ExFreePool(modeData);
1879 break;
1880 }
1881
1882 case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
1883
1884 DebugPrint((2, "IOCTL_DISK_GET_DRIVE_GEOMETRY to device %p through irp %p\n",
1885 DeviceObject, Irp));
1886 DebugPrint((2, "Device is a%s.\n",
1887 commonExtension->IsFdo ? "n fdo" : " pdo"));
1888
1889 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1890 sizeof(DISK_GEOMETRY)) {
1891
1892 status = STATUS_BUFFER_TOO_SMALL;
1893 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1894 break;
1895 }
1896
1897 if(!commonExtension->IsFdo) {
1898
1899 //
1900 // Pdo should issue this request to the lower device object
1901 //
1902
1903 ClassReleaseRemoveLock(DeviceObject, Irp);
1904 ExFreePool(srb);
1905 SendToFdo(DeviceObject, Irp, status);
1906 return status;
1907 }
1908
1909 // DiskAcquirePartitioningLock(fdoExtension);
1910
1911 if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
1912
1913 //
1914 // Issue ReadCapacity to update device extension
1915 // with information for current media.
1916 //
1917
1918 status = DiskReadDriveCapacity(
1919 commonExtension->PartitionZeroExtension->DeviceObject);
1920
1921 //
1922 // Note whether the drive is ready.
1923 //
1924
1925 diskData->ReadyStatus = status;
1926
1927 if (!NT_SUCCESS(status)) {
1928 // DiskReleasePartitioningLock(fdoExtension);
1929 break;
1930 }
1931 }
1932
1933 //
1934 // Copy drive geometry information from device extension.
1935 //
1936
1937 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
1938 &(fdoExtension->DiskGeometry),
1939 sizeof(DISK_GEOMETRY));
1940
1941 status = STATUS_SUCCESS;
1942 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1943 // DiskReleasePartitioningLock(fdoExtension);
1944 break;
1945 }
1946
1947 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: {
1948 DebugPrint((1, "IOCTL_DISK_GET_DRIVE_GEOMETRY_EX to device %p through irp %p\n",
1949 DeviceObject, Irp));
1950 DebugPrint((1, "Device Is a%s.\n",
1951 commonExtension->IsFdo ? "n fdo" : " pdo"));
1952
1953
1954 if (!commonExtension->IsFdo) {
1955
1956 //
1957 // Pdo should issue this request to the lower device object
1958 //
1959
1960 ClassReleaseRemoveLock (DeviceObject, Irp);
1961 ExFreePool (srb);
1962 SendToFdo (DeviceObject, Irp, status);
1963 return status;
1964
1965 } else {
1966
1967 status = DiskIoctlGetDriveGeometryEx( DeviceObject, Irp );
1968 }
1969
1970 break;
1971 }
1972
1973 case IOCTL_STORAGE_PREDICT_FAILURE : {
1974
1975 PSTORAGE_PREDICT_FAILURE checkFailure;
1976 STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
1977
1978 DebugPrint((2, "IOCTL_STORAGE_PREDICT_FAILURE to device %p through irp %p\n",
1979 DeviceObject, Irp));
1980 DebugPrint((2, "Device is a%s.\n",
1981 commonExtension->IsFdo ? "n fdo" : " pdo"));
1982
1983 checkFailure = (PSTORAGE_PREDICT_FAILURE)Irp->AssociatedIrp.SystemBuffer;
1984
1985 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1986 sizeof(STORAGE_PREDICT_FAILURE)) {
1987
1988 status = STATUS_BUFFER_TOO_SMALL;
1989 Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE);
1990 break;
1991 }
1992
1993 if(!commonExtension->IsFdo) {
1994
1995 //
1996 // Pdo should issue this request to the lower device object
1997 //
1998
1999 ClassReleaseRemoveLock(DeviceObject, Irp);
2000 ExFreePool(srb);
2001 SendToFdo(DeviceObject, Irp, status);
2002 return status;
2003 }
2004
2005 //
2006 // See if the disk is predicting failure
2007 //
2008
2009 if (diskData->FailurePredictionCapability == FailurePredictionSense) {
2010 ULONG readBufferSize;
2011 PUCHAR readBuffer;
2012 PIRP readIrp;
2013 IO_STATUS_BLOCK ioStatus;
2014 PDEVICE_OBJECT topOfStack;
2015
2016 checkFailure->PredictFailure = 0;
2017
2018 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
2019
2020 topOfStack = IoGetAttachedDeviceReference(DeviceObject);
2021
2022 //
2023 // SCSI disks need to have a read sent down to provoke any
2024 // failures to be reported.
2025 //
2026 // Issue a normal read operation. The error-handling code in
2027 // classpnp will take care of a failure prediction by logging the
2028 // correct event.
2029 //
2030
2031 readBufferSize = fdoExtension->DiskGeometry.BytesPerSector;
2032 readBuffer = ExAllocatePoolWithTag(NonPagedPool,
2033 readBufferSize,
2034 DISK_TAG_SMART);
2035
2036 if (readBuffer != NULL) {
2037 LARGE_INTEGER offset;
2038
2039 offset.QuadPart = 0;
2040 readIrp = IoBuildSynchronousFsdRequest(
2041 IRP_MJ_READ,
2042 topOfStack,
2043 readBuffer,
2044 readBufferSize,
2045 &offset,
2046 &event,
2047 &ioStatus);
2048
2049
2050 if (readIrp != NULL) {
2051 status = IoCallDriver(topOfStack, readIrp);
2052 if (status == STATUS_PENDING) {
2053 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
2054 status = ioStatus.Status;
2055 }
2056 }
2057
2058 ExFreePool(readBuffer);
2059 }
2060 ObDereferenceObject(topOfStack);
2061 }
2062
2063 if ((diskData->FailurePredictionCapability == FailurePredictionSmart) ||
2064 (diskData->FailurePredictionCapability == FailurePredictionSense))
2065 {
2066 status = DiskReadFailurePredictStatus(fdoExtension,
2067 &diskSmartStatus);
2068
2069 if (NT_SUCCESS(status))
2070 {
2071 status = DiskReadFailurePredictData(fdoExtension,
2072 Irp->AssociatedIrp.SystemBuffer);
2073
2074 if (diskSmartStatus.PredictFailure)
2075 {
2076 checkFailure->PredictFailure = 1;
2077 } else {
2078 checkFailure->PredictFailure = 0;
2079 }
2080
2081 Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE);
2082 }
2083 } else {
2084 status = STATUS_INVALID_DEVICE_REQUEST;
2085 }
2086
2087 break;
2088 }
2089
2090 case IOCTL_DISK_VERIFY: {
2091
2092 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
2093 LARGE_INTEGER byteOffset;
2094
2095 DebugPrint((2, "IOCTL_DISK_VERIFY to device %p through irp %p\n",
2096 DeviceObject, Irp));
2097 DebugPrint((2, "Device is a%s.\n",
2098 commonExtension->IsFdo ? "n fdo" : " pdo"));
2099
2100 //
2101 // Validate buffer length.
2102 //
2103
2104 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2105 sizeof(VERIFY_INFORMATION)) {
2106
2107 status = STATUS_INFO_LENGTH_MISMATCH;
2108 break;
2109 }
2110
2111 //
2112 // Add disk offset to starting sector.
2113 //
2114
2115 byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart +
2116 verifyInfo->StartingOffset.QuadPart;
2117
2118 if(!commonExtension->IsFdo) {
2119
2120 //
2121 // Adjust the request and forward it down
2122 //
2123
2124 verifyInfo->StartingOffset.QuadPart = byteOffset.QuadPart;
2125
2126 ClassReleaseRemoveLock(DeviceObject, Irp);
2127 SendToFdo(DeviceObject, Irp, status);
2128 ExFreePool(srb);
2129 return status;
2130 }
2131
2132 //
2133 // Perform a bounds check on the sector range
2134 //
2135
2136 if ((verifyInfo->StartingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
2137 (verifyInfo->StartingOffset.QuadPart < 0))
2138 {
2139 status = STATUS_NONEXISTENT_SECTOR;
2140 break;
2141 }
2142 else
2143 {
2144 ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart;
2145
2146 if ((ULONGLONG)verifyInfo->Length > bytesRemaining)
2147 {
2148 status = STATUS_NONEXISTENT_SECTOR;
2149 break;
2150 }
2151 }
2152
2153 {
2154 PDISK_VERIFY_WORKITEM_CONTEXT Context = NULL;
2155
2156 Context = ExAllocatePoolWithTag(NonPagedPool,
2157 sizeof(DISK_VERIFY_WORKITEM_CONTEXT),
2158 DISK_TAG_WI_CONTEXT);
2159
2160 if (Context)
2161 {
2162 Context->Irp = Irp;
2163 Context->Srb = srb;
2164 Context->WorkItem = IoAllocateWorkItem(DeviceObject);
2165
2166 if (Context->WorkItem)
2167 {
2168 IoMarkIrpPending(Irp);
2169
2170 IoQueueWorkItem(Context->WorkItem,
2171 (PIO_WORKITEM_ROUTINE)DiskIoctlVerify,
2172 DelayedWorkQueue,
2173 Context);
2174
2175 return STATUS_PENDING;
2176 }
2177
2178 ExFreePool(Context);
2179 }
2180
2181 status = STATUS_INSUFFICIENT_RESOURCES;
2182 }
2183
2184 break;
2185 }
2186
2187 case IOCTL_DISK_CREATE_DISK: {
2188
2189 if (!commonExtension->IsFdo) {
2190 ClassReleaseRemoveLock(DeviceObject, Irp);
2191 ExFreePool(srb);
2192 SendToFdo(DeviceObject, Irp, status);
2193 return status;
2194 }
2195
2196 status = DiskIoctlCreateDisk (
2197 DeviceObject,
2198 Irp
2199 );
2200 break;
2201 }
2202
2203 case IOCTL_DISK_GET_DRIVE_LAYOUT: {
2204
2205 DebugPrint((1, "IOCTL_DISK_GET_DRIVE_LAYOUT to device %p through irp %p\n",
2206 DeviceObject, Irp));
2207 DebugPrint((1, "Device is a%s.\n",
2208 commonExtension->IsFdo ? "n fdo" : " pdo"));
2209
2210 if (!commonExtension->IsFdo) {
2211 ClassReleaseRemoveLock(DeviceObject, Irp);
2212 ExFreePool(srb);
2213 SendToFdo(DeviceObject, Irp, status);
2214 return status;
2215 }
2216
2217 status = DiskIoctlGetDriveLayout(
2218 DeviceObject,
2219 Irp);
2220 break;
2221 }
2222
2223 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: {
2224
2225 DebugPrint((1, "IOCTL_DISK_GET_DRIVE_LAYOUT_EX to device %p through irp %p\n",
2226 DeviceObject, Irp));
2227 DebugPrint((1, "Device is a%s.\n",
2228 commonExtension->IsFdo ? "n fdo" : " pdo"));
2229
2230 if (!commonExtension->IsFdo) {
2231 ClassReleaseRemoveLock(DeviceObject, Irp);
2232 ExFreePool(srb);
2233 SendToFdo(DeviceObject, Irp, status);
2234 return status;
2235 }
2236
2237 status = DiskIoctlGetDriveLayoutEx(
2238 DeviceObject,
2239 Irp);
2240 break;
2241
2242 }
2243
2244 case IOCTL_DISK_SET_DRIVE_LAYOUT: {
2245
2246 DebugPrint((1, "IOCTL_DISK_SET_DRIVE_LAYOUT to device %p through irp %p\n",
2247 DeviceObject, Irp));
2248 DebugPrint((1, "Device is a%s.\n",
2249 commonExtension->IsFdo ? "n fdo" : " pdo"));
2250
2251 if(!commonExtension->IsFdo) {
2252 ClassReleaseRemoveLock(DeviceObject, Irp);
2253 ExFreePool(srb);
2254 SendToFdo(DeviceObject, Irp, status);
2255 return status;
2256 }
2257
2258 status = DiskIoctlSetDriveLayout(DeviceObject, Irp);
2259
2260 //
2261 // Notify everyone that the disk layout has changed
2262 //
2263 {
2264 TARGET_DEVICE_CUSTOM_NOTIFICATION Notification;
2265
2266 Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
2267 Notification.Version = 1;
2268 Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
2269 Notification.FileObject = NULL;
2270 Notification.NameBufferOffset = -1;
2271
2272 IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
2273 &Notification,
2274 NULL,
2275 NULL);
2276 }
2277
2278 break;
2279 }
2280
2281 case IOCTL_DISK_SET_DRIVE_LAYOUT_EX: {
2282
2283 DebugPrint((1, "IOCTL_DISK_SET_DRIVE_LAYOUT_EX to device %p through irp %p\n",
2284 DeviceObject, Irp));
2285 DebugPrint((1, "Device is a%s.\n",
2286 commonExtension->IsFdo ? "n fdo" : " pdo"));
2287
2288 if (!commonExtension->IsFdo) {
2289 ClassReleaseRemoveLock(DeviceObject, Irp);
2290 ExFreePool(srb);
2291 SendToFdo(DeviceObject, Irp, status);
2292
2293 return status;
2294 }
2295
2296 status = DiskIoctlSetDriveLayoutEx(
2297 DeviceObject,
2298 Irp);
2299
2300 //
2301 // Notify everyone that the disk layout has changed
2302 //
2303 {
2304 TARGET_DEVICE_CUSTOM_NOTIFICATION Notification;
2305
2306 Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
2307 Notification.Version = 1;
2308 Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
2309 Notification.FileObject = NULL;
2310 Notification.NameBufferOffset = -1;
2311
2312 IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
2313 &Notification,
2314 NULL,
2315 NULL);
2316 }
2317
2318 break;
2319 }
2320
2321 case IOCTL_DISK_GET_PARTITION_INFO: {
2322
2323 DebugPrint((1, "IOCTL_DISK_GET_PARTITION_INFO to device %p through irp %p\n",
2324 DeviceObject, Irp));
2325 DebugPrint((1, "Device is a%s.\n",
2326 commonExtension->IsFdo ? "n fdo" : " pdo"));
2327
2328 status = DiskIoctlGetPartitionInfo(
2329 DeviceObject,
2330 Irp);
2331 break;
2332 }
2333
2334 case IOCTL_DISK_GET_PARTITION_INFO_EX: {
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 = DiskIoctlGetPartitionInfoEx(
2342 DeviceObject,
2343 Irp);
2344 break;
2345 }
2346
2347 case IOCTL_DISK_GET_LENGTH_INFO: {
2348 DebugPrint((1, "IOCTL_DISK_GET_LENGTH_INFO to device %p through irp %p\n",
2349 DeviceObject, Irp));
2350 DebugPrint((1, "Device is a%s.\n",
2351 commonExtension->IsFdo ? "n fdo" : " pdo"));
2352
2353 status = DiskIoctlGetLengthInfo(
2354 DeviceObject,
2355 Irp);
2356 break;
2357 }
2358
2359 case IOCTL_DISK_SET_PARTITION_INFO: {
2360
2361 DebugPrint((1, "IOCTL_DISK_SET_PARTITION_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
2367 status = DiskIoctlSetPartitionInfo (
2368 DeviceObject,
2369 Irp);
2370 break;
2371 }
2372
2373
2374 case IOCTL_DISK_SET_PARTITION_INFO_EX: {
2375
2376 DebugPrint((1, "IOCTL_DISK_SET_PARTITION_INFO_EX to device %p through irp %p\n",
2377 DeviceObject, Irp));
2378 DebugPrint((1, "Device is a%s.\n",
2379 commonExtension->IsFdo ? "n fdo" : " pdo"));
2380
2381 status = DiskIoctlSetPartitionInfoEx(
2382 DeviceObject,
2383 Irp);
2384 break;
2385 }
2386
2387 case IOCTL_DISK_DELETE_DRIVE_LAYOUT: {
2388
2389 CREATE_DISK CreateDiskInfo;
2390
2391 //
2392 // Update the disk with new partition information.
2393 //
2394
2395 DebugPrint((1, "IOCTL_DISK_DELETE_DRIVE_LAYOUT to device %p through irp %p\n",
2396 DeviceObject, Irp));
2397 DebugPrint((1, "Device is a%s.\n",
2398 commonExtension->IsFdo ? "n fdo" : " pdo"));
2399
2400 if(!commonExtension->IsFdo) {
2401
2402 ClassReleaseRemoveLock(DeviceObject, Irp);
2403 ExFreePool(srb);
2404 SendToFdo(DeviceObject, Irp, status);
2405 return status;
2406 }
2407
2408 DiskAcquirePartitioningLock(fdoExtension);
2409
2410 DiskInvalidatePartitionTable(fdoExtension, TRUE);
2411
2412 //
2413 // IoCreateDisk called with a partition style of raw
2414 // will remove any partition tables from the disk.
2415 //
2416
2417 RtlZeroMemory (&CreateDiskInfo, sizeof (CreateDiskInfo));
2418 CreateDiskInfo.PartitionStyle = PARTITION_STYLE_RAW;
2419
2420 status = IoCreateDisk(
2421 DeviceObject,
2422 &CreateDiskInfo);
2423
2424
2425 DiskReleasePartitioningLock(fdoExtension);
2426 ClassInvalidateBusRelations(DeviceObject);
2427
2428 Irp->IoStatus.Status = status;
2429
2430 break;
2431 }
2432
2433 case IOCTL_DISK_REASSIGN_BLOCKS: {
2434
2435 //
2436 // Map defective blocks to new location on disk.
2437 //
2438
2439 PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
2440 ULONG bufferSize;
2441 ULONG blockNumber;
2442 ULONG blockCount;
2443
2444 DebugPrint((2, "IOCTL_DISK_REASSIGN_BLOCKS to device %p through irp %p\n",
2445 DeviceObject, Irp));
2446 DebugPrint((2, "Device is a%s.\n",
2447 commonExtension->IsFdo ? "n fdo" : " pdo"));
2448
2449 //
2450 // Validate buffer length.
2451 //
2452
2453 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2454 sizeof(REASSIGN_BLOCKS)) {
2455
2456 status = STATUS_INFO_LENGTH_MISMATCH;
2457 break;
2458 }
2459
2460 //
2461 // Send to FDO
2462 //
2463
2464 if(!commonExtension->IsFdo) {
2465
2466 ClassReleaseRemoveLock(DeviceObject, Irp);
2467 ExFreePool(srb);
2468 SendToFdo(DeviceObject, Irp, status);
2469 return status;
2470 }
2471
2472 bufferSize = sizeof(REASSIGN_BLOCKS) +
2473 ((badBlocks->Count - 1) * sizeof(ULONG));
2474
2475 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2476 bufferSize) {
2477
2478 status = STATUS_INFO_LENGTH_MISMATCH;
2479 break;
2480 }
2481
2482 //
2483 // Build the data buffer to be transferred in the input buffer.
2484 // The format of the data to the device is:
2485 //
2486 // 2 bytes Reserved
2487 // 2 bytes Length
2488 // x * 4 btyes Block Address
2489 //
2490 // All values are big endian.
2491 //
2492
2493 badBlocks->Reserved = 0;
2494 blockCount = badBlocks->Count;
2495
2496 //
2497 // Convert # of entries to # of bytes.
2498 //
2499
2500 blockCount *= 4;
2501 badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
2502 badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
2503
2504 //
2505 // Convert back to number of entries.
2506 //
2507
2508 blockCount /= 4;
2509
2510 for (; blockCount > 0; blockCount--) {
2511
2512 blockNumber = badBlocks->BlockNumber[blockCount-1];
2513
2514 REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
2515 (PFOUR_BYTE) &blockNumber);
2516 }
2517
2518 srb->CdbLength = 6;
2519
2520 cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
2521
2522 //
2523 // Set timeout value.
2524 //
2525
2526 srb->TimeOutValue = fdoExtension->TimeOutValue;
2527
2528 status = ClassSendSrbSynchronous(DeviceObject,
2529 srb,
2530 badBlocks,
2531 bufferSize,
2532 TRUE);
2533
2534 Irp->IoStatus.Status = status;
2535 Irp->IoStatus.Information = 0;
2536 ExFreePool(srb);
2537 ClassReleaseRemoveLock(DeviceObject, Irp);
2538 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
2539
2540 return(status);
2541 }
2542
2543 case IOCTL_DISK_IS_WRITABLE: {
2544
2545 //
2546 // This routine mimics IOCTL_STORAGE_GET_MEDIA_TYPES_EX
2547 //
2548
2549 ULONG modeLength;
2550 ULONG retries = 4;
2551
2552 DebugPrint((3, "Disk.DiskDeviceControl: IOCTL_DISK_IS_WRITABLE\n"));
2553
2554 if (!commonExtension->IsFdo)
2555 {
2556 ClassReleaseRemoveLock(DeviceObject, Irp);
2557 ExFreePool(srb);
2558 SendToFdo(DeviceObject, Irp, status);
2559 return status;
2560 }
2561
2562 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2563
2564 //
2565 // Allocate memory for a mode header and then some
2566 // for port drivers that need to convert to MODE10
2567 // or always return the MODE_PARAMETER_BLOCK (even
2568 // when memory was not allocated for this purpose)
2569 //
2570
2571 modeLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
2572 modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2573 modeLength,
2574 DISK_TAG_MODE_DATA);
2575
2576 if (modeData == NULL)
2577 {
2578 status = STATUS_INSUFFICIENT_RESOURCES;
2579 break;
2580 }
2581
2582 RtlZeroMemory(modeData, modeLength);
2583
2584 //
2585 // Build the MODE SENSE CDB
2586 //
2587
2588 srb->CdbLength = 6;
2589 cdb = (PCDB)srb->Cdb;
2590
2591 //
2592 // Set the timeout value from the device extension
2593 //
2594
2595 srb->TimeOutValue = fdoExtension->TimeOutValue;
2596
2597 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2598 cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL;
2599 cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
2600
2601 while (retries != 0)
2602 {
2603 status = ClassSendSrbSynchronous(DeviceObject,
2604 srb,
2605 modeData,
2606 modeLength,
2607 FALSE);
2608
2609 if (status != STATUS_VERIFY_REQUIRED)
2610 {
2611 if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)
2612 {
2613 status = STATUS_SUCCESS;
2614 }
2615
2616 break;
2617 }
2618
2619 retries--;
2620 }
2621
2622 if (NT_SUCCESS(status))
2623 {
2624 if (TEST_FLAG(modeData->DeviceSpecificParameter, MODE_DSP_WRITE_PROTECT))
2625 {
2626 status = STATUS_MEDIA_WRITE_PROTECTED;
2627 }
2628 }
2629
2630 ExFreePool(modeData);
2631 break;
2632 }
2633
2634 case IOCTL_DISK_INTERNAL_SET_VERIFY: {
2635
2636 //
2637 // If the caller is kernel mode, set the verify bit.
2638 //
2639
2640 if (Irp->RequestorMode == KernelMode) {
2641
2642 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
2643
2644 if(commonExtension->IsFdo) {
2645
2646 Irp->IoStatus.Information = 0;
2647 }
2648 }
2649
2650 DiskInvalidatePartitionTable(fdoExtension, FALSE);
2651
2652 status = STATUS_SUCCESS;
2653 break;
2654 }
2655
2656 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: {
2657
2658 //
2659 // If the caller is kernel mode, clear the verify bit.
2660 //
2661
2662 if (Irp->RequestorMode == KernelMode) {
2663 CLEAR_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
2664 }
2665 status = STATUS_SUCCESS;
2666 break;
2667 }
2668
2669 case IOCTL_DISK_UPDATE_DRIVE_SIZE: {
2670
2671 DebugPrint((2, "IOCTL_DISK_UPDATE_DRIVE_SIZE to device %p "
2672 "through irp %p\n",
2673 DeviceObject, Irp));
2674
2675 DebugPrint((2, "Device is a%s.\n",
2676 commonExtension->IsFdo ? "n fdo" : " pdo"));
2677
2678 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
2679 sizeof(DISK_GEOMETRY)) {
2680
2681 status = STATUS_BUFFER_TOO_SMALL;
2682 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
2683 break;
2684 }
2685
2686 if(!commonExtension->IsFdo) {
2687
2688 //
2689 // Pdo should issue this request to the lower device object.
2690 //
2691
2692 ClassReleaseRemoveLock(DeviceObject, Irp);
2693 ExFreePool(srb);
2694 SendToFdo(DeviceObject, Irp, status);
2695 return status;
2696 }
2697
2698 DiskAcquirePartitioningLock(fdoExtension);
2699
2700 //
2701 // Invalidate the cached partition table.
2702 //
2703
2704 DiskInvalidatePartitionTable(fdoExtension, TRUE);
2705
2706 //
2707 // At this point, commonExtension *is* the FDO extension. This
2708 // should be the same as PartitionZeroExtension.
2709 //
2710
2711 ASSERT(commonExtension ==
2712 &(commonExtension->PartitionZeroExtension->CommonExtension));
2713
2714 //
2715 // Issue ReadCapacity to update device extension with information
2716 // for current media.
2717 //
2718
2719 status = DiskReadDriveCapacity(DeviceObject);
2720
2721 //
2722 // Note whether the drive is ready.
2723 //
2724
2725 diskData->ReadyStatus = status;
2726
2727 //
2728 // The disk's partition tables may be invalid after the drive geometry
2729 // has been updated. The call to IoValidatePartitionTable (below) will
2730 // fix it if this is the case.
2731 //
2732
2733 if (NT_SUCCESS(status)) {
2734
2735 status = DiskVerifyPartitionTable (fdoExtension, TRUE);
2736 }
2737
2738
2739 if (NT_SUCCESS(status)) {
2740
2741 //
2742 // Copy drive geometry information from the device extension.
2743 //
2744
2745 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
2746 &(fdoExtension->DiskGeometry),
2747 sizeof(DISK_GEOMETRY));
2748
2749 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
2750 status = STATUS_SUCCESS;
2751
2752 }
2753
2754 DiskReleasePartitioningLock(fdoExtension);
2755
2756 break;
2757 }
2758
2759 case IOCTL_DISK_GROW_PARTITION: {
2760
2761 PDISK_GROW_PARTITION inputBuffer;
2762
2763 // PDEVICE_OBJECT pdo;
2764 PCOMMON_DEVICE_EXTENSION pdoExtension;
2765
2766 LARGE_INTEGER bytesPerCylinder;
2767 LARGE_INTEGER newStoppingOffset;
2768 LARGE_INTEGER newPartitionLength;
2769
2770 PPHYSICAL_DEVICE_EXTENSION sibling;
2771
2772 PDRIVE_LAYOUT_INFORMATION_EX layoutInfo;
2773 PPARTITION_INFORMATION_EX pdoPartition;
2774 PPARTITION_INFORMATION_EX containerPartition;
2775 ULONG partitionIndex;
2776
2777 DebugPrint((2, "IOCTL_DISK_GROW_PARTITION to device %p through "
2778 "irp %p\n",
2779 DeviceObject, Irp));
2780
2781 DebugPrint((2, "Device is a%s.\n",
2782 commonExtension->IsFdo ? "n fdo" : " pdo"));
2783
2784 Irp->IoStatus.Information = 0;
2785
2786 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
2787 sizeof(DISK_GROW_PARTITION)) {
2788
2789 status = STATUS_INFO_LENGTH_MISMATCH;
2790 Irp->IoStatus.Information = sizeof(DISK_GROW_PARTITION);
2791 break;
2792 }
2793
2794 if(!commonExtension->IsFdo) {
2795
2796 //
2797 // Pdo should issue this request to the lower device object
2798 //
2799
2800 ClassReleaseRemoveLock(DeviceObject, Irp);
2801 ExFreePool(srb);
2802 SendToFdo(DeviceObject, Irp, status);
2803 return status;
2804 }
2805
2806 DiskAcquirePartitioningLock(fdoExtension);
2807 ClassAcquireChildLock(fdoExtension);
2808
2809 //
2810 // At this point, commonExtension *is* the FDO extension. This should
2811 // be the same as PartitionZeroExtension.
2812 //
2813
2814 ASSERT(commonExtension ==
2815 &(commonExtension->PartitionZeroExtension->CommonExtension));
2816
2817 //
2818 // Get the input parameters
2819 //
2820
2821 inputBuffer = (PDISK_GROW_PARTITION) Irp->AssociatedIrp.SystemBuffer;
2822
2823 ASSERT(inputBuffer);
2824
2825 //
2826 // Make sure that we are actually being asked to grow the partition.
2827 //
2828
2829 if(inputBuffer->BytesToGrow.QuadPart == 0) {
2830
2831 status = STATUS_INVALID_PARAMETER;
2832 ClassReleaseChildLock(fdoExtension);
2833 DiskReleasePartitioningLock(fdoExtension);
2834 break;
2835 }
2836
2837 //
2838 // Find the partition that matches the supplied number
2839 //
2840
2841 pdoExtension = &commonExtension->ChildList->CommonExtension;
2842
2843 while(pdoExtension != NULL) {
2844
2845 //
2846 // Is this the partition we are searching for?
2847 //
2848
2849 if(inputBuffer->PartitionNumber == pdoExtension->PartitionNumber) {
2850 break;
2851 }
2852
2853 pdoExtension = &pdoExtension->ChildList->CommonExtension;
2854 }
2855
2856 // Did we find the partition?
2857
2858 if(pdoExtension == NULL) {
2859 status = STATUS_INVALID_PARAMETER;
2860 ClassReleaseChildLock(fdoExtension);
2861 DiskReleasePartitioningLock(fdoExtension);
2862 break;
2863 }
2864
2865 ASSERT(pdoExtension);
2866
2867 //
2868 // Compute the new values for the partition to grow.
2869 //
2870
2871 newPartitionLength.QuadPart =
2872 (pdoExtension->PartitionLength.QuadPart +
2873 inputBuffer->BytesToGrow.QuadPart);
2874
2875 newStoppingOffset.QuadPart =
2876 (pdoExtension->StartingOffset.QuadPart +
2877 newPartitionLength.QuadPart - 1);
2878
2879 //
2880 // Test the partition alignment before getting to involved.
2881 //
2882 // NOTE:
2883 // All partition stopping offsets should be one byte less
2884 // than a cylinder boundary offset. Also, all first partitions
2885 // (within partition0 and within an extended partition) start
2886 // on the second track while all other partitions start on a
2887 // cylinder boundary.
2888 //
2889 bytesPerCylinder.QuadPart =
2890 ((LONGLONG) fdoExtension->DiskGeometry.TracksPerCylinder *
2891 (LONGLONG) fdoExtension->DiskGeometry.SectorsPerTrack *
2892 (LONGLONG) fdoExtension->DiskGeometry.BytesPerSector);
2893
2894 // Temporarily adjust up to cylinder boundary.
2895
2896 newStoppingOffset.QuadPart += 1;
2897
2898 if(newStoppingOffset.QuadPart % bytesPerCylinder.QuadPart) {
2899
2900 // Adjust the length first...
2901 newPartitionLength.QuadPart -=
2902 (newStoppingOffset.QuadPart % bytesPerCylinder.QuadPart);
2903
2904 // ...and then the stopping offset.
2905 newStoppingOffset.QuadPart -=
2906 (newStoppingOffset.QuadPart % bytesPerCylinder.QuadPart);
2907
2908 DebugPrint((2, "IOCTL_DISK_GROW_PARTITION: "
2909 "Adjusted the requested partition size to cylinder boundary"));
2910 }
2911
2912 // Restore to one byte less than a cylinder boundary.
2913 newStoppingOffset.QuadPart -= 1;
2914
2915 //
2916 // Will the new partition fit within Partition0?
2917 // Remember: commonExtension == &PartitionZeroExtension->CommonExtension
2918 //
2919
2920 if(newStoppingOffset.QuadPart >
2921 (commonExtension->StartingOffset.QuadPart +
2922 commonExtension->PartitionLength.QuadPart - 1)) {
2923
2924 //
2925 // The new partition falls outside Partition0
2926 //
2927
2928 status = STATUS_UNSUCCESSFUL;
2929 ClassReleaseChildLock(fdoExtension);
2930 DiskReleasePartitioningLock(fdoExtension);
2931 break;
2932 }
2933
2934 //
2935 // Search for any partition that will conflict with the new partition.
2936 // This is done before testing for any containing partitions to
2937 // simplify the container handling.
2938 //
2939
2940 sibling = commonExtension->ChildList;
2941
2942 while(sibling != NULL) {
2943 LARGE_INTEGER sibStoppingOffset;
2944 PCOMMON_DEVICE_EXTENSION siblingExtension;
2945
2946 siblingExtension = &(sibling->CommonExtension);
2947
2948 ASSERT( siblingExtension );
2949
2950 sibStoppingOffset.QuadPart =
2951 (siblingExtension->StartingOffset.QuadPart +
2952 siblingExtension->PartitionLength.QuadPart - 1);
2953
2954 //
2955 // Only check the siblings that start beyond the new partition
2956 // starting offset. Also, assume that since the starting offset
2957 // has not changed, it will not be in conflict with any other
2958 // partitions; only the new stopping offset needs to be tested.
2959 //
2960
2961 if((inputBuffer->PartitionNumber !=
2962 siblingExtension->PartitionNumber) &&
2963
2964 (siblingExtension->StartingOffset.QuadPart >
2965 pdoExtension->StartingOffset.QuadPart) &&
2966
2967 (newStoppingOffset.QuadPart >=
2968 siblingExtension->StartingOffset.QuadPart)) {
2969
2970 //
2971 // We have a conflict; bail out leaving pdoSibling set.
2972 //
2973
2974 break;
2975 }
2976 sibling = siblingExtension->ChildList;
2977 }
2978
2979
2980 //
2981 // If there is a sibling that conflicts, it will be in pdoSibling; there
2982 // could be more than one, but this is the first one detected.
2983 //
2984
2985 if(sibling != NULL) {
2986 //
2987 // Report the conflict and abort the grow request.
2988 //
2989
2990 status = STATUS_UNSUCCESSFUL;
2991 ClassReleaseChildLock(fdoExtension);
2992 DiskReleasePartitioningLock(fdoExtension);
2993 break;
2994 }
2995
2996 //
2997 // Read the partition table. Since we're planning on modifying it
2998 // we should bypass the cache.
2999 //
3000
3001 status = DiskReadPartitionTableEx(fdoExtension, TRUE, &layoutInfo );
3002
3003 if( !NT_SUCCESS(status) ) {
3004 ClassReleaseChildLock(fdoExtension);
3005 DiskReleasePartitioningLock(fdoExtension);
3006 break;
3007 }
3008
3009 ASSERT( layoutInfo );
3010
3011 //
3012 // Search the layout for the partition that matches the
3013 // PDO in hand.
3014 //
3015
3016 pdoPartition =
3017 DiskPdoFindPartitionEntry(
3018 (PPHYSICAL_DEVICE_EXTENSION) pdoExtension,
3019 layoutInfo);
3020
3021 if(pdoPartition == NULL) {
3022 // Looks like something is wrong interally-- error ok?
3023 status = STATUS_DRIVER_INTERNAL_ERROR;
3024 layoutInfo = NULL;
3025 ClassReleaseChildLock(fdoExtension);
3026 DiskReleasePartitioningLock(fdoExtension);
3027 break;
3028 }
3029
3030 //
3031 // Search the on-disk partition information to find the root containing
3032 // partition (top-to-bottom).
3033 //
3034 // Remember: commonExtension == &PartitionZeroExtension->CommonExtension
3035 //
3036
3037 //
3038 // All affected containers will have a new stopping offset
3039 // that is equal to the new partition (logical drive)
3040 // stopping offset. Walk the layout information from
3041 // bottom-to-top searching for logical drive containers and
3042 // propagating the change.
3043 //
3044
3045 containerPartition =
3046 DiskFindContainingPartition(
3047 layoutInfo,
3048 pdoPartition,
3049 FALSE);
3050
3051 //
3052 // This loop should only execute at most 2 times; once for
3053 // the logical drive container, and once for the root
3054 // extended partition container. If the growing partition
3055 // is not contained, the loop does not run.
3056 //
3057
3058 while(containerPartition != NULL) {
3059 LARGE_INTEGER containerStoppingOffset;
3060 PPARTITION_INFORMATION_EX nextContainerPartition;
3061
3062 //
3063 // Plan ahead and get the container's container before
3064 // modifing the current size.
3065 //
3066
3067 nextContainerPartition =
3068 DiskFindContainingPartition(
3069 layoutInfo,
3070 containerPartition,
3071 FALSE);
3072
3073 //
3074 // Figure out where the current container ends and test
3075 // to see if it already encompasses the containee.
3076 //
3077
3078 containerStoppingOffset.QuadPart =
3079 (containerPartition->StartingOffset.QuadPart +
3080 containerPartition->PartitionLength.QuadPart - 1);
3081
3082 if(newStoppingOffset.QuadPart <=
3083 containerStoppingOffset.QuadPart) {
3084
3085 //
3086 // No need to continue since this container fits
3087 //
3088 break;
3089 }
3090
3091 //
3092 // Adjust the container to have a stopping offset that
3093 // matches the grown partition stopping offset.
3094 //
3095
3096 containerPartition->PartitionLength.QuadPart =
3097 newStoppingOffset.QuadPart + 1 -
3098 containerPartition->StartingOffset.QuadPart;
3099
3100 containerPartition->RewritePartition = TRUE;
3101
3102 // Continue with the next container
3103 containerPartition = nextContainerPartition;
3104 }
3105
3106 //
3107 // Wait until after searching the containers to update the
3108 // partition size.
3109 //
3110
3111 pdoPartition->PartitionLength.QuadPart =
3112 newPartitionLength.QuadPart;
3113
3114 pdoPartition->RewritePartition = TRUE;
3115
3116 //
3117 // Commit the changes to disk
3118 //
3119
3120 status = DiskWritePartitionTableEx(fdoExtension, layoutInfo );
3121
3122 if( NT_SUCCESS(status) ) {
3123
3124 //
3125 // Everything looks good so commit the new length to the
3126 // PDO. This has to be done carefully. We may potentially
3127 // grow the partition in three steps:
3128 // * increase the high-word of the partition length
3129 // to be just below the new size - the high word should
3130 // be greater than or equal to the current length.
3131 //
3132 // * change the low-word of the partition length to the
3133 // new value - this value may potentially be lower than
3134 // the current value (if the high part was changed which
3135 // is why we changed that first)
3136 //
3137 // * change the high part to the correct value.
3138 //
3139
3140 if(newPartitionLength.HighPart >
3141 pdoExtension->PartitionLength.HighPart) {
3142
3143 //
3144 // Swap in one less than the high word.
3145 //
3146
3147 InterlockedExchange(
3148 &(pdoExtension->PartitionLength.HighPart),
3149 (newPartitionLength.HighPart - 1));
3150 }
3151
3152 //
3153 // Swap in the low part.
3154 //
3155
3156 InterlockedExchange(
3157 &(pdoExtension->PartitionLength.LowPart),
3158 newPartitionLength.LowPart);
3159
3160 if(newPartitionLength.HighPart !=
3161 pdoExtension->PartitionLength.HighPart) {
3162
3163 //
3164 // Swap in one less than the high word.
3165 //
3166
3167 InterlockedExchange(
3168 &(pdoExtension->PartitionLength.HighPart),
3169 newPartitionLength.HighPart);
3170 }
3171 }
3172
3173 //
3174 // Invalidate and free the cached partition table.
3175 //
3176
3177 DiskInvalidatePartitionTable(fdoExtension, TRUE);
3178
3179 //
3180 // Free the partition buffer regardless of the status
3181 //
3182
3183 ClassReleaseChildLock(fdoExtension);
3184 DiskReleasePartitioningLock(fdoExtension);
3185
3186 break;
3187 }
3188
3189
3190 case IOCTL_DISK_UPDATE_PROPERTIES: {
3191
3192 //
3193 // Invalidate the partition table and re-enumerate the device.
3194 //
3195
3196 if(DiskInvalidatePartitionTable(fdoExtension, FALSE)) {
3197 IoInvalidateDeviceRelations(fdoExtension->LowerPdo, BusRelations);
3198 }
3199 status = STATUS_SUCCESS;
3200
3201 break;
3202 }
3203
3204 case IOCTL_DISK_MEDIA_REMOVAL: {
3205
3206 //
3207 // If the disk is not removable then don't allow this command.
3208 //
3209
3210 DebugPrint((2, "IOCTL_DISK_MEDIA_REMOVAL to device %p through irp %p\n",
3211 DeviceObject, Irp));
3212 DebugPrint((2, "Device is a%s.\n",
3213 commonExtension->IsFdo ? "n fdo" : " pdo"));
3214
3215 if(!commonExtension->IsFdo) {
3216 ClassReleaseRemoveLock(DeviceObject, Irp);
3217 ExFreePool(srb);
3218 SendToFdo(DeviceObject,Irp,status);
3219 return status;
3220 }
3221
3222 if (!TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
3223 status = STATUS_INVALID_DEVICE_REQUEST;
3224 break;
3225 }
3226
3227 //
3228 // Fall through and let the class driver process the request.
3229 //
3230 goto defaultHandler;
3231
3232 }
3233
3234
3235
3236 defaultHandler:
3237 default: {
3238
3239 //
3240 // Free the Srb, since it is not needed.
3241 //
3242
3243 ExFreePool(srb);
3244
3245 //
3246 // Pass the request to the common device control routine.
3247 //
3248
3249 return(ClassDeviceControl(DeviceObject, Irp));
3250
3251 break;
3252 }
3253
3254 } // end switch
3255
3256 Irp->IoStatus.Status = status;
3257
3258 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
3259
3260 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
3261 }
3262
3263 ClassReleaseRemoveLock(DeviceObject, Irp);
3264 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
3265 ExFreePool(srb);
3266 return(status);
3267
3268 } // end DiskDeviceControl()
3269
3270 \f
3271 NTSTATUS
3272 DiskShutdownFlush (
3273 IN PDEVICE_OBJECT DeviceObject,
3274 IN PIRP Irp
3275 )
3276
3277 /*++
3278
3279 Routine Description:
3280
3281 This routine is called for a shutdown and flush IRPs. These are sent by the
3282 system before it actually shuts down or when the file system does a flush.
3283 A synchronize cache command is sent to the device if it is write caching.
3284 If the device is removable an unlock command will be sent. This routine
3285 will sent a shutdown or flush Srb to the port driver.
3286
3287 Arguments:
3288
3289 DriverObject - Pointer to device object to being shutdown by system.
3290
3291 Irp - IRP involved.
3292
3293 Return Value:
3294
3295 NT Status
3296
3297 --*/
3298
3299 {
3300 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3301 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension;
3302
3303 PIO_STACK_LOCATION irpStack;
3304 PSCSI_REQUEST_BLOCK srb;
3305 NTSTATUS status;
3306 PCDB cdb;
3307
3308 //
3309 // Send partition flush requests to the FDO
3310 //
3311
3312 if(!commonExtension->IsFdo) {
3313
3314 PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject;
3315
3316 ClassReleaseRemoveLock(DeviceObject, Irp);
3317 IoMarkIrpPending(Irp);
3318 IoCopyCurrentIrpStackLocationToNext(Irp);
3319 IoCallDriver(lowerDevice, Irp);
3320 return STATUS_PENDING;
3321 }
3322
3323 //
3324 // Allocate SCSI request block.
3325 //
3326
3327 srb = ExAllocatePoolWithTag(NonPagedPool,
3328 sizeof(SCSI_REQUEST_BLOCK),
3329 DISK_TAG_SRB);
3330
3331 if (srb == NULL) {
3332
3333 //
3334 // Set the status and complete the request.
3335 //
3336
3337 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3338 ClassReleaseRemoveLock(DeviceObject, Irp);
3339 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
3340 return(STATUS_INSUFFICIENT_RESOURCES);
3341 }
3342
3343 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);