ReactOS  0.4.13-dev-563-g0561610
disk.c
Go to the documentation of this file.
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 
33 NTAPI
35  IN PDEVICE_OBJECT Fdo,
36  IN PIRP Irp,
37  IN UCHAR MediumType,
38  IN UCHAR DensityCode,
41  );
42 
44 NTAPI
48  );
49 
51 NTAPI
54  IN PPARTITION_INFORMATION_EX BasePartition
55  );
56 
58 NTAPI
61  IN PPARTITION_INFORMATION_EX BasePartition,
62  IN BOOLEAN SearchTopToBottom
63  );
64 
66 NTAPI
69  IN PIRP Irp
70  );
71 
73 NTAPI
76  IN PIRP Irp
77  );
78 
80 NTAPI
83  IN PIRP Irp
84  );
85 
87 NTAPI
90  IN PIRP Irp
91  );
92 
94 NTAPI
97  IN PIRP Irp
98  );
99 
100 NTSTATUS
101 NTAPI
104  IN PIRP Irp
105  );
106 
107 NTSTATUS
108 NTAPI
111  IN PIRP Irp
112  );
113 
114 NTSTATUS
115 NTAPI
118  IN PIRP Irp
119  );
120 
121 NTSTATUS
122 NTAPI
125  IN PIRP Irp
126  );
127 
128 NTSTATUS
129 NTAPI
132  IN PIRP Irp
133  );
134 
135 NTSTATUS
136 NTAPI
139  IN PIRP Irp
140  );
141 
142 NTSTATUS
143 NTAPI
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
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 {
216  CLASS_QUERY_WMI_REGINFO_EX_LIST classQueryWmiRegInfoExList;
217  GUID guidQueryRegInfoEx = GUID_CLASSPNP_QUERY_REGINFOEX;
218 
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 
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 
328 
329  //
330  // Call the class init routine
331  //
332 
334 
335 #if defined(_X86_)
336  if(NT_SUCCESS(status)) {
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 
352  &guidQueryRegInfoEx,
353  &classQueryWmiRegInfoExList);
354 
355  return status;
356 
357 } // end DriverEntry()
358 
359 VOID
360 NTAPI
363  )
364 {
365  PAGED_CODE();
366 
367 #if defined(_X86_)
368  DiskCleanupDetectInfo(DriverObject);
369 #endif
370  return;
371 }
372 
373 NTSTATUS
374 NTAPI
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 
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,
448  NULL,
449  NULL);
450 
453  &objectAttributes);
454 
455  (*DeviceCount)++;
456 
457  } while((status == STATUS_OBJECT_NAME_COLLISION) ||
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 
479 
480  status = ClassClaimDevice(lowerDevice, FALSE);
481 
482  if (!NT_SUCCESS(status)) {
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 
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 
512  deviceName,
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 =
577  deviceObject,
579 
580  if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
581 
582  //
583  // Uh - oh, we couldn't attach
584  // cleanup and return
585  //
586 
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 
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)) {
637  ZwClose(handle);
638  }
639 
640  ObDereferenceObject(lowerDevice);
641 
642  return(status);
643 }
644 
645 NTSTATUS
646 NTAPI
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 {
671 
673  ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
674  LARGE_INTEGER startingOffset;
675 
676  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
677  commonExtension->PartitionZeroExtension;
678 
679  ULONG residualBytes;
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 
716 
717  //
718  // status will keep the current error
719  //
720 
722 
723  } else if ((commonExtension->IsFdo != FALSE) && (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 
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 
741 
742  }
743 
744  } else {
745 
746  //
747  // the drive is ready, so ok the read/write
748  //
749 
751 
752  }
753 
754  Irp->IoStatus.Status = status;
755  return status;
756 
757 } // end DiskReadWrite()
758 
759 NTSTATUS
760 NTAPI
762  IN PDEVICE_OBJECT Fdo,
763  IN PIRP Irp,
764  IN UCHAR MediumType,
765  IN UCHAR DensityCode,
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;
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,
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;
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
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 {
1057  //PPHYSICAL_DEVICE_EXTENSION pdoExtension = DeviceObject->DeviceExtension;
1059 
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 
1075  DISK_TAG_SRB);
1076  Irp->IoStatus.Information = 0;
1077 
1078  if (srb == NULL) {
1079 
1080  Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1084  }
1085 
1086  //
1087  // Write zeros to Srb.
1088  //
1089 
1091 
1092  cdb = (PCDB)srb->Cdb;
1093 
1094  switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
1095 
1097  b = TRUE;
1099 
1100  BOOLEAN getCaching = b;
1101  PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer;
1102 
1103  if(!commonExtension->IsFdo) {
1104 
1106  ExFreePool(srb);
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  ) {
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 
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,
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  //
1156  break;
1157  }
1158  }
1159  else
1160  {
1161  if (TEST_FLAG(fdoExtension->ScanForSpecialFlags,
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  //
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,
1185  }
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,
1199  &specialFlags);
1200 
1202 
1203  SET_FLAG(fdoExtension->ScanForSpecialFlags,
1205 
1206  ClassSetDeviceParameter(fdoExtension,
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 
1225  ExFreePool(srb);
1227  return status;
1228  }
1229 
1230  //
1231  // Validate the request.
1232  //
1233 
1234  if(irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_WRITE_CACHE_STATE)) {
1235 
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 
1248  {
1249  *writeCacheState = DiskWriteCacheDisableNotSupported;
1250  }
1251 
1252  //
1253  // Determine whether it is safe to toggle the write cache
1254  //
1255 
1257  {
1258  *writeCacheState = DiskWriteCacheForceDisable;
1259  }
1260 
1261  Irp->IoStatus.Information = sizeof(DISK_WRITE_CACHE_STATE);
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) {
1275  ExFreePool(srb);
1277  return status;
1278  }
1279 
1280  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1281  sizeof(GETVERSIONINPARAMS)) {
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 
1293 
1294  srbControl = ExAllocatePoolWithTag(NonPagedPool,
1295  sizeof(SRB_IO_CONTROL) +
1296  sizeof(GETVERSIONINPARAMS),
1297  DISK_TAG_SMART);
1298 
1299  if (!srbControl) {
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);
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 
1337  Irp->AssociatedIrp.SystemBuffer,
1338  sizeof(GETVERSIONINPARAMS));
1339 
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) {
1380  ExFreePool(srb);
1382  return status;
1383  }
1384 
1385  if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1386  (sizeof(SENDCMDINPARAMS) - 1)) {
1388  Irp->IoStatus.Information = 0;
1389  break;
1390 
1391  } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1392  (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
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 
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 
1413  controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
1414 
1415  } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
1416  switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
1417  case READ_ATTRIBUTES:
1420  break;
1421  case READ_THRESHOLDS:
1424  break;
1425  default:
1427  break;
1428  }
1429  } else {
1430 
1432  }
1433 
1434  if (controlCode == 0) {
1436  break;
1437  }
1438 
1439  srbControl = ExAllocatePoolWithTag(NonPagedPool,
1440  sizeof(SRB_IO_CONTROL) + length,
1441  DISK_TAG_SMART);
1442 
1443  if (!srbControl) {
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 
1476  Irp->AssociatedIrp.SystemBuffer,
1477  sizeof(SENDCMDINPARAMS) - 1);
1478 
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) {
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) {
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) {
1541  ExFreePool(srb);
1543  return status;
1544  }
1545 
1546  if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1547  (sizeof(SENDCMDINPARAMS) - 1)) {
1549  Irp->IoStatus.Information = 0;
1550  break;
1551 
1552  } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1553  (sizeof(SENDCMDOUTPARAMS) - 1)) {
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 
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 
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 
1601  break;
1602 
1603  case SAVE_ATTRIBUTE_VALUES:
1605  break;
1606 
1607  case EXECUTE_OFFLINE_DIAGS:
1608  //
1609  // Validate that this is an ok self test command
1610  //
1612  {
1614  }
1615  break;
1616 
1619  break;
1620 
1621  default:
1623  break;
1624  }
1625  } else {
1626 
1628  }
1629 
1630  if (controlCode == 0) {
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) {
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 
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) {
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) {
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 
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)) {
1743  Irp->IoStatus.Information = sizeof(GET_MEDIA_TYPES);
1744  break;
1745  }
1746 
1747  if(!commonExtension->IsFdo) {
1749  ExFreePool(srb);
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 
1769  srb,
1770  NULL,
1771  0,
1772  FALSE);
1773 
1774 
1775  if (NT_SUCCESS(status)) {
1776  mediaPresent = TRUE;
1777  }
1778 
1780 
1781  //
1782  // Allocate memory for mode header and block descriptor.
1783  //
1784 
1785  modeLength = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
1787  modeLength,
1789 
1790  if (modeData == NULL) {
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:
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) {
1838  }
1839 
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,
1869  writable = FALSE;
1870  } else {
1871  writable = TRUE;
1872  }
1873 
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 
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 
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 
1917  ExFreePool(srb);
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 
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 
1955  Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1956  // DiskReleasePartitioningLock(fdoExtension);
1957  break;
1958  }
1959 
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 
1974  ExFreePool (srb);
1976  return status;
1977 
1978  } else {
1979 
1981  }
1982 
1983  break;
1984  }
1985 
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 
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 
2013  ExFreePool(srb);
2015  return status;
2016  }
2017 
2018  //
2019  // See if the disk is predicting failure
2020  //
2021 
2023  ULONG readBufferSize;
2024  PUCHAR readBuffer;
2025  PIRP readIrp;
2026  IO_STATUS_BLOCK ioStatus;
2027  PDEVICE_OBJECT topOfStack;
2028 
2029  checkFailure->PredictFailure = 0;
2030 
2032 
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) {
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) {
2067  status = ioStatus.Status;
2068  }
2069  }
2070 
2071  ExFreePool(readBuffer);
2072  }
2073  ObDereferenceObject(topOfStack);
2074  }
2075 
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 {
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 
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 
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  {
2153  break;
2154  }
2155  else
2156  {
2157  ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart;
2158 
2159  if ((ULONGLONG)verifyInfo->Length > bytesRemaining)
2160  {
2162  break;
2163  }
2164  }
2165 
2166  {
2168 
2172 
2173  if (Context)
2174  {
2175  Context->Irp = Irp;
2176  Context->Srb = srb;
2178 
2179  if (Context->WorkItem)
2180  {
2182 
2183  IoQueueWorkItem(Context->WorkItem,
2186  Context);
2187 
2188  return STATUS_PENDING;
2189  }
2190 
2192  }
2193 
2195  }
2196 
2197  break;
2198  }
2199 
2200  case IOCTL_DISK_CREATE_DISK: {
2201 
2202  if (!commonExtension->IsFdo) {
2204  ExFreePool(srb);
2206  return status;
2207  }
2208 
2210  DeviceObject,
2211  Irp
2212  );
2213  break;
2214  }
2215 
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) {
2225  ExFreePool(srb);
2227  return status;
2228  }
2229 
2231  DeviceObject,
2232  Irp);
2233  break;
2234  }
2235 
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) {
2245  ExFreePool(srb);
2247  return status;
2248  }
2249 
2251  DeviceObject,
2252  Irp);
2253  break;
2254 
2255  }
2256 
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) {
2266  ExFreePool(srb);
2268  return status;
2269  }
2270 
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 
2286  &Notification,
2287  NULL,
2288  NULL);
2289  }
2290 
2291  break;
2292  }
2293 
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) {
2303  ExFreePool(srb);
2305 
2306  return status;
2307  }
2308 
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 
2326  &Notification,
2327  NULL,
2328  NULL);
2329  }
2330 
2331  break;
2332  }
2333 
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 
2342  DeviceObject,
2343  Irp);
2344  break;
2345  }
2346 
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 
2355  DeviceObject,
2356  Irp);
2357  break;
2358  }
2359 
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 
2367  DeviceObject,
2368  Irp);
2369  break;
2370  }
2371 
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 
2381  DeviceObject,
2382  Irp);
2383  break;
2384  }
2385 
2386 
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 
2395  DeviceObject,
2396  Irp);
2397  break;
2398  }
2399 
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 
2416  ExFreePool(srb);
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);
2440 
2441  Irp->IoStatus.Status = status;
2442 
2443  break;
2444  }
2445 
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 
2470  break;
2471  }
2472 
2473  //
2474  // Send to FDO
2475  //
2476 
2477  if(!commonExtension->IsFdo) {
2478 
2480  ExFreePool(srb);
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 
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 
2542  srb,
2543  badBlocks,
2544  bufferSize,
2545  TRUE);
2546 
2547  Irp->IoStatus.Status = status;
2548  Irp->IoStatus.Information = 0;
2549  ExFreePool(srb);
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  {
2570  ExFreePool(srb);
2572  return status;
2573  }
2574 
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);
2586  modeLength,
2588 
2589  if (modeData == NULL)
2590  {
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  {
2617  srb,
2618  modeData,
2619  modeLength,
2620  FALSE);
2621 
2623  {
2625  {
2627  }
2628 
2629  break;
2630  }
2631 
2632  retries--;
2633  }
2634 
2635  if (NT_SUCCESS(status))
2636  {
2638  {
2640  }
2641  }
2642 
2643  ExFreePool(modeData);
2644  break;
2645  }
2646 
2648 
2649  //
2650  // If the caller is kernel mode, set the verify bit.
2651  //
2652 
2653  if (Irp->RequestorMode == KernelMode) {
2654 
2656 
2657  if(commonExtension->IsFdo) {
2658 
2659  Irp->IoStatus.Information = 0;
2660  }
2661  }
2662 
2663  DiskInvalidatePartitionTable(fdoExtension, FALSE);
2664 
2666  break;
2667  }
2668 
2670 
2671  //
2672  // If the caller is kernel mode, clear the verify bit.
2673  //
2674 
2675  if (Irp->RequestorMode == KernelMode) {
2677  }
2679  break;
2680  }
2681 
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 
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 
2706  ExFreePool(srb);
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 
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);
2764 
2765  }
2766 
2767  DiskReleasePartitioningLock(fdoExtension);
2768 
2769  break;
2770  }
2771 
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 
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 
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 
2814  ExFreePool(srb);
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 
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) {
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 
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 
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 =
3031  (PPHYSICAL_DEVICE_EXTENSION) pdoExtension,
3032  layoutInfo);
3033 
3034  if(pdoPartition == NULL) {
3035  // Looks like something is wrong interally-- error ok?
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 =
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 =
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 
3161  &(pdoExtension->PartitionLength.HighPart),
3162  (newPartitionLength.HighPart - 1));
3163  }
3164 
3165  //
3166  // Swap in the low part.
3167  //
3168 
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 
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 
3204 
3205  //
3206  // Invalidate the partition table and re-enumerate the device.
3207  //
3208 
3209  if(DiskInvalidatePartitionTable(fdoExtension, FALSE)) {
3211  }
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) {
3230  ExFreePool(srb);
3232  return status;
3233  }
3234 
3235  if (!TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
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 
3263 
3264  break;
3265  }
3266 
3267  } // end switch
3268 
3269  Irp->IoStatus.Status = status;
3270 
3272 
3274  }
3275 
3278  ExFreePool(srb);
3279  return(status);
3280 
3281 } // end DiskDeviceControl()
3282 
3283 NTSTATUS
3284 NTAPI
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 {
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 
3332  IoCallDriver(lowerDevice, Irp);
3333  return STATUS_PENDING;
3334  }
3335 
3336  //
3337  // Allocate SCSI request block.
3338  //
3339 
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;
3354  }
3355 
3357 
3358  //
3359  // Write length to SRB.
3360  //
3361 
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;
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 
3380  srb->CdbLength = 10;
3381 
3382  srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
3383 
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;
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 ?
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 
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 
3469  IoCallDriver(commonExtension->LowerDeviceObject, Irp);
3470  return STATUS_PENDING;
3471 } // end DiskShutdown()
3472 
3473 NTSTATUS
3474 NTAPI
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 
3525  length2,
3527 
3528  if(buffer == NULL) {
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 
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) {
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
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,
3638  &specialFlags);
3639 
3640  RtlZeroMemory(&cacheInfo, sizeof(DISK_CACHE_INFORMATION));
3641 
3642  status = DiskGetCacheInformation(fdoExtension, &cacheInfo);
3643 
3644  if (NT_SUCCESS(status) && (cacheInfo.WriteCacheEnabled != FALSE)) {
3645 
3646  cacheInfo.WriteCacheEnabled = FALSE;
3647 
3648  status = DiskSetCacheInformation(fdoExtension, &cacheInfo);
3649 
3651  {
3652  //
3653  // This device does not allow for
3654  // the write cache to be disabled
3655  //
3657 
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 
3674 
3675  ClassSetDeviceParameter(fdoExtension,
3678  specialFlags);
3679 
3680  IoFreeWorkItem(WorkItem);
3681 }
3682 
3683 //
3684 // This routine is structured as a work-item routine
3685 //
3686 VOID
3687 NTAPI
3689  IN PDEVICE_OBJECT Fdo,
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;
3699  PCDB Cdb = (PCDB)Srb->Cdb;
3700  LARGE_INTEGER byteOffset;
3701  ULONG sectorOffset;
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  {
3751 
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 
3778  Srb,
3779  NULL,
3780  0,
3781  FALSE);
3782 
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 
3796 
3797  ExFreePool(Srb);
3799 }
3800 
3801 VOID
3802 NTAPI
3804  PDEVICE_OBJECT Fdo,
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 
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,
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) {
3925  switch (ascq) {
3929  invalidatePartitionTable = TRUE;
3930  break;
3931  }
3932  } // end switch(ascq)
3933  break;
3934  }
3935 
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 
3950  invalidatePartitionTable = TRUE;
3951  break;
3952  }
3953 
3955  switch (senseBuffer->AdditionalSenseCode) {
3957  invalidatePartitionTable = TRUE;
3958  break;
3959  }
3960  }
3961  break;
3962  }
3963 
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)) {
3981  case SRB_STATUS_NO_DEVICE:
3982  case SRB_STATUS_NO_HBA:
3985  case SRB_STATUS_TIMEOUT:
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
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 
4047 
4048  //
4049  // Disable tagged queuing.
4050  //
4051 
4053  }
4054 
4056 
4057  //
4058  // Disable synchronous data transfers.
4059  //
4060 
4062 
4063  }
4064 
4066 
4067  //
4068  // Disable spinning down of drives.
4069  //
4070 
4071  SET_FLAG(FdoExtension->ScanForSpecialFlags,
4073 
4074  }
4075 
4077 
4078  //
4079  // Disable the drive's write cache
4080  //
4081 
4082  SET_FLAG(FdoExtension->ScanForSpecialFlags,
4084 
4085  }
4086 
4088 
4089  SET_FLAG(FdoExtension->ScanForSpecialFlags,
4091  }
4092 
4093  if (TEST_FLAG(fdo->Characteristics, FILE_REMOVABLE_MEDIA) &&
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
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 
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 
4148  }
4149 
4150  if (TEST_FLAG(specialFlags, HackDisableWriteCacheNotSupported))
4151  {
4152  //
4153  // This device does not permit disabling of the write cache
4154  //
4155 
4157  }
4158 }
4159 
4160 VOID
4161 NTAPI
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;
4189 
4190  DebugPrint((1, "Disk ResetBus: Sending reset bus request to port driver.\n"));
4191 
4192  //
4193  // Allocate Srb from nonpaged pool.
4194  //
4195 
4197  sizeof(COMPLETION_CONTEXT),
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 
4217 
4218  //
4219  // Write length to SRB.
4220  //
4221 
4223 
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) {
4236  return;
4237  }
4238 
4239  ClassAcquireRemoveLock(Fdo, irp);
4240 
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
4275  )
4276 
4277 {
4279  //PDISK_DATA diskData = commonExtension->DriverData;
4280 
4281  PAGED_CODE();
4282 
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
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 
4332 
4333  if (modeData == NULL) {
4334 
4335  DebugPrint((1, "DiskGetSetCacheInformation: Unable to allocate mode "
4336  "data buffer\n"));
4338  }
4339 
4340  RtlZeroMemory(modeData, MODE_DATA_SIZE);
4341 
4342  length = ClassModeSense(FdoExtension->DeviceObject,
4343  (PUCHAR) modeData,
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,
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,
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
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 
4453 
4454  if (modeData == NULL) {
4455 
4456  DebugPrint((1, "DiskSetCacheInformation: Unable to allocate mode "
4457  "data buffer\n"));
4459  }
4460 
4461  RtlZeroMemory(modeData, MODE_DATA_SIZE);
4462 
4463  length = ClassModeSense(FdoExtension->DeviceObject,
4464  (PUCHAR) modeData,
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,
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,
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 
4630 NTAPI
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 
4694 NTAPI
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 
4766 NTAPI
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 != FALSE) {
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
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 
4882 
4883  if (modeData == NULL) {
4884 
4885  DebugPrint((1, "DiskGetInfoExceptionInformation: Unable to allocate mode "
4886  "data buffer\n"));
4888  }
4889 
4890  RtlZeroMemory(modeData, MODE_DATA_SIZE);
4891 
4892  length = ClassModeSense(FdoExtension->DeviceObject,
4893  (PUCHAR) modeData,
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,
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,
4934  TRUE);
4935 
4936  if (pageData != NULL) {
4937  RtlCopyMemory(ReturnPageData, pageData, sizeof(MODE_INFO_EXCEPTIONS));
4939  } else {
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
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(
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;
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 
5041  return status;
5042  }
5043 
5044  if (commonExtension->PartitionNumber == 0) {
5045 
5047  return status;
5048  }
5049 
5050  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
5051  sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) {
5052 
5054  return status;
5055  }
5056 
5057  valueName = ExAllocatePoolWithTag(PagedPool,
5058  sizeof(WCHAR) * 64,
5059  DISK_TAG_NEC_98);
5060 
5061  if (!valueName) {
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 |
5080  queryTable[0].Name = valueName;
5081  queryTable[0].EntryContext = &driveLetterName;
5082 
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 |
5109  queryTable[0].Name = valueName;
5110  queryTable[0].EntryContext = &driveLetterName;
5111 
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 
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 =
5143 
5144  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
5145  Irp->IoStatus.Information) {
5146 
5147  Irp->IoStatus.Information =
5150  ExFreePool(valueName);
5151  return status;
5152  }
5153 
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
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 
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);
5260 
5261  Irp->IoStatus.Status = status;
5262 
5263  return status;
5264 }
5265 
5266 NTSTATUS
5267 NTAPI
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);
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);
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);
5417 
5418  return status;
5419 }
5420 
5421 NTSTATUS
5422 NTAPI
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;
5532  invalidateBusRelations = FALSE;
5533  }
5534 
5535  DiskReleasePartitioningLock(fdoExtension);
5536 
5537  if ( invalidateBusRelations ) {
5539  }
5540 
5541  return status;
5542 }
5543 
5544 NTSTATUS
5545 NTAPI
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;