ReactOS  0.4.15-dev-1397-g19779b3
disk.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 2010
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 #define DEBUG_MAIN_SOURCE 1
24 #include "disk.h"
25 
26 
27 //
28 // Now instantiate the GUIDs
29 //
30 
31 #include "initguid.h"
32 #include "ntddstor.h"
33 #include "ntddvol.h"
34 #include "ioevent.h"
35 
36 #ifdef DEBUG_USE_WPP
37 #include "disk.tmh"
38 #endif
39 
40 #ifdef ALLOC_PRAGMA
41 
42 #pragma alloc_text(INIT, DriverEntry)
43 #pragma alloc_text(PAGE, DiskUnload)
44 #pragma alloc_text(PAGE, DiskCreateFdo)
45 #pragma alloc_text(PAGE, DiskDetermineMediaTypes)
46 #pragma alloc_text(PAGE, DiskModeSelect)
47 #pragma alloc_text(PAGE, DisableWriteCache)
48 #pragma alloc_text(PAGE, DiskSetSpecialHacks)
49 #pragma alloc_text(PAGE, DiskGetCacheInformation)
50 #pragma alloc_text(PAGE, DiskSetCacheInformation)
51 #pragma alloc_text(PAGE, DiskLogCacheInformation)
52 #pragma alloc_text(PAGE, DiskSetInfoExceptionInformation)
53 #pragma alloc_text(PAGE, DiskGetInfoExceptionInformation)
54 #pragma alloc_text(PAGE, DiskIoctlGetCacheSetting)
55 #pragma alloc_text(PAGE, DiskIoctlSetCacheSetting)
56 #pragma alloc_text(PAGE, DiskIoctlGetLengthInfo)
57 #pragma alloc_text(PAGE, DiskIoctlGetDriveGeometry)
58 #pragma alloc_text(PAGE, DiskIoctlGetDriveGeometryEx)
59 #pragma alloc_text(PAGE, DiskIoctlGetCacheInformation)
60 #pragma alloc_text(PAGE, DiskIoctlSetCacheInformation)
61 #pragma alloc_text(PAGE, DiskIoctlGetMediaTypesEx)
62 #pragma alloc_text(PAGE, DiskIoctlPredictFailure)
63 #pragma alloc_text(PAGE, DiskIoctlEnableFailurePrediction)
64 #pragma alloc_text(PAGE, DiskIoctlReassignBlocks)
65 #pragma alloc_text(PAGE, DiskIoctlReassignBlocksEx)
66 #pragma alloc_text(PAGE, DiskIoctlIsWritable)
67 #pragma alloc_text(PAGE, DiskIoctlUpdateDriveSize)
68 #pragma alloc_text(PAGE, DiskIoctlGetVolumeDiskExtents)
69 #pragma alloc_text(PAGE, DiskIoctlSmartGetVersion)
70 #pragma alloc_text(PAGE, DiskIoctlSmartReceiveDriveData)
71 #pragma alloc_text(PAGE, DiskIoctlSmartSendDriveCommand)
72 #pragma alloc_text(PAGE, DiskIoctlVerifyThread)
73 
74 #endif
75 
76 //
77 // ETW related globals
78 //
80 
82 
83 const GUID GUID_NULL = { 0 };
84 #define DiskCompareGuid(_First,_Second) \
85  (memcmp ((_First),(_Second), sizeof (GUID)))
86 
87 //
88 // This macro is used to work around a bug in the definition of
89 // DISK_CACHE_RETENTION_PRIORITY. The value KeepReadData should be
90 // assigned 0xf rather than 0x2. Since the interface was already published
91 // when this was discovered the disk driver has been modified to translate
92 // between the interface value and the correct scsi value.
93 //
94 // 0x2 is turned into 0xf
95 // 0xf is turned into 0x2 - this ensures that future SCSI defintions can be
96 // accomodated.
97 //
98 
99 #define TRANSLATE_RETENTION_PRIORITY(_x)\
100  ((_x) == 0xf ? 0x2 : \
101  ((_x) == 0x2 ? 0xf : _x) \
102  )
103 
104 #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN CTL_CODE(IOCTL_VOLUME_BASE, 0, METHOD_BUFFERED, FILE_READ_ACCESS)
105 
106 VOID
107 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
110  IN PVOID Nothing,
111  IN ULONG Count
112  )
113 {
117 
119 }
120 
121 VOID
122 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
125  IN PVOID Nothing,
126  IN ULONG Count
127  )
128 {
130 
131 #if defined(_X86_) || defined(_AMD64_)
132 
133  DiskDriverReinitialization(DriverObject, Nothing, Count);
134 
135 #else
136 
139 
140 #endif
141 
142 }
143 
144 NTSTATUS
145 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
149  )
150 
151 /*++
152 
153 Routine Description:
154 
155  This routine initializes the SCSI hard disk class driver.
156 
157 Arguments:
158 
159  DriverObject - Pointer to driver object created by system.
160 
161  RegistryPath - Pointer to the name of the services node for this driver.
162 
163 Return Value:
164 
165  The function value is the final status from the initialization operation.
166 
167 --*/
168 
169 {
171  CLASS_QUERY_WMI_REGINFO_EX_LIST classQueryWmiRegInfoExList = { 0 };
172  GUID guidQueryRegInfoEx = GUID_CLASSPNP_QUERY_REGINFOEX;
173  GUID guidSrbSupport = GUID_CLASSPNP_SRB_SUPPORT;
174  ULONG srbSupport;
175 
177 
178  //
179  // Initializes tracing
180  //
182 
183 #if defined(_X86_) || defined(_AMD64_)
184 
185  //
186  // Read the information NtDetect squirreled away about the disks in this
187  // system.
188  //
189 
190  DiskSaveDetectInfo(DriverObject);
191 
192 #endif
193 
194  InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
195 
196  //
197  // Setup sizes and entry points for functional device objects
198  //
199 
200  InitializationData.FdoData.DeviceExtensionSize = FUNCTIONAL_EXTENSION_SIZE;
201  InitializationData.FdoData.DeviceType = FILE_DEVICE_DISK;
202  InitializationData.FdoData.DeviceCharacteristics = FILE_DEVICE_SECURE_OPEN;
203 
204  InitializationData.FdoData.ClassInitDevice = DiskInitFdo;
205  InitializationData.FdoData.ClassStartDevice = DiskStartFdo;
206  InitializationData.FdoData.ClassStopDevice = DiskStopDevice;
207  InitializationData.FdoData.ClassRemoveDevice = DiskRemoveDevice;
208  InitializationData.FdoData.ClassPowerDevice = ClassSpinDownPowerHandler;
209 
210  InitializationData.FdoData.ClassError = DiskFdoProcessError;
211  InitializationData.FdoData.ClassReadWriteVerification = DiskReadWriteVerification;
212  InitializationData.FdoData.ClassDeviceControl = DiskDeviceControl;
213  InitializationData.FdoData.ClassShutdownFlush = DiskShutdownFlush;
214  InitializationData.FdoData.ClassCreateClose = NULL;
215 
216 
217  InitializationData.FdoData.ClassWmiInfo.GuidCount = 7;
218  InitializationData.FdoData.ClassWmiInfo.GuidRegInfo = DiskWmiFdoGuidList;
219  InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiRegInfo = DiskFdoQueryWmiRegInfo;
220  InitializationData.FdoData.ClassWmiInfo.ClassQueryWmiDataBlock = DiskFdoQueryWmiDataBlock;
221  InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataBlock = DiskFdoSetWmiDataBlock;
222  InitializationData.FdoData.ClassWmiInfo.ClassSetWmiDataItem = DiskFdoSetWmiDataItem;
223  InitializationData.FdoData.ClassWmiInfo.ClassExecuteWmiMethod = DiskFdoExecuteWmiMethod;
224  InitializationData.FdoData.ClassWmiInfo.ClassWmiFunctionControl = DiskWmiFunctionControl;
225 
226  InitializationData.ClassAddDevice = DiskAddDevice;
227  InitializationData.ClassUnload = DiskUnload;
228 
229  //
230  // Initialize regregistration data structures
231  //
232 
234 
235  //
236  // Call the class init routine
237  //
238 
239  status = ClassInitialize(DriverObject, RegistryPath, &InitializationData);
240 
241  if (NT_SUCCESS(status)) {
242 
245  NULL);
246  }
247 
248  //
249  // Call class init Ex routine to register a
250  // PCLASS_QUERY_WMI_REGINFO_EX routine
251  //
252 
253  classQueryWmiRegInfoExList.Size = sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST);
254  classQueryWmiRegInfoExList.ClassFdoQueryWmiRegInfoEx = DiskFdoQueryWmiRegInfoEx;
255 
256  (VOID)ClassInitializeEx(DriverObject,
257  &guidQueryRegInfoEx,
258  &classQueryWmiRegInfoExList);
259 
260  //
261  // Call class init Ex routine to register SRB support
262  //
264  if (!NT_SUCCESS(ClassInitializeEx(DriverObject,
265  &guidSrbSupport,
266  &srbSupport))) {
267  //
268  // Should not fail
269  //
270  NT_ASSERT(FALSE);
271  }
272 
273 
274  return status;
275 
276 } // end DriverEntry()
277 
278 
279 VOID
280 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
283  )
284 {
285  PAGED_CODE();
286 
287 #if defined(_X86_) || defined(_AMD64_)
288  DiskCleanupDetectInfo(DriverObject);
289 #else
290  // NB: Need to use UNREFERENCED_PARAMETER to prevent build error
291  // DriverObject is not referenced below in WPP_CLEANUP.
292  // WPP_CLEANUP is currently an "NOOP" marco.
294 #endif
295 
296 
297  //
298  // Cleans up tracing
299  //
301 
302  return;
303 }
304 
305 
306 NTSTATUS
311  IN BOOLEAN DasdAccessOnly
312  )
313 
314 /*++
315 
316 Routine Description:
317 
318  This routine creates an object for the functional device
319 
320 Arguments:
321 
322  DriverObject - Pointer to driver object created by system.
323 
324  PhysicalDeviceObject - Lower level driver we should attach to
325 
326  DeviceCount - Number of previously installed devices.
327 
328  DasdAccessOnly - indicates whether or not a file system is allowed to mount
329  on this device object. Used to avoid double-mounting of
330  file systems on super-floppies (which can unfortunately be
331  fixed disks). If set the i/o system will only allow rawfs
332  to be mounted.
333 
334 Return Value:
335 
336  NTSTATUS
337 
338 --*/
339 
340 {
341  PCCHAR deviceName = NULL;
342  HANDLE handle = NULL;
343  PDEVICE_OBJECT lowerDevice = NULL;
345  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
347 
348  PAGED_CODE();
349 
350  *DeviceCount = 0;
351 
352  //
353  // Set up an object directory to contain the objects for this
354  // device and all its partitions.
355  //
356 
357  do {
358 
359  WCHAR dirBuffer[64] = { 0 };
360  UNICODE_STRING dirName;
361  OBJECT_ATTRIBUTES objectAttribs;
362 
363  status = RtlStringCchPrintfW(dirBuffer, sizeof(dirBuffer) / sizeof(dirBuffer[0]) - 1, L"\\Device\\Harddisk%d", *DeviceCount);
364  if (!NT_SUCCESS(status)) {
365  TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Format symbolic link failed with error: 0x%X\n", status));
366  return status;
367  }
368 
369  RtlInitUnicodeString(&dirName, dirBuffer);
370 
371  InitializeObjectAttributes(&objectAttribs,
372  &dirName,
374  NULL,
375  NULL);
376 
379  &objectAttribs);
380 
381  (*DeviceCount)++;
382 
383  } while((status == STATUS_OBJECT_NAME_COLLISION) ||
385 
386  if (!NT_SUCCESS(status)) {
387 
388  TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Could not create directory - %lx\n", status));
389 
390  return(status);
391  }
392 
393  //
394  // When this loop exits the count is inflated by one - fix that.
395  //
396 
397  (*DeviceCount)--;
398 
399  //
400  // Claim the device.
401  //
402 
404 
405  status = ClassClaimDevice(lowerDevice, FALSE);
406 
407  if (!NT_SUCCESS(status)) {
409  ZwClose(handle);
410  ObDereferenceObject(lowerDevice);
411  return status;
412  }
413 
414  //
415  // Create a device object for this device. Each physical disk will
416  // have at least one device object. The required device object
417  // describes the entire device. Its directory path is
418  // \Device\HarddiskN\Partition0, where N = device number.
419  //
420 
421  status = DiskGenerateDeviceName(*DeviceCount, &deviceName);
422 
423  if(!NT_SUCCESS(status)) {
424  TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo - couldn't create name %lx\n", status));
425 
426  goto DiskCreateFdoExit;
427 
428  }
429 
430  status = ClassCreateDeviceObject(DriverObject,
431  deviceName,
433  TRUE,
434  &deviceObject);
435 
436  if (!NT_SUCCESS(status)) {
437  TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, "DiskCreateFdo: Can not create device object %s\n", deviceName));
438  goto DiskCreateFdoExit;
439  }
440 
441  FREE_POOL(deviceName);
442 
443  //
444  // Indicate that IRPs should include MDLs for data transfers.
445  //
446 
448 
449  fdoExtension = deviceObject->DeviceExtension;
450 
451  if(DasdAccessOnly) {
452 
453  //
454  // Inidicate that only RAW should be allowed to mount on the root
455  // partition object. This ensures that a file system can't doubly
456  // mount on a super-floppy by mounting once on P0 and once on P1.
457  //
458 
459 #ifdef _MSC_VER
460 #pragma prefast(suppress:28175);
461 #endif
462  SET_FLAG(deviceObject->Vpb->Flags, VPB_RAW_MOUNT);
463  }
464 
465  //
466  // Initialize lock count to zero. The lock count is used to
467  // disable the ejection mechanism on devices that support
468  // removable media. Only the lock count in the physical
469  // device extension is used.
470  //
471 
472  fdoExtension->LockCount = 0;
473 
474  //
475  // Save system disk number.
476  //
477 
478  fdoExtension->DeviceNumber = *DeviceCount;
479 
480  //
481  // Set the alignment requirements for the device based on the
482  // host adapter requirements
483  //
484 
485  if (lowerDevice->AlignmentRequirement > deviceObject->AlignmentRequirement) {
486  deviceObject->AlignmentRequirement = lowerDevice->AlignmentRequirement;
487  }
488 
489  //
490  // Finally, attach to the pdo
491  //
492 
493  fdoExtension->LowerPdo = PhysicalDeviceObject;
494 
495  fdoExtension->CommonExtension.LowerDeviceObject =
497 
498 
499  if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
500 
501  //
502  // Uh - oh, we couldn't attach
503  // cleanup and return
504  //
505 
507  goto DiskCreateFdoExit;
508  }
509 
510  //
511  // Clear the init flag.
512  //
513 
515 
516  //
517  // Store a handle to the device object directory for this disk
518  //
519 
520  fdoExtension->DeviceDirectory = handle;
521 
522  ObDereferenceObject(lowerDevice);
523 
524  return STATUS_SUCCESS;
525 
526 DiskCreateFdoExit:
527 
528  if (deviceObject != NULL)
529  {
531  }
532 
533  FREE_POOL(deviceName);
534 
535  ObDereferenceObject(lowerDevice);
536 
538  ZwClose(handle);
539 
540  return status;
541 }
542 
543 
544 NTSTATUS
545 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
548  IN PIRP Irp
549  )
550 
551 /*++
552 
553 Routine Description:
554 
555  I/O System entry for read and write requests to SCSI disks.
556 
557 Arguments:
558 
559  DeviceObject - Pointer to driver object created by system.
560  Irp - IRP involved.
561 
562 Return Value:
563 
564  NT Status
565 
566 --*/
567 
568 {
569  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
571  ULONG residualBytes;
572  ULONG residualOffset;
574 
575  //
576  // Make sure that the request is within the bounds of the partition,
577  // the number of bytes to transfer and the byte offset are a
578  // multiple of the sector size.
579  //
580 
581  residualBytes = irpSp->Parameters.Read.Length & (commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector - 1);
582  residualOffset = irpSp->Parameters.Read.ByteOffset.LowPart & (commonExtension->PartitionZeroExtension->DiskGeometry.BytesPerSector - 1);
583 
584  if ((irpSp->Parameters.Read.ByteOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
585  (irpSp->Parameters.Read.ByteOffset.QuadPart < 0) ||
586  (residualBytes != 0) ||
587  (residualOffset != 0))
588  {
589  NT_ASSERT(residualOffset == 0);
591  }
592  else
593  {
594  ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - irpSp->Parameters.Read.ByteOffset.QuadPart;
595 
596  if ((ULONGLONG)irpSp->Parameters.Read.Length > bytesRemaining)
597  {
599  }
600  }
601 
602  if (!NT_SUCCESS(status))
603  {
604  //
605  // This error may be caused by the fact that the drive is not ready.
606  //
607 
608  status = ((PDISK_DATA) commonExtension->DriverData)->ReadyStatus;
609 
610  if (!NT_SUCCESS(status)) {
611 
612  //
613  // Flag this as a user error so that a popup is generated.
614  //
615 
616  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DiskReadWriteVerification: ReadyStatus is %lx\n", status));
617 
618  if (IoIsErrorUserInduced(status) && Irp->Tail.Overlay.Thread != NULL) {
620  }
621 
622  //
623  // status will keep the current error
624  //
625 
626  } else if ((residualBytes == 0) && (residualOffset == 0)) {
627 
628  //
629  // This failed because we think the physical disk is too small.
630  // Send it down to the drive and let the hardware decide for
631  // itself.
632  //
633 
635 
636  } else {
637 
638  //
639  // Note fastfat depends on this parameter to determine when to
640  // remount due to a sector size change.
641  //
642 
644  }
645  }
646 
647  Irp->IoStatus.Status = status;
648 
649  return status;
650 
651 } // end DiskReadWrite()
652 
653 
654 NTSTATUS
657  IN PIRP Irp,
658  IN UCHAR MediumType,
659  IN UCHAR DensityCode,
662  )
663 
664 /*++
665 
666 Routine Description:
667 
668  Determines number of types based on the physical device, validates the user buffer
669  and builds the MEDIA_TYPE information.
670 
671 Arguments:
672 
673  DeviceObject - Pointer to functional device object created by system.
674  Irp - IOCTL_STORAGE_GET_MEDIA_TYPES_EX Irp.
675  MediumType - byte returned in mode data header.
676  DensityCode - byte returned in mode data block descriptor.
677  NumberOfTypes - pointer to be updated based on actual device.
678 
679 Return Value:
680 
681  Status is returned.
682 
683 --*/
684 
685 {
686  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
688 
689  PGET_MEDIA_TYPES mediaTypes = Irp->AssociatedIrp.SystemBuffer;
690  PDEVICE_MEDIA_INFO mediaInfo = &mediaTypes->MediaInfo[0];
691  BOOLEAN deviceMatched = FALSE;
692 
693  PAGED_CODE();
694 
695  //
696  // this should be checked prior to calling into this routine
697  // as we use the buffer as mediaTypes
698  //
699 
700  NT_ASSERT(irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
701  sizeof(GET_MEDIA_TYPES));
702 
703  //
704  // Determine if this device is removable or fixed.
705  //
706 
707  if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
708 
709  //
710  // Fixed disk.
711  //
712 
713  mediaTypes->DeviceType = FILE_DEVICE_DISK;
714  mediaTypes->MediaInfoCount = 1;
715 
716  mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
717  mediaInfo->DeviceSpecific.DiskInfo.MediaType = FixedMedia;
718  mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
719  mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
720  mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
721  mediaInfo->DeviceSpecific.DiskInfo.NumberMediaSides = 1;
722  mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE);
723 
724  if (!IsWritable) {
725 
726  SET_FLAG(mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics,
728  }
729 
730  } else {
731 
732  PCCHAR vendorId = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->VendorIdOffset;
733  PCCHAR productId = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductIdOffset;
734  PCCHAR productRevision = (PCCHAR) fdoExtension->DeviceDescriptor + fdoExtension->DeviceDescriptor->ProductRevisionOffset;
735  DISK_MEDIA_TYPES_LIST const *mediaListEntry;
736  ULONG currentMedia;
737  ULONG i;
738  ULONG j;
739  ULONG sizeNeeded;
740 
741  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
742  "DiskDetermineMediaTypes: Vendor %s, Product %s\n",
743  vendorId,
744  productId));
745 
746 
747  //
748  // If there's an entry with such vendorId & ProductId in the DiskMediaTypesExclude list,
749  // this device shouldn't be looked up in the DiskMediaTypes list to determine a medium type.
750  // The exclude table allows to narrow down the set of devices described by the DiskMediaTypes
751  // list (e.g.: DiskMediaTypes says "all HP devices" and DiskMediaTypesExlclude says
752  // "except for HP RDX")
753  //
754 
755  for (i = 0; DiskMediaTypesExclude[i].VendorId != NULL; i++) {
756  mediaListEntry = &DiskMediaTypesExclude[i];
757 
758  if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) {
759  continue;
760  }
761 
762  if ((mediaListEntry->ProductId != NULL) &&
763  strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) {
764  continue;
765  }
766 
767  goto SkipTable;
768  }
769 
770  //
771  // Run through the list until we find the entry with a NULL Vendor Id.
772  //
773 
774  for (i = 0; DiskMediaTypes[i].VendorId != NULL; i++) {
775 
776  mediaListEntry = &DiskMediaTypes[i];
777 
778  if (strncmp(mediaListEntry->VendorId,vendorId,strlen(mediaListEntry->VendorId))) {
779  continue;
780  }
781 
782  if ((mediaListEntry->ProductId != NULL) &&
783  strncmp(mediaListEntry->ProductId, productId, strlen(mediaListEntry->ProductId))) {
784  continue;
785  }
786 
787  if ((mediaListEntry->Revision != NULL) &&
788  strncmp(mediaListEntry->Revision, productRevision, strlen(mediaListEntry->Revision))) {
789  continue;
790  }
791 
792  deviceMatched = TRUE;
793 
794  mediaTypes->DeviceType = FILE_DEVICE_DISK;
795  mediaTypes->MediaInfoCount = mediaListEntry->NumberOfTypes;
796 
797  //
798  // Ensure that buffer is large enough.
799  //
800 
801  sizeNeeded = FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) +
802  (mediaListEntry->NumberOfTypes *
803  sizeof(DEVICE_MEDIA_INFO)
804  );
805 
806  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
807  sizeNeeded) {
808 
809  //
810  // Buffer too small
811  //
812 
813  Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
815  }
816 
817  for (j = 0; j < mediaListEntry->NumberOfTypes; j++) {
818 
819  mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
820  mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
821  mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
822  mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
823  mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = mediaListEntry->NumberOfSides;
824 
825  //
826  // Set the type.
827  //
828 
829  mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = mediaListEntry->MediaTypes[j];
830 
831  if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == MO_5_WO) {
832  mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_WRITE_ONCE;
833  } else {
834  mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
835  }
836 
837  //
838  // Status will either be success, if media is present, or no media.
839  // It would be optimal to base from density code and medium type, but not all devices
840  // have values for these fields.
841  //
842 
843  if (MediaPresent) {
844 
845  //
846  // The usage of MediumType and DensityCode is device specific, so this may need
847  // to be extended to further key off of product/vendor ids.
848  // Currently, the MO units are the only devices that return this information.
849  //
850 
851  if (MediumType == 2) {
852  currentMedia = MO_5_WO;
853  } else if (MediumType == 3) {
854  currentMedia = MO_5_RW;
855 
856  if (DensityCode == 0x87) {
857 
858  //
859  // Indicate that the pinnacle 4.6 G media
860  // is present. Other density codes will default to normal
861  // RW MO media.
862  //
863 
864  currentMedia = PINNACLE_APEX_5_RW;
865  }
866  } else {
867  currentMedia = 0;
868  }
869 
870  if (currentMedia) {
871  if (mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType == (STORAGE_MEDIA_TYPE)currentMedia) {
872  SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
873  }
874 
875  } else {
876  SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
877  }
878  }
879 
880  if (!IsWritable) {
881  SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED);
882  }
883 
884  //
885  // Advance to next entry.
886  //
887 
888  mediaInfo++;
889  }
890  }
891 
892 SkipTable:
893 
894  if (!deviceMatched) {
895 
896  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL,
897  "DiskDetermineMediaTypes: Unknown device. Vendor: %s Product: %s Revision: %s\n",
898  vendorId,
899  productId,
900  productRevision));
901  //
902  // Build an entry for unknown.
903  //
904 
905  mediaTypes->DeviceType = FILE_DEVICE_DISK;
906  mediaTypes->MediaInfoCount = 1;
907 
908  mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = fdoExtension->DiskGeometry.Cylinders.QuadPart;
909  mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = RemovableMedia;
910  mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = fdoExtension->DiskGeometry.TracksPerCylinder;
911  mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = fdoExtension->DiskGeometry.SectorsPerTrack;
912  mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = fdoExtension->DiskGeometry.BytesPerSector;
913  mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
914  mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = MEDIA_READ_WRITE;
915 
916  if (MediaPresent) {
917 
918  SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_CURRENTLY_MOUNTED);
919  }
920 
921  if (!IsWritable) {
922 
923  SET_FLAG(mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics, MEDIA_WRITE_PROTECTED);
924  }
925  }
926  }
927 
928  Irp->IoStatus.Information =
929  FIELD_OFFSET(GET_MEDIA_TYPES, MediaInfo[0]) +
930  (mediaTypes->MediaInfoCount * sizeof(DEVICE_MEDIA_INFO));
931 
932  return STATUS_SUCCESS;
933 }
934 
935 NTSTATUS
936 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
939  PIRP Irp
940  )
941 
942 /*++
943 
944 Routine Description:
945 
946  I/O system entry for device controls to SCSI disks.
947 
948 Arguments:
949 
950  Fdo - Pointer to functional device object created by system.
951  Irp - IRP involved.
952 
953 Return Value:
954 
955  Status is returned.
956 
957 --*/
958 
959 {
962  ULONG ioctlCode;
963 
965 
966  Irp->IoStatus.Information = 0;
967  ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
968 
969  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "DiskDeviceControl: Received IOCTL 0x%X for device %p through IRP %p\n",
970  ioctlCode, DeviceObject, Irp));
971 
972 
973  switch (ioctlCode) {
974 
977  break;
978  }
979 
982  break;
983  }
984 
987  break;
988  }
989 
992  break;
993  }
994 
997  break;
998  }
999 
1002  break;
1003  }
1004 
1005  case IOCTL_DISK_VERIFY: {
1007  break;
1008  }
1009 
1012  break;
1013  }
1014 
1015  case IOCTL_DISK_IS_WRITABLE: {
1017  break;
1018  }
1019 
1022  break;
1023  }
1024 
1027  break;
1028  }
1029 
1032  break;
1033  }
1034 
1037  break;
1038  }
1039 
1042  break;
1043  }
1044 
1047  break;
1048  }
1049 
1052  break;
1053  }
1054 
1055  #if (NTDDI_VERSION >= NTDDI_WINBLUE)
1056  case IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG : {
1058  break;
1059  }
1060  #endif
1061 
1062  case SMART_GET_VERSION: {
1064  break;
1065  }
1066 
1067  case SMART_RCV_DRIVE_DATA: {
1069  break;
1070  }
1071 
1072  case SMART_SEND_DRIVE_COMMAND: {
1074  break;
1075  }
1076 
1080  break;
1081  }
1082 
1083  default: {
1084 
1085  //
1086  // Pass the request to the common device control routine.
1087  //
1089  break;
1090  }
1091  } // end switch
1092 
1093  if (!NT_SUCCESS(status)) {
1094 
1095  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskDeviceControl: IOCTL 0x%X to device %p failed with error 0x%X\n",
1096  ioctlCode, DeviceObject, status));
1098  (Irp->Tail.Overlay.Thread != NULL)) {
1100  }
1101  }
1102 
1103  //
1104  // DiskIoctlVerify() (IOCTL_DISK_VERIFY) function returns STATUS_PENDING
1105  // and completes the IRP in the work item. Do not touch or complete
1106  // the IRP if STATUS_PENDING is returned.
1107  //
1108 
1109  if (status != STATUS_PENDING) {
1110 
1111 
1112  Irp->IoStatus.Status = status;
1115  }
1116 
1117  return(status);
1118 } // end DiskDeviceControl()
1119 
1120 NTSTATUS
1121 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1124  IN PIRP Irp
1125  )
1126 
1127 /*++
1128 
1129 Routine Description:
1130 
1131  This routine is the handler for shutdown and flush requests. It sends
1132  down a synch cache command to the device if its cache is enabled. If
1133  the request is a shutdown and the media is removable, it sends down
1134  an unlock request
1135 
1136  Finally, an SRB_FUNCTION_SHUTDOWN or SRB_FUNCTION_FLUSH is sent down
1137  the stack
1138 
1139 Arguments:
1140 
1141  DeviceObject - The device object processing the request
1142  Irp - The shutdown | flush request being serviced
1143 
1144 Return Value:
1145 
1146  STATUS_PENDING if successful, an error code otherwise
1147 
1148 --*/
1149 
1150 {
1151  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1152  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension;
1153  PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData;
1154  PIO_STACK_LOCATION irpStack;
1156  ULONG srbSize;
1157  PSCSI_REQUEST_BLOCK srb;
1158  PSTORAGE_REQUEST_BLOCK srbEx = NULL;
1159  PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
1160  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL;
1161  PCDB cdb;
1162  KIRQL irql;
1163 
1164  //
1165  // Flush requests are combined and need to be handled in a special manner
1166  //
1167 
1168  irpStack = IoGetCurrentIrpStackLocation(Irp);
1169 
1170  if (irpStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) {
1171 
1172  if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED)) {
1173 
1174  //
1175  // We've been assured that both the disk
1176  // and adapter caches are battery-backed
1177  //
1178 
1179  Irp->IoStatus.Status = STATUS_SUCCESS;
1182  return STATUS_SUCCESS;
1183  }
1184 
1186 
1187  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: IRP %p flags = 0x%x\n", Irp, irpStack->Flags));
1188 
1189  //
1190  // This request will most likely be completed asynchronously
1191  //
1193 
1194  //
1195  // Look to see if a flush is in progress
1196  //
1197 
1198  if (diskData->FlushContext.CurrIrp != NULL) {
1199 
1200  //
1201  // There is an outstanding flush. Queue this
1202  // request to the group that is next in line
1203  //
1204 
1205  if (diskData->FlushContext.NextIrp != NULL) {
1206 
1207  #if DBG
1208  diskData->FlushContext.DbgTagCount++;
1209  #endif
1210 
1211  InsertTailList(&diskData->FlushContext.NextList, &Irp->Tail.Overlay.ListEntry);
1212 
1214 
1215  //
1216  // This request will be completed by its representative
1217  //
1218 
1219  } else {
1220 
1221  #if DBG
1222  if (diskData->FlushContext.DbgTagCount < 64) {
1223 
1224  diskData->FlushContext.DbgRefCount[diskData->FlushContext.DbgTagCount]++;
1225  }
1226 
1227  diskData->FlushContext.DbgSavCount += diskData->FlushContext.DbgTagCount;
1228  diskData->FlushContext.DbgTagCount = 0;
1229  #endif
1230 
1231  diskData->FlushContext.NextIrp = Irp;
1233 
1234 
1236 
1237 
1238  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: waiting for event\n"));
1239 
1240  //
1241  // Wait for the outstanding flush to complete
1242  //
1244 
1245  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskShutdownFlush: event signal\n"));
1246 
1247  //
1248  // Make this group the outstanding one and free up the next slot
1249  //
1250 
1252 
1254 
1255  while (!IsListEmpty(&diskData->FlushContext.NextList)) {
1256 
1257  PLIST_ENTRY listEntry = RemoveHeadList(&diskData->FlushContext.NextList);
1258  InsertTailList(&diskData->FlushContext.CurrList, listEntry);
1259  }
1260 
1261  NT_ASSERT(diskData->FlushContext.CurrIrp != diskData->FlushContext.NextIrp);
1262  diskData->FlushContext.CurrIrp = diskData->FlushContext.NextIrp;
1263  diskData->FlushContext.NextIrp = NULL;
1264 
1266 
1267  //
1268  // Send this request down to the device
1269  //
1271  }
1272 
1273  } else {
1274 
1275  diskData->FlushContext.CurrIrp = Irp;
1277 
1278  NT_ASSERT(diskData->FlushContext.NextIrp == NULL);
1280 
1281 
1283 
1285  }
1286 
1287  } else {
1288 
1289  //
1290  // Allocate SCSI request block.
1291  //
1292 
1293  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1295  } else {
1296  srbSize = sizeof(SCSI_REQUEST_BLOCK);
1297  }
1298 
1299  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
1300  srbSize,
1301  DISK_TAG_SRB);
1302  if (srb == NULL) {
1303 
1304  //
1305  // Set the status and complete the request.
1306  //
1307 
1308  Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1312  }
1313 
1314  RtlZeroMemory(srb, srbSize);
1315  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1316 
1317  srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
1318 
1319  //
1320  // Set up STORAGE_REQUEST_BLOCK fields
1321  //
1322 
1323  srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
1324  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
1325  srbEx->Signature = SRB_SIGNATURE;
1326  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
1327  srbEx->SrbLength = srbSize;
1328  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1329  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
1330  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
1331  srbEx->NumSrbExData = 1;
1332 
1333  // Set timeout value and mark the request as not being a tagged request.
1334  srbEx->TimeOutValue = fdoExtension->TimeOutValue * 4;
1335  srbEx->RequestTag = SP_UNTAGGED;
1336  srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST;
1337  srbEx->SrbFlags = fdoExtension->SrbFlags;
1338 
1339  //
1340  // Set up address fields
1341  //
1342 
1343  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
1344  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
1345  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
1346 
1347  //
1348  // Set up SCSI SRB extended data fields
1349  //
1350 
1351  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
1352  sizeof(STOR_ADDR_BTL8);
1353  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
1354  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
1355  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
1356  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
1357 
1358  cdb = (PCDB)srbExDataCdb16->Cdb;
1359  } else {
1360  // Should not happen
1361  NT_ASSERT(FALSE);
1362 
1363  //
1364  // Set the status and complete the request.
1365  //
1366 
1367  Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
1370  return(STATUS_INTERNAL_ERROR);
1371  }
1372 
1373  } else {
1374 
1375  //
1376  // Write length to SRB.
1377  //
1378 
1379  srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1380 
1381  //
1382  // Set timeout value and mark the request as not being a tagged request.
1383  //
1384 
1385  srb->TimeOutValue = fdoExtension->TimeOutValue * 4;
1386  srb->QueueTag = SP_UNTAGGED;
1387  srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
1388  srb->SrbFlags = fdoExtension->SrbFlags;
1389  srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1390 
1391  cdb = (PCDB)srb->Cdb;
1392  }
1393 
1394  //
1395  // If the write cache is enabled then send a synchronize cache request.
1396  //
1397 
1398  if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE)) {
1399 
1400  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1401  srbExDataCdb16->CdbLength = 10;
1402  } else {
1403  srb->CdbLength = 10;
1404  }
1405 
1406  cdb->CDB10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
1407 
1409  srb,
1410  NULL,
1411  0,
1412  TRUE);
1413 
1414  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status));
1415  }
1416 
1417  //
1418  // Unlock the device if it contains removable media
1419  //
1420 
1421  if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
1422  {
1423 
1424  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1425 
1426  //
1427  // Reinitialize status fields to 0 in case there was a previous request
1428  //
1429 
1430  srbEx->SrbStatus = 0;
1431  srbExDataCdb16->ScsiStatus = 0;
1432 
1433  srbExDataCdb16->CdbLength = 6;
1434 
1435  //
1436  // Set timeout value
1437  //
1438 
1439  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
1440 
1441  } else {
1442 
1443  //
1444  // Reinitialize status fields to 0 in case there was a previous request
1445  //
1446 
1447  srb->SrbStatus = 0;
1448  srb->ScsiStatus = 0;
1449 
1450  srb->CdbLength = 6;
1451 
1452  //
1453  // Set timeout value.
1454  //
1455 
1456  srb->TimeOutValue = fdoExtension->TimeOutValue;
1457  }
1458 
1459  cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
1460  cdb->MEDIA_REMOVAL.Prevent = FALSE;
1461 
1463  srb,
1464  NULL,
1465  0,
1466  TRUE);
1467 
1468  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskShutdownFlush: Unlock device request sent. Status = %lx\n", status));
1469  }
1470 
1471  //
1472  // Set up a SHUTDOWN SRB
1473  //
1474 
1475  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1476  srbEx->NumSrbExData = 0;
1477  srbEx->SrbExDataOffset[0] = 0;
1478  srbEx->SrbFunction = SRB_FUNCTION_SHUTDOWN;
1479  srbEx->OriginalRequest = Irp;
1480  srbEx->SrbLength = CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE;
1481  srbEx->SrbStatus = 0;
1482  } else {
1483  srb->CdbLength = 0;
1484  srb->Function = SRB_FUNCTION_SHUTDOWN;
1485  srb->SrbStatus = 0;
1486  srb->OriginalRequest = Irp;
1487  }
1488 
1489  //
1490  // Set the retry count to zero.
1491  //
1492 
1493  irpStack->Parameters.Others.Argument4 = (PVOID) 0;
1494 
1495  //
1496  // Set up IoCompletion routine address.
1497  //
1498 
1500 
1501  //
1502  // Get next stack location and
1503  // set major function code.
1504  //
1505 
1506  irpStack = IoGetNextIrpStackLocation(Irp);
1507 
1508  irpStack->MajorFunction = IRP_MJ_SCSI;
1509 
1510  //
1511  // Set up SRB for execute scsi request.
1512  // Save SRB address in next stack for port driver.
1513  //
1514 
1515  irpStack->Parameters.Scsi.Srb = srb;
1516 
1517  //
1518  // Call the port driver to process the request.
1519  //
1520 
1522  IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1523  }
1524 
1525  return STATUS_PENDING;
1526 }
1527 
1528 
1529 VOID
1532  IN PDISK_GROUP_CONTEXT FlushContext
1533  )
1534 
1535 /*++
1536 
1537 Routine Description:
1538 
1539  This routine is the handler for flush requests. It sends down a synch
1540  cache command to the device if its cache is enabled. This is followed
1541  by an SRB_FUNCTION_FLUSH
1542 
1543 Arguments:
1544 
1545  Fdo - The device object processing the flush request
1546  FlushContext - The flush group context
1547 
1548 Return Value:
1549 
1550  None
1551 
1552 --*/
1553 
1554 {
1555  PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
1556  PSCSI_REQUEST_BLOCK srb = &FlushContext->Srb.Srb;
1557  PSTORAGE_REQUEST_BLOCK srbEx = &FlushContext->Srb.SrbEx;
1559  PSTOR_ADDR_BTL8 storAddrBtl8;
1560  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
1561  NTSTATUS SyncCacheStatus = STATUS_SUCCESS;
1562 
1563  //
1564  // Fill in the srb fields appropriately
1565  //
1566  if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1567  RtlZeroMemory(srbEx, sizeof(FlushContext->Srb.SrbExBuffer));
1568 
1569  srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
1570  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
1571  srbEx->Signature = SRB_SIGNATURE;
1572  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
1573  srbEx->SrbLength = sizeof(FlushContext->Srb.SrbExBuffer);
1574  srbEx->RequestPriority = IoGetIoPriorityHint(FlushContext->CurrIrp);
1575  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
1576  srbEx->TimeOutValue = fdoExt->TimeOutValue * 4;
1577  srbEx->RequestTag = SP_UNTAGGED;
1578  srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST;
1579  srbEx->SrbFlags = fdoExt->SrbFlags;
1580 
1581  //
1582  // Set up address fields
1583  //
1584 
1585  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
1586  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
1587  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
1588 
1589  } else {
1591 
1593  srb->TimeOutValue = fdoExt->TimeOutValue * 4;
1594  srb->QueueTag = SP_UNTAGGED;
1596  srb->SrbFlags = fdoExt->SrbFlags;
1597  }
1598 
1599  //
1600  // If write caching is enabled then send down a synchronize cache request
1601  //
1602  if (TEST_FLAG(fdoExt->DeviceFlags, DEV_WRITE_CACHE))
1603  {
1604 
1605  if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1606  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1607  srbEx->NumSrbExData = 1;
1608 
1609  //
1610  // Set up SCSI SRB extended data fields
1611  //
1612 
1613  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
1614  sizeof(STOR_ADDR_BTL8);
1615  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
1616  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
1617  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
1618  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
1619  srbExDataCdb16->CdbLength = 10;
1620  srbExDataCdb16->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
1621  } else {
1622  // Should not happen
1623  NT_ASSERT(FALSE);
1624  return;
1625  }
1626 
1627  } else {
1629  srb->CdbLength = 10;
1630  srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
1631  }
1632 
1633  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending sync cache\n"));
1634 
1635  SyncCacheStatus = ClassSendSrbSynchronous(Fdo, srb, NULL, 0, TRUE);
1636  }
1637 
1638  //
1639  // Set up a FLUSH SRB
1640  //
1641  if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1642  srbEx->SrbFunction = SRB_FUNCTION_FLUSH;
1643  srbEx->NumSrbExData = 0;
1644  srbEx->SrbExDataOffset[0] = 0;
1645  srbEx->OriginalRequest = FlushContext->CurrIrp;
1646  srbEx->SrbStatus = 0;
1647 
1648  //
1649  // Make sure that this srb does not get freed
1650  //
1651  SET_FLAG(srbEx->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT);
1652 
1653  } else {
1655  srb->CdbLength = 0;
1656  srb->OriginalRequest = FlushContext->CurrIrp;
1657  srb->SrbStatus = 0;
1658  srb->ScsiStatus = 0;
1659 
1660  //
1661  // Make sure that this srb does not get freed
1662  //
1664  }
1665 
1666  //
1667  // Make sure that this request does not get retried
1668  //
1669  irpSp = IoGetCurrentIrpStackLocation(FlushContext->CurrIrp);
1670 
1671  irpSp->Parameters.Others.Argument4 = (PVOID) 0;
1672 
1673  //
1674  // Fill in the irp fields appropriately
1675  //
1676  irpSp = IoGetNextIrpStackLocation(FlushContext->CurrIrp);
1677 
1678  irpSp->MajorFunction = IRP_MJ_SCSI;
1679  irpSp->Parameters.Scsi.Srb = srb;
1680 
1681  IoSetCompletionRoutine(FlushContext->CurrIrp, DiskFlushComplete, (PVOID)SyncCacheStatus, TRUE, TRUE, TRUE);
1682 
1683  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending srb flush on irp %p\n", FlushContext->CurrIrp));
1684 
1685  //
1686  // Send down the flush request
1687  //
1688  IoCallDriver(((PCOMMON_DEVICE_EXTENSION)fdoExt)->LowerDeviceObject, FlushContext->CurrIrp);
1689 }
1690 
1691 
1692 
1693 NTSTATUS
1694 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1697  IN PIRP Irp,
1698  IN PVOID Context
1699  )
1700 
1701 /*++
1702 
1703 Routine Description:
1704 
1705  This completion routine is a wrapper around ClassIoComplete. It
1706  will complete all the flush requests that are tagged to it, set
1707  an event to signal the next group to proceed and return
1708 
1709 Arguments:
1710 
1711  Fdo - The device object which requested the completion routine
1712  Irp - The irp that is being completed
1713  Context - If disk had write cache enabled and SYNC CACHE command was sent as 1st part of FLUSH processing
1714  then context must carry the completion status of SYNC CACHE request,
1715  else context must be set to STATUS_SUCCESS.
1716 
1717 Return Value:
1718 
1719  STATUS_SUCCESS if successful, an error code otherwise
1720 
1721 --*/
1722 
1723 {
1724  PDISK_GROUP_CONTEXT FlushContext;
1725  NTSTATUS status;
1727  PDISK_DATA diskData;
1728 #ifdef _MSC_VER
1729  #pragma warning(suppress:4311) // pointer truncation from 'PVOID' to 'NTSTATUS'
1730 #endif
1731  NTSTATUS SyncCacheStatus = (NTSTATUS) Context;
1732 
1733  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DiskFlushComplete: %p %p\n", Fdo, Irp));
1734 
1735  //
1736  // Get the flush context from the device extension
1737  //
1738  fdoExt = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension;
1739  diskData = (PDISK_DATA)fdoExt->CommonExtension.DriverData;
1740  NT_ASSERT(diskData != NULL);
1741  _Analysis_assume_(diskData != NULL);
1742 
1743  FlushContext = &diskData->FlushContext;
1744 
1745  //
1746  // Make sure everything is in order
1747  //
1748  NT_ASSERT(Irp == FlushContext->CurrIrp);
1749 
1750  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushComplete: completing irp %p\n", Irp));
1751  status = ClassIoComplete(Fdo, Irp, &FlushContext->Srb.Srb);
1752 
1753  //
1754  // Make sure that ClassIoComplete did not decide to retry this request
1755  //
1757 
1758  //
1759  // If sync cache failed earlier, final status of the flush request needs to be failure
1760  // even if SRB_FUNCTION_FLUSH srb request succeeded
1761  //
1762  if (NT_SUCCESS(status) &&
1763  (!NT_SUCCESS(SyncCacheStatus))) {
1764  Irp->IoStatus.Status = status = SyncCacheStatus;
1765  }
1766 
1767  //
1768  // Complete the flush requests tagged to this one
1769  //
1770 
1771  while (!IsListEmpty(&FlushContext->CurrList)) {
1772 
1773  PLIST_ENTRY listEntry = RemoveHeadList(&FlushContext->CurrList);
1774  PIRP tempIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
1775 
1776  InitializeListHead(&tempIrp->Tail.Overlay.ListEntry);
1777  tempIrp->IoStatus = Irp->IoStatus;
1778 
1779  ClassReleaseRemoveLock(Fdo, tempIrp);
1781  }
1782 
1783 
1784  //
1785  // Notify the next group's representative that it may go ahead now
1786  //
1787  KeSetEvent(&FlushContext->Event, IO_NO_INCREMENT, FALSE);
1788 
1789 
1790  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushComplete: irp %p status = 0x%x\n", Irp, status));
1791 
1792  return status;
1793 }
1794 
1795 
1796 
1797 NTSTATUS
1800  _In_reads_bytes_(Length) PCHAR ModeSelectBuffer,
1801  IN ULONG Length,
1802  IN BOOLEAN SavePage
1803  )
1804 
1805 /*++
1806 
1807 Routine Description:
1808 
1809  This routine sends a mode select command.
1810 
1811 Arguments:
1812 
1813  DeviceObject - Supplies the device object associated with this request.
1814 
1815  ModeSelectBuffer - Supplies a buffer containing the page data.
1816 
1817  Length - Supplies the length in bytes of the mode select buffer.
1818 
1819  SavePage - Indicates that parameters should be written to disk.
1820 
1821 Return Value:
1822 
1823  Length of the transferred data is returned.
1824 
1825 --*/
1826 
1827 {
1828  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
1829  PCDB cdb;
1830  SCSI_REQUEST_BLOCK srb = {0};
1831  ULONG retries = 1;
1832  ULONG length2;
1833  NTSTATUS status;
1834  PULONG buffer;
1835  PMODE_PARAMETER_BLOCK blockDescriptor;
1836  UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0};
1837  PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer;
1838  PSTOR_ADDR_BTL8 storAddrBtl8;
1839  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
1840  PSCSI_REQUEST_BLOCK srbPtr;
1841 
1842  PAGED_CODE();
1843 
1844  //
1845  // Check whether block length is available
1846  //
1847 
1848  if (fdoExtension->DiskGeometry.BytesPerSector == 0) {
1849 
1850  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskModeSelect: Block length is not available. Unable to send mode select\n"));
1851  NT_ASSERT(fdoExtension->DiskGeometry.BytesPerSector != 0);
1852  return STATUS_INVALID_PARAMETER;
1853  }
1854 
1855 
1856 
1857  length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
1858 
1859  //
1860  // Allocate buffer for mode select header, block descriptor, and mode page.
1861  //
1862 
1863  buffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
1864  length2,
1866 
1867  if (buffer == NULL) {
1869  }
1870 
1871  RtlZeroMemory(buffer, length2);
1872 
1873  //
1874  // Set length in header to size of mode page.
1875  //
1876 
1877  ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
1878 
1879  blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
1880 
1881  //
1882  // Set block length from the cached disk geometry
1883  //
1884 
1885  blockDescriptor->BlockLength[2] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector >> 16);
1886  blockDescriptor->BlockLength[1] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector >> 8);
1887  blockDescriptor->BlockLength[0] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector);
1888 
1889  //
1890  // Copy mode page to buffer.
1891  //
1892 
1893  RtlCopyMemory(buffer + 3, ModeSelectBuffer, Length);
1894 
1895  //
1896  // Build the MODE SELECT CDB.
1897  //
1898 
1899  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1900 
1901  //
1902  // Set up STORAGE_REQUEST_BLOCK fields
1903  //
1904 
1905  srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
1906  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
1907  srbEx->Signature = SRB_SIGNATURE;
1908  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
1909  srbEx->SrbLength = sizeof(srbExBuffer);
1910  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1911  srbEx->RequestPriority = IoPriorityNormal;
1912  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
1913  srbEx->NumSrbExData = 1;
1914 
1915  // Set timeout value from device extension.
1916  srbEx->TimeOutValue = fdoExtension->TimeOutValue * 2;
1917 
1918  //
1919  // Set up address fields
1920  //
1921 
1922  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
1923  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
1924  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
1925 
1926  //
1927  // Set up SCSI SRB extended data fields
1928  //
1929 
1930  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
1931  sizeof(STOR_ADDR_BTL8);
1932  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
1933  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
1934  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
1935  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
1936  srbExDataCdb16->CdbLength = 6;
1937 
1938  cdb = (PCDB)srbExDataCdb16->Cdb;
1939  } else {
1940  // Should not happen
1941  NT_ASSERT(FALSE);
1942 
1943  FREE_POOL(buffer);
1944  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskModeSelect: Insufficient extended SRB size\n"));
1945  return STATUS_INTERNAL_ERROR;
1946  }
1947 
1948  srbPtr = (PSCSI_REQUEST_BLOCK)srbEx;
1949 
1950  } else {
1951 
1952  srb.CdbLength = 6;
1953  cdb = (PCDB)srb.Cdb;
1954 
1955  //
1956  // Set timeout value from device extension.
1957  //
1958 
1959  srb.TimeOutValue = fdoExtension->TimeOutValue * 2;
1960 
1961  srbPtr = &srb;
1962  }
1963 
1964  cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1965  cdb->MODE_SELECT.SPBit = SavePage;
1966  cdb->MODE_SELECT.PFBit = 1;
1967  cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
1968 
1969 Retry:
1970 
1972  srbPtr,
1973  buffer,
1974  length2,
1975  TRUE);
1976 
1977  if (status == STATUS_VERIFY_REQUIRED) {
1978 
1979  //
1980  // Routine ClassSendSrbSynchronous does not retry requests returned with
1981  // this status.
1982  //
1983 
1984  if (retries--) {
1985 
1986  //
1987  // Retry request.
1988  //
1989 
1990  goto Retry;
1991  }
1992 
1993  } else if (SRB_STATUS(srbPtr->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
1995  }
1996 
1997  FREE_POOL(buffer);
1998 
1999  return status;
2000 } // end DiskModeSelect()
2001 
2002 
2003 //
2004 // This routine is structured as a work-item routine
2005 //
2006 VOID
2007 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2010  IN PVOID Context
2011  )
2012 
2013 {
2014  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension;
2015  DISK_CACHE_INFORMATION cacheInfo = { 0 };
2016  NTSTATUS status;
2018 
2019  PAGED_CODE();
2020 
2021  NT_ASSERT(WorkItem != NULL);
2023 
2024  status = DiskGetCacheInformation(fdoExtension, &cacheInfo);
2025 
2026  if (NT_SUCCESS(status) && (cacheInfo.WriteCacheEnabled == TRUE)) {
2027 
2028  cacheInfo.WriteCacheEnabled = FALSE;
2029 
2030  DiskSetCacheInformation(fdoExtension, &cacheInfo);
2031  }
2032 
2034 }
2035 
2036 
2037 //
2038 // This routine is structured as a work-item routine
2039 //
2040 VOID
2041 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2044  IN PVOID Context
2045  )
2046 {
2048  PIRP Irp = NULL;
2050  PDISK_DATA DiskData = (PDISK_DATA)FdoExtension->CommonExtension.DriverData;
2051  PVERIFY_INFORMATION verifyInfo = NULL;
2053  PCDB Cdb = NULL;
2054  LARGE_INTEGER byteOffset;
2055  LARGE_INTEGER sectorOffset;
2058  PSTORAGE_REQUEST_BLOCK srbEx = NULL;
2059  PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
2060  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL;
2061 
2062  PAGED_CODE();
2063 
2064  NT_ASSERT(WorkContext != NULL);
2065  _Analysis_assume_(WorkContext != NULL);
2066 
2067  Srb = WorkContext->Srb;
2068  Irp = WorkContext->Irp;
2069  verifyInfo = (PVERIFY_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2070 
2071  //
2072  // We don't need to hold on to this memory as
2073  // the following operation may take some time
2074  //
2075 
2076  IoFreeWorkItem(WorkContext->WorkItem);
2077 
2078  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlVerifyThread: Spliting up the request\n"));
2079 
2080  //
2081  // Add disk offset to starting the sector
2082  //
2083 
2084  byteOffset.QuadPart = FdoExtension->CommonExtension.StartingOffset.QuadPart +
2085  verifyInfo->StartingOffset.QuadPart;
2086 
2087  //
2088  // Convert byte offset to the sector offset
2089  //
2090 
2091  sectorOffset.QuadPart = byteOffset.QuadPart >> FdoExtension->SectorShift;
2092 
2093  //
2094  // Convert byte count to sector count.
2095  //
2096 
2097  sectorCount = verifyInfo->Length >> FdoExtension->SectorShift;
2098 
2099  //
2100  // Make sure that all previous verify requests have indeed completed
2101  // This greatly reduces the possibility of a Denial-of-Service attack
2102  //
2103 
2104  KeWaitForMutexObject(&DiskData->VerifyMutex,
2105  Executive,
2106  KernelMode,
2107  FALSE,
2108  NULL);
2109 
2110  //
2111  // Initialize SCSI SRB for a verify CDB
2112  //
2113  if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2115  srbEx = (PSTORAGE_REQUEST_BLOCK)Srb;
2116 
2117  //
2118  // Set up STORAGE_REQUEST_BLOCK fields
2119  //
2120 
2121  srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
2122  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
2123  srbEx->Signature = SRB_SIGNATURE;
2124  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
2125  srbEx->SrbLength = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
2126  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
2127  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
2128  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
2129  srbEx->NumSrbExData = 1;
2130 
2131  //
2132  // Set up address fields
2133  //
2134 
2135  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
2136  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
2137  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
2138 
2139  //
2140  // Set up SCSI SRB extended data fields
2141  //
2142 
2143  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
2144  sizeof(STOR_ADDR_BTL8);
2145  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
2146  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
2147  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
2148  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
2149 
2150  Cdb = (PCDB)srbExDataCdb16->Cdb;
2151  if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
2152  srbExDataCdb16->CdbLength = 16;
2153  Cdb->CDB16.OperationCode = SCSIOP_VERIFY16;
2154  } else {
2155  srbExDataCdb16->CdbLength = 10;
2156  Cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2157  }
2158  } else {
2159  // Should not happen
2160  NT_ASSERT(FALSE);
2161 
2162  FREE_POOL(Srb);
2163  FREE_POOL(WorkContext);
2165  }
2166 
2167  } else {
2169 
2170  Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
2171  Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2172 
2173  Cdb = (PCDB)Srb->Cdb;
2174  if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
2175  Srb->CdbLength = 16;
2176  Cdb->CDB16.OperationCode = SCSIOP_VERIFY16;
2177  } else {
2178  Srb->CdbLength = 10;
2179  Cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2180  }
2181 
2182  }
2183 
2184  while (NT_SUCCESS(status) && (sectorCount != 0)) {
2185 
2187 
2188  if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2189 
2190  //
2191  // Reset status fields
2192  //
2193 
2194  srbEx->SrbStatus = 0;
2195  srbExDataCdb16->ScsiStatus = 0;
2196 
2197  //
2198  // Calculate the request timeout value based
2199  // on the number of sectors being verified
2200  //
2201 
2202  srbEx->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue;
2203  } else {
2204 
2205  //
2206  // Reset status fields
2207  //
2208 
2209  Srb->SrbStatus = 0;
2210  Srb->ScsiStatus = 0;
2211 
2212  //
2213  // Calculate the request timeout value based
2214  // on the number of sectors being verified
2215  //
2216 
2217  Srb->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue;
2218  }
2219 
2220  //
2221  // Update verify CDB info.
2222  // NOTE - CDB opcode and length has been initialized prior to entering
2223  // the while loop
2224  //
2225 
2226  if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
2227 
2228  REVERSE_BYTES_QUAD(&Cdb->CDB16.LogicalBlock, &sectorOffset);
2229  REVERSE_BYTES_SHORT(&Cdb->CDB16.TransferLength[2], &numSectors);
2230  } else {
2231 
2232  //
2233  // Move little endian values into CDB in big endian format
2234  //
2235 
2236  Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2237  Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2238  Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2239  Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2240 
2241  Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numSectors)->Byte1;
2242  Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numSectors)->Byte0;
2243  }
2244 
2246  Srb,
2247  NULL,
2248  0,
2249  FALSE);
2250 
2252 
2253  sectorCount -= numSectors;
2254  sectorOffset.QuadPart += numSectors;
2255  }
2256 
2257  KeReleaseMutex(&DiskData->VerifyMutex, FALSE);
2258 
2259  Irp->IoStatus.Status = status;
2260  Irp->IoStatus.Information = 0;
2261 
2264 
2265  FREE_POOL(Srb);
2266  FREE_POOL(WorkContext);
2267 }
2268 
2269 
2270 VOID
2271 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2275  NTSTATUS *Status,
2276  BOOLEAN *Retry
2277  )
2278 
2279 /*++
2280 
2281 Routine Description:
2282 
2283  This routine checks the type of error. If the error indicates an underrun
2284  then indicate the request should be retried.
2285 
2286 Arguments:
2287 
2288  Fdo - Supplies a pointer to the functional device object.
2289 
2290  Srb - Supplies a pointer to the failing Srb.
2291 
2292  Status - Status with which the IRP will be completed.
2293 
2294  Retry - Indication of whether the request will be retried.
2295 
2296 Return Value:
2297 
2298  None.
2299 
2300 --*/
2301 
2302 {
2303  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2304  PSTORAGE_REQUEST_BLOCK srbEx;
2305  PCDB cdb = NULL;
2306  UCHAR scsiStatus = 0;
2307  UCHAR senseBufferLength = 0;
2308  PVOID senseBuffer = NULL;
2309  CDB noOp = {0};
2310 
2311  //
2312  // Get relevant fields from SRB
2313  //
2314  if (Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) {
2315 
2316  srbEx = (PSTORAGE_REQUEST_BLOCK)Srb;
2317 
2318  //
2319  // Look for SCSI SRB specific fields
2320  //
2321  if ((srbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI) &&
2322  (srbEx->NumSrbExData > 0)) {
2323  cdb = GetSrbScsiData(srbEx, NULL, NULL, &scsiStatus, &senseBuffer, &senseBufferLength);
2324 
2325  //
2326  // cdb and sense buffer should not be NULL
2327  //
2328  NT_ASSERT(cdb != NULL);
2329  NT_ASSERT(senseBuffer != NULL);
2330 
2331  }
2332 
2333  if (cdb == NULL) {
2334 
2335  //
2336  // Use a cdb that is all 0s
2337  //
2338  cdb = &noOp;
2339  }
2340 
2341  } else {
2342 
2343  cdb = (PCDB)(Srb->Cdb);
2344  scsiStatus = Srb->ScsiStatus;
2345  senseBufferLength = Srb->SenseInfoBufferLength;
2346  senseBuffer = Srb->SenseInfoBuffer;
2347  }
2348 
2349  if (*Status == STATUS_DATA_OVERRUN &&
2350  (cdb != NULL) &&
2351  (IS_SCSIOP_READWRITE(cdb->CDB10.OperationCode))) {
2352 
2353  *Retry = TRUE;
2354 
2355  //
2356  // Update the error count for the device.
2357  //
2358 
2359  fdoExtension->ErrorCount++;
2360 
2361  } else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
2362  scsiStatus == SCSISTAT_BUSY) {
2363 
2364  //
2365  // a disk drive should never be busy this long. Reset the scsi bus
2366  // maybe this will clear the condition.
2367  //
2368 
2369  ResetBus(Fdo);
2370 
2371  //
2372  // Update the error count for the device.
2373  //
2374 
2375  fdoExtension->ErrorCount++;
2376 
2377  } else {
2378 
2379  BOOLEAN invalidatePartitionTable = FALSE;
2380 
2381  //
2382  // See if this might indicate that something on the drive has changed.
2383  //
2384 
2385  if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
2386  (senseBuffer != NULL) && (cdb != NULL)) {
2387 
2389  UCHAR senseKey = 0;
2390  UCHAR asc = 0;
2391  UCHAR ascq = 0;
2392 
2393  validSense = ScsiGetSenseKeyAndCodes(senseBuffer,
2394  senseBufferLength,
2396  &senseKey,
2397  &asc,
2398  &ascq);
2399 
2400  if (validSense) {
2401 
2402  switch (senseKey) {
2403 
2405 
2406  switch (asc) {
2407 
2409  {
2410  //
2411  // Look to see if this is an Io request with the ForceUnitAccess flag set
2412  //
2413  if (((cdb->CDB10.OperationCode == SCSIOP_WRITE) ||
2414  (cdb->CDB10.OperationCode == SCSIOP_WRITE16)) &&
2415  (cdb->CDB10.ForceUnitAccess))
2416  {
2417  PDISK_DATA diskData = (PDISK_DATA)fdoExtension->CommonExtension.DriverData;
2418 
2420  {
2421  PIO_ERROR_LOG_PACKET logEntry = NULL;
2422 
2423  //
2424  // The user has explicitly requested that write caching be turned on.
2425  // Warn the user that writes with FUA enabled are not working and that
2426  // they should disable write cache.
2427  //
2428 
2429  logEntry = IoAllocateErrorLogEntry(fdoExtension->DeviceObject,
2430  sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG)));
2431 
2432  if (logEntry != NULL)
2433  {
2434  logEntry->FinalStatus = *Status;
2436  logEntry->SequenceNumber = 0;
2437  logEntry->MajorFunctionCode = IRP_MJ_SCSI;
2438  logEntry->IoControlCode = 0;
2439  logEntry->RetryCount = 0;
2440  logEntry->UniqueErrorValue = 0;
2441  logEntry->DumpDataSize = 4 * sizeof(ULONG);
2442 
2443  logEntry->DumpData[0] = diskData->ScsiAddress.PortNumber;
2444  logEntry->DumpData[1] = diskData->ScsiAddress.PathId;
2445  logEntry->DumpData[2] = diskData->ScsiAddress.TargetId;
2446  logEntry->DumpData[3] = diskData->ScsiAddress.Lun;
2447 
2448  //
2449  // Write the error log packet.
2450  //
2451 
2452  IoWriteErrorLogEntry(logEntry);
2453  }
2454  }
2455  else
2456  {
2457  //
2458  // Turn off write caching on this device. This is so that future
2459  // critical requests need not be sent down with ForceUnitAccess
2460  //
2461  PIO_WORKITEM workItem = IoAllocateWorkItem(Fdo);
2462 
2463  if (workItem)
2464  {
2465  IoQueueWorkItem(workItem, DisableWriteCache, CriticalWorkQueue, workItem);
2466  }
2467  }
2468 
2470  ADJUST_FUA_FLAG(fdoExtension);
2471 
2472 
2473  cdb->CDB10.ForceUnitAccess = FALSE;
2474  *Retry = TRUE;
2475 
2476  } else if ((cdb->CDB6FORMAT.OperationCode == SCSIOP_MODE_SENSE) &&
2477  (cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL)) {
2478 
2479  //
2480  // Mode sense for all pages failed. This command could fail with
2481  // SCSI_SENSE_ILLEGAL_REQUEST / SCSI_ADSENSE_INVALID_CDB if the data
2482  // to be returned is more than 256 bytes. In which case, try to get
2483  // only MODE_PAGE_CACHING since we only need the block descriptor.
2484  //
2485  // Simply change the page code and retry the request
2486  //
2487 
2488  cdb->MODE_SENSE.PageCode = MODE_PAGE_CACHING;
2489  *Retry = TRUE;
2490  }
2491 
2492  break;
2493  }
2494  } // end switch(asc)
2495  break;
2496  }
2497 
2498  case SCSI_SENSE_NOT_READY: {
2499 
2500  switch (asc) {
2502  switch (ascq) {
2506  invalidatePartitionTable = TRUE;
2507  break;
2508  }
2509  } // end switch(ascq)
2510  break;
2511  }
2512 
2514  invalidatePartitionTable = TRUE;
2515  break;
2516  }
2517  } // end switch(asc)
2518  break;
2519  }
2520 
2521  case SCSI_SENSE_MEDIUM_ERROR: {
2522  invalidatePartitionTable = TRUE;
2523  break;
2524  }
2525 
2527  invalidatePartitionTable = TRUE;
2528  break;
2529  }
2530 
2532  {
2533  invalidatePartitionTable = TRUE;
2534  break;
2535  }
2536 
2538  invalidatePartitionTable = TRUE;
2539  break;
2540  }
2541 
2542  } // end switch(senseKey)
2543  } // end if (validSense)
2544  } else {
2545 
2546  //
2547  // On any exceptional scsi condition which might indicate that the
2548  // device was changed we will flush out the state of the partition
2549  // table.
2550  //
2551 
2552  switch (SRB_STATUS(Srb->SrbStatus)) {
2555  case SRB_STATUS_NO_DEVICE:
2556  case SRB_STATUS_NO_HBA:
2559  case SRB_STATUS_TIMEOUT:
2564  {
2565  invalidatePartitionTable = TRUE;
2566  break;
2567  }
2568 
2569  case SRB_STATUS_ERROR:
2570  {
2571  if (scsiStatus == SCSISTAT_RESERVATION_CONFLICT)
2572  {
2573  invalidatePartitionTable = TRUE;
2574  }
2575 
2576  break;
2577  }
2578  } // end switch(Srb->SrbStatus)
2579  }
2580 
2581  if (invalidatePartitionTable && TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
2582 
2583  //
2584  // Inform the upper layers that the volume
2585  // on this disk is in need of verification
2586  //
2587 
2588  SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME);
2589  }
2590  }
2591 
2592  return;
2593 }
2594 
2595 
2596 VOID
2597 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2600  IN ULONG_PTR Data
2601  )
2602 
2603 /*++
2604 
2605 Routine Description:
2606 
2607  This function checks to see if an SCSI logical unit requires speical
2608  flags to be set.
2609 
2610 Arguments:
2611 
2612  Fdo - Supplies the device object to be tested.
2613 
2614  InquiryData - Supplies the inquiry data returned by the device of interest.
2615 
2616  AdapterDescriptor - Supplies the capabilities of the device object.
2617 
2618 Return Value:
2619 
2620  None.
2621 
2622 --*/
2623 
2624 {
2625  PDEVICE_OBJECT fdo = FdoExtension->DeviceObject;
2626 
2627  PAGED_CODE();
2628 
2629  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "Disk SetSpecialHacks, Setting Hacks %p\n", (void*) Data));
2630 
2631  //
2632  // Found a listed controller. Determine what must be done.
2633  //
2634 
2636 
2637  //
2638  // Disable tagged queuing.
2639  //
2640 
2642  }
2643 
2645 
2646  //
2647  // Disable synchronous data transfers.
2648  //
2649 
2651 
2652  }
2653 
2655 
2656  //
2657  // Disable spinning down of drives.
2658  //
2659 
2660  SET_FLAG(FdoExtension->ScanForSpecialFlags,
2662 
2663  }
2664 
2666 
2667  //
2668  // Disable the drive's write cache
2669  //
2670 
2671  SET_FLAG(FdoExtension->ScanForSpecialFlags,
2673 
2674  }
2675 
2677 
2678  SET_FLAG(FdoExtension->ScanForSpecialFlags,
2680  }
2681 
2682  if (TEST_FLAG(fdo->Characteristics, FILE_REMOVABLE_MEDIA) &&
2684  ) {
2685 
2686  //
2687  // this is a list of vendors who require the START_UNIT command
2688  //
2689 
2690  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DiskScanForSpecial (%p) => This unit requires "
2691  " START_UNITS\n", fdo));
2692  SET_FLAG(FdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
2693 
2694  }
2695 
2696  return;
2697 }
2698 
2699 
2700 VOID
2703  )
2704 
2705 /*++
2706 
2707 Routine Description:
2708 
2709  This command sends a reset bus command to the SCSI port driver.
2710 
2711 Arguments:
2712 
2713  Fdo - The functional device object for the logical unit with hardware problem.
2714 
2715 Return Value:
2716 
2717  None.
2718 
2719 --*/
2720 
2721 {
2722  PIO_STACK_LOCATION irpStack;
2723  PIRP irp;
2724 
2725  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2726  PSCSI_REQUEST_BLOCK srb;
2728  PSTORAGE_REQUEST_BLOCK srbEx = NULL;
2729  PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
2730 
2731  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "Disk ResetBus: Sending reset bus request to port driver.\n"));
2732 
2733  //
2734  // Allocate Srb from nonpaged pool.
2735  //
2736 
2737  context = ExAllocatePoolWithTag(NonPagedPoolNx,
2738  sizeof(COMPLETION_CONTEXT),
2740 
2741  if(context == NULL) {
2742  return;
2743  }
2744 
2745  //
2746  // Save the device object in the context for use by the completion
2747  // routine.
2748  //
2749 
2750  context->DeviceObject = Fdo;
2751  srb = &context->Srb.Srb;
2752 
2753  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2754  srbEx = &context->Srb.SrbEx;
2755 
2756  //
2757  // Zero out srb
2758  //
2759 
2760  RtlZeroMemory(srbEx, sizeof(context->Srb.SrbExBuffer));
2761 
2762  //
2763  // Set up STORAGE_REQUEST_BLOCK fields
2764  //
2765 
2766  srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
2767  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
2768  srbEx->Signature = SRB_SIGNATURE;
2769  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
2770  srbEx->SrbLength = sizeof(context->Srb.SrbExBuffer);
2771  srbEx->SrbFunction = SRB_FUNCTION_RESET_BUS;
2772  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
2773 
2774  //
2775  // Set up address fields
2776  //
2777 
2778  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
2779  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
2780  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
2781 
2782  } else {
2783 
2784  //
2785  // Zero out srb.
2786  //
2787 
2789 
2790  //
2791  // Write length to SRB.
2792  //
2793 
2795 
2797 
2798  }
2799 
2800  //
2801  // Build the asynchronous request to be sent to the port driver.
2802  // Since this routine is called from a DPC the IRP should always be
2803  // available.
2804  //
2805 
2806  irp = IoAllocateIrp(Fdo->StackSize, FALSE);
2807 
2808  if (irp == NULL) {
2809  FREE_POOL(context);
2810  return;
2811  }
2812 
2814 
2817  context,
2818  TRUE,
2819  TRUE,
2820  TRUE);
2821 
2822  irpStack = IoGetNextIrpStackLocation(irp);
2823 
2824  irpStack->MajorFunction = IRP_MJ_SCSI;
2825 
2826  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2827  srbEx->RequestPriority = IoGetIoPriorityHint(irp);
2828  srbEx->OriginalRequest = irp;
2829  } else {
2830  srb->OriginalRequest = irp;
2831  }
2832 
2833  //
2834  // Store the SRB address in next stack for port driver.
2835  //
2836 
2837  irpStack->Parameters.Scsi.Srb = srb;
2838 
2839  //
2840  // Call the port driver with the IRP.
2841  //
2842 
2843  IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
2844 
2845  return;
2846 
2847 } // end ResetBus()
2848 
2849 
2850 
2851 VOID
2854  IN PDISK_CACHE_INFORMATION CacheInfo,
2856  )
2857 {
2858  PIO_ERROR_LOG_PACKET logEntry = NULL;
2859 
2860  PAGED_CODE();
2861 
2862  logEntry = IoAllocateErrorLogEntry(FdoExtension->DeviceObject, sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG)));
2863 
2864  if (logEntry != NULL)
2865  {
2866  PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
2867  BOOLEAN bIsEnabled = TEST_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
2868 
2869  logEntry->FinalStatus = Status;
2870  logEntry->ErrorCode = (bIsEnabled) ? IO_WRITE_CACHE_ENABLED : IO_WRITE_CACHE_DISABLED;
2871  logEntry->SequenceNumber = 0;
2872  logEntry->MajorFunctionCode = IRP_MJ_SCSI;
2873  logEntry->IoControlCode = 0;
2874  logEntry->RetryCount = 0;
2875  logEntry->UniqueErrorValue = 0x1;
2876  logEntry->DumpDataSize = 4 * sizeof(ULONG);
2877 
2878  logEntry->DumpData[0] = diskData->ScsiAddress.PathId;
2879  logEntry->DumpData[1] = diskData->ScsiAddress.TargetId;
2880  logEntry->DumpData[2] = diskData->ScsiAddress.Lun;
2881  logEntry->DumpData[3] = CacheInfo->WriteCacheEnabled;
2882 
2883  //
2884  // Write the error log packet.
2885  //
2886 
2887  IoWriteErrorLogEntry(logEntry);
2888  }
2889 }
2890 
2891 NTSTATUS
2894  IN PMODE_INFO_EXCEPTIONS ReturnPageData
2895  )
2896 {
2897  PMODE_PARAMETER_HEADER modeData;
2898  PMODE_INFO_EXCEPTIONS pageData;
2899  ULONG length;
2900 
2901  NTSTATUS status;
2902 
2903  PAGED_CODE();
2904 
2905  //
2906  // ReturnPageData is allocated by the caller
2907  //
2908 
2909  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
2912 
2913  if (modeData == NULL) {
2914 
2915  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Unable to allocate mode "
2916  "data buffer\n"));
2918  }
2919 
2920  RtlZeroMemory(modeData, MODE_DATA_SIZE);
2921 
2922  length = ClassModeSense(FdoExtension->DeviceObject,
2923  (PCHAR) modeData,
2926 
2927  if (length < sizeof(MODE_PARAMETER_HEADER)) {
2928 
2929  //
2930  // Retry the request in case of a check condition.
2931  //
2932 
2933  length = ClassModeSense(FdoExtension->DeviceObject,
2934  (PCHAR) modeData,
2937 
2938  if (length < sizeof(MODE_PARAMETER_HEADER)) {
2939  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Mode Sense failed\n"));
2940  FREE_POOL(modeData);
2941  return STATUS_IO_DEVICE_ERROR;
2942  }
2943  }
2944 
2945  //
2946  // If the length is greater than length indicated by the mode data reset
2947  // the data to the mode data.
2948  //
2949 
2950  if (length > (ULONG) (modeData->ModeDataLength + 1)) {
2951  length = modeData->ModeDataLength + 1;
2952  }
2953 
2954  //
2955  // Find the mode page for info exceptions
2956  //
2957 
2958  pageData = ClassFindModePage((PCHAR) modeData,
2959  length,
2961  TRUE);
2962 
2963  if (pageData != NULL) {
2964  RtlCopyMemory(ReturnPageData, pageData, sizeof(MODE_INFO_EXCEPTIONS));
2966  } else {
2968  }
2969 
2970  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: %s support SMART for device %p\n",
2971  NT_SUCCESS(status) ? "does" : "does not",
2972  FdoExtension->DeviceObject));
2973 
2974  FREE_POOL(modeData);
2975 
2976  return(status);
2977 }
2978 
2979 
2980 NTSTATUS
2983  IN PMODE_INFO_EXCEPTIONS PageData
2984  )
2985 
2986 {
2987  ULONG i;
2989 
2990  PAGED_CODE();
2991 
2992  //
2993  // We will attempt (twice) to issue the mode select with the page.
2994  // Make the setting persistant so that we don't have to turn it back
2995  // on after a bus reset.
2996  //
2997 
2998  for (i = 0; i < 2; i++)
2999  {
3000  status = DiskModeSelect(FdoExtension->DeviceObject,
3001  (PCHAR) PageData,
3002  sizeof(MODE_INFO_EXCEPTIONS),
3003  TRUE);
3004  }
3005 
3006  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskSetInfoExceptionInformation: %s for device %p\n",
3007  NT_SUCCESS(status) ? "succeeded" : "failed",
3008  FdoExtension->DeviceObject));
3009 
3010  return status;
3011 }
3012 
3013 NTSTATUS
3014 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3017  IN PDISK_CACHE_INFORMATION CacheInfo
3018  )
3019 /*++
3020 
3021 Routine Description:
3022 
3023  This function gets the caching mode page from the drive. This function
3024  is called from DiskIoctlGetCacheInformation() in response to the IOCTL
3025  IOCTL_DISK_GET_CACHE_INFORMATION. This is also called from the
3026  DisableWriteCache() worker thread to disable caching when write commands fail.
3027 
3028 Arguments:
3029 
3030  FdoExtension - The device extension for this device.
3031 
3032  CacheInfo - Buffer to receive the Cache Information.
3033 
3034 Return Value:
3035 
3036  NTSTATUS code
3037 
3038 --*/
3039 
3040 {
3041  PMODE_PARAMETER_HEADER modeData;
3042  PMODE_CACHING_PAGE pageData;
3043 
3044  ULONG length;
3045 
3046  PAGED_CODE();
3047 
3048 
3049 
3050  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
3053 
3054  if (modeData == NULL) {
3055 
3056  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetSetCacheInformation: Unable to allocate mode "
3057  "data buffer\n"));
3059  }
3060 
3061  RtlZeroMemory(modeData, MODE_DATA_SIZE);
3062 
3063  length = ClassModeSense(FdoExtension->DeviceObject,
3064  (PCHAR) modeData,
3067 
3068  if (length < sizeof(MODE_PARAMETER_HEADER)) {
3069 
3070  //
3071  // Retry the request in case of a check condition.
3072  //
3073 
3074  length = ClassModeSense(FdoExtension->DeviceObject,
3075  (PCHAR) modeData,
3078 
3079  if (length < sizeof(MODE_PARAMETER_HEADER)) {
3080 
3081  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetCacheInformation: Mode Sense failed\n"));
3082 
3083  FREE_POOL(modeData);
3084  return STATUS_IO_DEVICE_ERROR;
3085  }
3086  }
3087 
3088  //
3089  // If the length is greater than length indicated by the mode data reset
3090  // the data to the mode data.
3091  //
3092 
3093  if (length > (ULONG) (modeData->ModeDataLength + 1)) {
3094  length = modeData->ModeDataLength + 1;
3095  }
3096 
3097  //
3098  // Check to see if the write cache is enabled.
3099  //
3100 
3101  pageData = ClassFindModePage((PCHAR) modeData,
3102  length,
3104  TRUE);
3105 
3106  //
3107  // Check if valid caching page exists.
3108  //
3109 
3110  if (pageData == NULL) {
3111  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetCacheInformation: Unable to find caching mode page.\n"));
3112  FREE_POOL(modeData);
3113  return STATUS_NOT_SUPPORTED;
3114  }
3115 
3116  //
3117  // Copy the parameters over.
3118  //
3119 
3120  RtlZeroMemory(CacheInfo, sizeof(DISK_CACHE_INFORMATION));
3121 
3122  CacheInfo->ParametersSavable = pageData->PageSavable;
3123 
3124  CacheInfo->ReadCacheEnabled = !(pageData->ReadDisableCache);
3125  CacheInfo->WriteCacheEnabled = pageData->WriteCacheEnable;
3126 
3127 
3128  //
3129  // Translate the values in the mode page into the ones defined in
3130  // ntdddisk.h.
3131  //
3132 
3133  CacheInfo->ReadRetentionPriority =
3135  CacheInfo->WriteRetentionPriority =
3137 
3138  CacheInfo->DisablePrefetchTransferLength =
3139  ((pageData->DisablePrefetchTransfer[0] << 8) +
3140  pageData->DisablePrefetchTransfer[1]);
3141 
3142  CacheInfo->ScalarPrefetch.Minimum =
3143  ((pageData->MinimumPrefetch[0] << 8) + pageData->MinimumPrefetch[1]);
3144 
3145  CacheInfo->ScalarPrefetch.Maximum =
3146  ((pageData->MaximumPrefetch[0] << 8) + pageData->MaximumPrefetch[1]);
3147 
3148  if(pageData->MultiplicationFactor) {
3149  CacheInfo->PrefetchScalar = TRUE;
3150  CacheInfo->ScalarPrefetch.MaximumBlocks =
3151  ((pageData->MaximumPrefetchCeiling[0] << 8) +
3152  pageData->MaximumPrefetchCeiling[1]);
3153  }
3154 
3155 
3156  FREE_POOL(modeData);
3157  return STATUS_SUCCESS;
3158 }
3159 
3160 
3161 NTSTATUS
3162 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3165  IN PDISK_CACHE_INFORMATION CacheInfo
3166  )
3167 /*++
3168 
3169 Routine Description:
3170 
3171  This function sets the caching mode page in the drive. This function
3172  is also called from the DisableWriteCache() worker thread to disable
3173  caching when write commands fail.
3174 
3175 Arguments:
3176 
3177  FdoExtension - The device extension for this device.
3178 
3179  CacheInfo - Buffer the contains the Cache Information to be set on the drive.
3180 
3181 Return Value:
3182 
3183  NTSTATUS code
3184 
3185 --*/
3186 {
3187  PMODE_PARAMETER_HEADER modeData;
3188  ULONG length;
3189  PMODE_CACHING_PAGE pageData;
3190  ULONG i;
3192 
3193  PAGED_CODE();
3194 
3195  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
3198 
3199  if (modeData == NULL) {
3200 
3201  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Unable to allocate mode "
3202  "data buffer\n"));
3204  }
3205 
3206  RtlZeroMemory(modeData, MODE_DATA_SIZE);
3207 
3208  length = ClassModeSense(FdoExtension->DeviceObject,
3209  (PCHAR) modeData,
3212 
3213  if (length < sizeof(MODE_PARAMETER_HEADER)) {
3214 
3215  //
3216  // Retry the request in case of a check condition.
3217  //
3218 
3219  length = ClassModeSense(FdoExtension->DeviceObject,
3220  (PCHAR) modeData,
3223 
3224  if (length < sizeof(MODE_PARAMETER_HEADER)) {
3225 
3226  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Mode Sense failed\n"));
3227 
3228  FREE_POOL(modeData);
3229  return STATUS_IO_DEVICE_ERROR;
3230  }
3231  }
3232 
3233  //
3234  // If the length is greater than length indicated by the mode data reset
3235  // the data to the mode data.
3236  //
3237 
3238  if (length > (ULONG) (modeData->ModeDataLength + 1)) {
3239  length = modeData->ModeDataLength + 1;
3240  }
3241 
3242  //
3243  // Check to see if the write cache is enabled.
3244  //
3245 
3246  pageData = ClassFindModePage((PCHAR) modeData,
3247  length,
3249  TRUE);
3250 
3251  //
3252  // Check if valid caching page exists.
3253  //
3254 
3255  if (pageData == NULL) {
3256  FREE_POOL(modeData);
3257  return STATUS_NOT_SUPPORTED;
3258  }
3259 
3260  //
3261  // Don't touch any of the normal parameters - not all drives actually
3262  // use the correct size of caching mode page. Just change the things
3263  // which the user could have modified.
3264  //
3265 
3266  pageData->PageSavable = FALSE;
3267 
3268  pageData->ReadDisableCache = !(CacheInfo->ReadCacheEnabled);
3269  pageData->MultiplicationFactor = CacheInfo->PrefetchScalar;
3270  pageData->WriteCacheEnable = CacheInfo->WriteCacheEnabled;
3271 
3272  pageData->WriteRetensionPriority = (UCHAR)
3273  TRANSLATE_RETENTION_PRIORITY(CacheInfo->WriteRetentionPriority);
3274  pageData->ReadRetensionPriority = (UCHAR)
3275  TRANSLATE_RETENTION_PRIORITY(CacheInfo->ReadRetentionPriority);
3276 
3277  pageData->DisablePrefetchTransfer[0] =
3278  (UCHAR) (CacheInfo->DisablePrefetchTransferLength >> 8);
3279  pageData->DisablePrefetchTransfer[1] =
3280  (UCHAR) (CacheInfo->DisablePrefetchTransferLength & 0x00ff);
3281 
3282  pageData->MinimumPrefetch[0] =
3283  (UCHAR) (CacheInfo->ScalarPrefetch.Minimum >> 8);
3284  pageData->MinimumPrefetch[1] =
3285  (UCHAR) (CacheInfo->ScalarPrefetch.Minimum & 0x00ff);
3286 
3287  pageData->MaximumPrefetch[0] =
3288  (UCHAR) (CacheInfo->ScalarPrefetch.Maximum >> 8);
3289  pageData->MaximumPrefetch[1] =
3290  (UCHAR) (CacheInfo->ScalarPrefetch.Maximum & 0x00ff);
3291 
3292  if(pageData->MultiplicationFactor) {
3293 
3294  pageData->MaximumPrefetchCeiling[0] =
3295  (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks >> 8);
3296  pageData->MaximumPrefetchCeiling[1] =
3297  (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks & 0x00ff);
3298  }
3299 
3300  //
3301  // We will attempt (twice) to issue the mode select with the page.
3302  //
3303 
3304  for (i = 0; i < 2; i++) {
3305 
3306  status = DiskModeSelect(FdoExtension->DeviceObject,
3307  (PCHAR) pageData,
3308  (pageData->PageLength + 2),
3309  CacheInfo->ParametersSavable);
3310 
3311  if (NT_SUCCESS(status)) {
3312 
3313  if (CacheInfo->WriteCacheEnabled)
3314  {
3315  SET_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3316  }
3317  else
3318  {
3319  CLEAR_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3320  }
3322 
3323  break;
3324  }
3325  }
3326 
3327  if (NT_SUCCESS(status))
3328  {
3329  } else {
3330 
3331  //
3332  // We were unable to modify the disk write cache setting
3333  //
3334 
3336  }
3337 
3338  FREE_POOL(modeData);
3339  return status;
3340 }
3341 
3342 NTSTATUS
3345  IN PIRP Irp
3346  )
3347 
3348 /*++
3349 
3350 Routine description:
3351 
3352  This routine services IOCTL_DISK_GET_CACHE_SETTING. It looks to
3353  see if there are any issues with the disk cache and whether the
3354  user had previously indicated that the cache is power-protected
3355 
3356 Arguments:
3357 
3358  Fdo - The functional device object processing the request
3359  Irp - The ioctl to be processed
3360 
3361 Return Value:
3362 
3363  STATUS_SUCCESS if successful, an error code otherwise
3364 
3365 --*/
3366 
3367 {
3368  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3371 
3372  PAGED_CODE();
3373 
3374  if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_SETTING))
3375  {
3377  }
3378  else
3379  {
3380  PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer;
3381 
3382  cacheSetting->Version = sizeof(DISK_CACHE_SETTING);
3383  cacheSetting->State = DiskCacheNormal;
3384 
3385  //
3386  // Determine whether it is safe to turn on the cache
3387  //
3389  {
3390  cacheSetting->State = DiskCacheWriteThroughNotSupported;
3391  }
3392 
3393  //
3394  // Determine whether it is possible to modify the cache setting
3395  //
3397  {
3398  cacheSetting->State = DiskCacheModifyUnsuccessful;
3399  }
3400 
3401  cacheSetting->IsPowerProtected = TEST_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
3402 
3403  Irp->IoStatus.Information = sizeof(DISK_CACHE_SETTING);
3404  }
3405 
3406  return status;
3407 }
3408 
3409 
3410 NTSTATUS
3413  IN PIRP Irp
3414  )
3415 
3416 /*++
3417 
3418 Routine description:
3419 
3420  This routine services IOCTL_DISK_SET_CACHE_SETTING. It allows
3421  the user to specify whether the disk cache is power-protected
3422  or not
3423 
3424  This function must be called at IRQL < DISPATCH_LEVEL.
3425 
3426 Arguments:
3427 
3428  Fdo - The functional device object processing the request
3429  Irp - The ioctl to be processed
3430 
3431 Return Value:
3432 
3433  STATUS_SUCCESS if successful, an error code otherwise
3434 
3435 --*/
3436 
3437 {
3438  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3441 
3442  //
3443  // This function must be called at less than dispatch level.
3444  // Fail if IRQL >= DISPATCH_LEVEL.
3445  //
3446  PAGED_CODE();
3447  CHECK_IRQL();
3448 
3449  if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_SETTING))
3450  {
3452  }
3453  else
3454  {
3455  PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer;
3456 
3457  if (cacheSetting->Version == sizeof(DISK_CACHE_SETTING))
3458  {
3459  ULONG isPowerProtected;
3460 
3461  //
3462  // Save away the user-defined override in our extension and the registry
3463  //
3464  if (cacheSetting->IsPowerProtected)
3465  {
3466  SET_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
3467  isPowerProtected = 1;
3468  }
3469  else
3470  {
3471  CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
3472  isPowerProtected = 0;
3473  }
3474  ADJUST_FUA_FLAG(fdoExtension);
3475 
3476  ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey, DiskDeviceCacheIsPowerProtected, isPowerProtected);
3477  }
3478  else
3479  {
3481  }
3482  }
3483 
3484  return status;
3485 }
3486 
3487 NTSTATUS
3490  IN OUT PIRP Irp
3491  )
3492 
3493 /*++
3494 
3495 Routine Description:
3496 
3497  This routine services IOCTL_DISK_GET_LENGTH_INFO. It returns
3498  the disk geometry to the caller.
3499 
3500  This function must be called at IRQL < DISPATCH_LEVEL.
3501 
3502 Arguments:
3503 
3504  DeviceObject - Supplies the device object associated with this request.
3505 
3506  Irp - The IRP to be processed
3507 
3508 Return Value:
3509 
3510  NTSTATUS code
3511 
3512 --*/
3513 
3514 {
3515  NTSTATUS status;
3516  PIO_STACK_LOCATION irpStack;
3517  PGET_LENGTH_INFORMATION lengthInfo;
3518  PFUNCTIONAL_DEVICE_EXTENSION p0Extension;
3519  PCOMMON_DEVICE_EXTENSION commonExtension;
3520  PDISK_DATA partitionZeroData;
3521  NTSTATUS oldReadyStatus;
3522 
3523  //
3524  // This function must be called at less than dispatch level.
3525  // Fail if IRQL >= DISPATCH_LEVEL.
3526  //
3527  PAGED_CODE();
3528  CHECK_IRQL();
3529 
3530  //
3531  // Initialization
3532  //
3533 
3534  commonExtension = DeviceObject->DeviceExtension;
3535  irpStack = IoGetCurrentIrpStackLocation(Irp);
3536  p0Extension = commonExtension->PartitionZeroExtension;
3537  partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData);
3538 
3539  //
3540  // Check that the buffer is large enough.
3541  //
3542 
3543  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_LENGTH_INFORMATION)) {
3544  return STATUS_BUFFER_TOO_SMALL;
3545  }
3546 
3547  //
3548  // Update the geometry in case it has changed
3549  //
3550 
3551  status = DiskReadDriveCapacity(p0Extension->DeviceObject);
3552 
3553  //
3554  // Note whether the drive is ready. If the status has changed then
3555  // notify pnp.
3556  //
3557 
3558  oldReadyStatus = InterlockedExchange(&(partitionZeroData->ReadyStatus), status);
3559 
3560  if(partitionZeroData->ReadyStatus != oldReadyStatus) {
3562  }
3563 
3564  if(!NT_SUCCESS(status)) {
3565  return status;
3566  }
3567  lengthInfo = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
3568 
3569  lengthInfo->Length = commonExtension->PartitionLength;
3570 
3572  Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
3573 
3574  return status;
3575 }
3576 
3577 NTSTATUS
3580  IN OUT PIRP Irp
3581  )
3582 
3583 /*++
3584 
3585 Routine Description:
3586 
3587  This routine services IOCTL_DISK_GET_DRIVE_GEOMETRY. It returns
3588  the disk geometry to the caller.
3589 
3590  This function must be called at IRQL < DISPATCH_LEVEL.
3591 
3592 Arguments:
3593 
3594  DeviceObject - Supplies the device object associated with this request.
3595 
3596  Irp - IRP with a return buffer large enough to receive the
3597  extended geometry information.
3598 
3599 Return Value:
3600 
3601  NTSTATUS code
3602 
3603 --*/
3604 
3605 {
3606  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3607  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3608  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
3610  NTSTATUS status;
3611 
3612  //
3613  // This function must be called at less than dispatch level.
3614  // Fail if IRQL >= DISPATCH_LEVEL.
3615  //
3616  PAGED_CODE();
3617  CHECK_IRQL();
3618 
3619  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) {
3620 
3621  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetDriveGeometry: Output buffer too small.\n"));
3622  return STATUS_BUFFER_TOO_SMALL;
3623  }
3624 
3625  if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
3626 
3627  //
3628  // Issue ReadCapacity to update device extension
3629  // with information for current media.
3630  //
3631 
3632  status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
3633 
3634  //
3635  // Note whether the drive is ready.
3636  //
3637 
3638  diskData->ReadyStatus = status;
3639 
3640  if (!NT_SUCCESS(status)) {
3641  return status;
3642  }
3643  }
3644 
3645  //
3646  // Copy drive geometry information from device extension.
3647  //
3648 
3649  RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
3650  &(fdoExtension->DiskGeometry),
3651  sizeof(DISK_GEOMETRY));
3652 
3653  if (((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector == 0) {
3654  ((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector = 512;
3655  }
3656  Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
3657  return STATUS_SUCCESS;
3658 }
3659 
3666 
3667 NTSTATUS
3670  IN OUT PIRP Irp
3671  )
3672 
3673 /*++
3674 
3675 Routine Description:
3676 
3677  This routine services IOCTL_DISK_GET_DRIVE_GEOMETRY_EX. It returns
3678  the extended disk geometry to the caller.
3679 
3680  This function must be called at IRQL < DISPATCH_LEVEL.
3681 
3682 Arguments:
3683 
3684  DeviceObject - The device object to obtain the geometry for.
3685 
3686  Irp - IRP with a return buffer large enough to receive the
3687  extended geometry information.
3688 
3689 Return Value:
3690 
3691  NTSTATUS code
3692 
3693 --*/
3694 
3695 {
3696  NTSTATUS status;
3697  PIO_STACK_LOCATION irpStack;
3698  PCOMMON_DEVICE_EXTENSION commonExtension;
3699  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
3700  PDISK_DATA diskData;
3701  PDISK_GEOMETRY_EX_INTERNAL geometryEx;
3703 
3704  //
3705  // This function must be called at less than dispatch level.
3706  // Fail if IRQL >= DISPATCH_LEVEL.
3707  //
3708  PAGED_CODE();
3709  CHECK_IRQL();
3710 
3711  //
3712  // Setup parameters
3713  //
3714 
3715  commonExtension = DeviceObject->DeviceExtension;
3716  fdoExtension = DeviceObject->DeviceExtension;
3717  diskData = (PDISK_DATA)(commonExtension->DriverData);
3718  irpStack = IoGetCurrentIrpStackLocation ( Irp );
3719  geometryEx = NULL;
3720  OutputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
3721 
3722  //
3723  // Check that the buffer is large enough. It must be large enough
3724  // to hold at lest the Geometry and DiskSize fields of of the
3725  // DISK_GEOMETRY_EX structure.
3726  //
3727 
3729 
3730  //
3731  // Buffer too small. Bail out, telling the caller the required
3732  // size.
3733  //
3734 
3735  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetDriveGeometryEx: Output buffer too small.\n"));
3737  return status;
3738  }
3739 
3740  if (TEST_FLAG (DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
3741 
3742  //
3743  // Issue a ReadCapacity to update device extension
3744  // with information for the current media.
3745  //
3746 
3747  status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
3748 
3749  diskData->ReadyStatus = status;
3750 
3751  if (!NT_SUCCESS (status)) {
3752  return status;
3753  }
3754  }
3755 
3756  //
3757  // Copy drive geometry.
3758  //
3759 
3760  geometryEx = (PDISK_GEOMETRY_EX_INTERNAL)Irp->AssociatedIrp.SystemBuffer;
3761  geometryEx->Geometry = fdoExtension->DiskGeometry;
3762  if (geometryEx->Geometry.BytesPerSector == 0) {
3763  geometryEx->Geometry.BytesPerSector = 512;
3764  }
3765  geometryEx->DiskSize = commonExtension->PartitionZeroExtension->CommonExtension.PartitionLength;
3766 
3767  //
3768  // If the user buffer is large enough to hold the partition information
3769  // then add that as well.
3770  //
3771 
3773 
3774  geometryEx->Partition.SizeOfPartitionInfo = sizeof (geometryEx->Partition);
3775  geometryEx->Partition.PartitionStyle = diskData->PartitionStyle;
3776 
3777  switch ( diskData->PartitionStyle ) {
3778 
3779  case PARTITION_STYLE_GPT:
3780 
3781  //
3782  // Copy GPT signature.
3783  //
3784 
3785  geometryEx->Partition.Gpt.DiskId = diskData->Efi.DiskId;
3786  break;
3787 
3788  case PARTITION_STYLE_MBR:
3789 
3790  //
3791  // Copy MBR signature and checksum.
3792  //
3793 
3794  geometryEx->Partition.Mbr.Signature = diskData->Mbr.Signature;
3795  geometryEx->Partition.Mbr.CheckSum = diskData->Mbr.MbrCheckSum;
3796  break;
3797 
3798  default:
3799 
3800  //
3801  // This is a raw disk. Zero out the signature area so
3802  // nobody gets confused.
3803  //
3804 
3805  RtlZeroMemory(&geometryEx->Partition, sizeof (geometryEx->Partition));
3806  }
3807  }
3808 
3809  //
3810  // If the buffer is large enough to hold the detection information,
3811  // then also add that.
3812  //
3813 
3815 
3816  geometryEx->Detection.SizeOfDetectInfo = sizeof (geometryEx->Detection);
3817 
3818  status = DiskGetDetectInfo(fdoExtension, &geometryEx->Detection);
3819 
3820  //
3821  // Failed to obtain detection information, set to none.
3822  //
3823 
3824  if (!NT_SUCCESS (status)) {
3825  geometryEx->Detection.DetectionType = DetectNone;
3826  }
3827  }
3828 
3830  Irp->IoStatus.Information = min (OutputBufferLength, sizeof (DISK_GEOMETRY_EX_INTERNAL));
3831 
3832  return status;
3833 }
3834 
3835 NTSTATUS
3838  IN OUT PIRP Irp
3839  )
3840 
3841 /*++
3842 
3843 Routine Description:
3844 
3845  This routine services IOCTL_DISK_GET_CACHE_INFORMATION. It reads
3846  the caching mode page from the device and returns information to
3847  the caller. After validating the user parameter it calls the
3848  DiskGetCacheInformation() function to get the mode page.
3849 
3850  This function must be called at IRQL < DISPATCH_LEVEL.
3851 
3852 Arguments:
3853 
3854  DeviceObject - Supplies the device object associated with this request.
3855 
3856  Irp - The IRP to be processed
3857 
3858 Return Value:
3859 
3860  NTSTATUS code
3861 
3862 --*/
3863 
3864 {
3865  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3867  PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer;
3868  NTSTATUS status;
3869 
3870  //
3871  // This function must be called at less than dispatch level.
3872  // Fail if IRQL >= DISPATCH_LEVEL.
3873  //
3874  PAGED_CODE();
3875  CHECK_IRQL();
3876 
3877  //
3878  // Validate the request.
3879  //
3880 
3881  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetCacheInformation: DeviceObject %p Irp %p\n", DeviceObject, Irp));
3882 
3883  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_INFORMATION)) {
3884 
3885  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetCacheInformation: Output buffer too small.\n"));
3886  return STATUS_BUFFER_TOO_SMALL;
3887  }
3888 
3889  status = DiskGetCacheInformation(fdoExtension, cacheInfo);
3890 
3891  if (NT_SUCCESS(status)) {
3892  Irp->IoStatus.Information = sizeof(DISK_CACHE_INFORMATION);
3893 
3894  //
3895  // Make sure write cache setting is reflected in device extension
3896  //
3897  if (cacheInfo->WriteCacheEnabled)
3898  {
3899  SET_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3900  }
3901  else
3902  {
3903  CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3904  }
3905  ADJUST_FUA_FLAG(fdoExtension);
3906 
3907  }
3908  return status;
3909 }
3910 
3911 
3912 NTSTATUS
3915  IN OUT PIRP Irp
3916  )
3917 
3918 /*++
3919 
3920 Routine Description:
3921 
3922  This routine services IOCTL_DISK_SET_CACHE_INFORMATION. It allows
3923  the caller to set the caching mode page on the device. This function
3924  validates the user parameter and calls the DiskSetCacheInformation()
3925  function to set the mode page. It also stores the cache value in the
3926  device extension and registry.
3927 
3928  This function must be called at IRQL < DISPATCH_LEVEL.
3929 
3930 Arguments:
3931 
3932  DeviceObject - Supplies the device object associated with this request.
3933 
3934  Irp - The IRP to be processed
3935 
3936 Return Value:
3937 
3938  NTSTATUS code
3939 
3940 --*/
3941 
3942 {
3943  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3944  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3945  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
3947  PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer;
3948  NTSTATUS status;
3949 
3950  //
3951  // This function must be called at less than dispatch level.
3952  // Fail if IRQL is equal or above DISPATCH_LEVEL.
3953  //
3954 
3955  PAGED_CODE();
3956  CHECK_IRQL();
3957 
3958  //
3959  // Validate the request.
3960  //
3961 
3962  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSetCacheInformation: DeviceObject %p Irp %p\n", DeviceObject, Irp));
3963 
3964  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_INFORMATION)) {
3965 
3966  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSetCacheInformation: Input buffer length mismatch.\n"));
3968  }
3969 
3970  status = DiskSetCacheInformation(fdoExtension, cacheInfo);
3971 
3972  //
3973  // Save away the user-defined override in our extension and the registry
3974  //
3975  if (cacheInfo->WriteCacheEnabled) {
3977  } else {
3979  }
3980 
3981  ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey,
3983 
3984  DiskLogCacheInformation(fdoExtension, cacheInfo, status);
3985 
3986  return status;
3987 }
3988 
3989 NTSTATUS
3992  IN OUT PIRP Irp
3993  )
3994 
3995 /*++
3996 
3997 Routine Description:
3998 
3999  This routine services IOCTL_STORAGE_GET_MEDIA_TYPES_EX. It returns
4000  the media type information to the caller. After validating the user
4001  parameter it calls DiskDetermineMediaTypes() to get the media type.
4002 
4003  This function must be called at IRQL < DISPATCH_LEVEL.
4004 
4005 Arguments:
4006 
4007  DeviceObject - Supplies the device object associated with this request.
4008 
4009  Irp - The IRP to be processed
4010 
4011 Return Value:
4012 
4013  NTSTATUS code
4014 
4015 --*/
4016 
4017 {
4018  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4020  NTSTATUS status;
4021 
4022  PMODE_PARAMETER_HEADER modeData;
4023  PMODE_PARAMETER_BLOCK blockDescriptor;
4024  PSCSI_REQUEST_BLOCK srb;
4025  PCDB cdb;
4026  ULONG modeLength;
4027  ULONG retries = 4;
4028  UCHAR densityCode = 0;
4029  BOOLEAN writable = TRUE;
4030  BOOLEAN mediaPresent = FALSE;
4031  ULONG srbSize;
4032  PSTORAGE_REQUEST_BLOCK srbEx = NULL;
4033  PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
4034  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL;
4035 
4036  //
4037  // This function must be called at less than dispatch level.
4038  // Fail if IRQL >= DISPATCH_LEVEL.
4039  //
4040  PAGED_CODE();
4041  CHECK_IRQL();
4042 
4043  //
4044  // Validate the request.
4045  //
4046 
4047  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4048 
4049  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_MEDIA_TYPES)) {
4050 
4051  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Output buffer too small.\n"));
4052  return STATUS_BUFFER_TOO_SMALL;
4053  }
4054 
4055  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4057  } else {
4058  srbSize = SCSI_REQUEST_BLOCK_SIZE;
4059  }
4060 
4061  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4062  srbSize,
4063  DISK_TAG_SRB);
4064 
4065  if (srb == NULL) {
4066  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n"));
4068  }
4069 
4070  RtlZeroMemory(srb, srbSize);
4071 
4072  //
4073  // Send a TUR to determine if media is present.
4074  //
4075 
4076  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4077  srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
4078 
4079  //
4080  // Set up STORAGE_REQUEST_BLOCK fields
4081  //
4082 
4084  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
4085  srbEx->Signature = SRB_SIGNATURE;
4086  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
4087  srbEx->SrbLength = srbSize;
4088  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
4089  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
4090  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
4091  srbEx->NumSrbExData = 1;
4092 
4093  // Set timeout value.
4094  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
4095 
4096  //
4097  // Set up address fields
4098  //
4099 
4100  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
4101  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
4102  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
4103 
4104  //
4105  // Set up SCSI SRB extended data fields
4106  //
4107 
4108  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
4109  sizeof(STOR_ADDR_BTL8);
4110  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
4111  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
4112  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
4113  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
4114  srbExDataCdb16->CdbLength = 6;
4115 
4116  cdb = (PCDB)srbExDataCdb16->Cdb;
4117  } else {
4118  // Should not happen
4119  NT_ASSERT(FALSE);
4120 
4121  FREE_POOL(srb);
4122  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Insufficient extended SRB size.\n"));
4123  return STATUS_INTERNAL_ERROR;
4124  }
4125 
4126  } else {
4127 
4130  srb->CdbLength = 6;
4131  cdb = (PCDB)srb->Cdb;
4132 
4133  //
4134  // Set timeout value.
4135  //
4136 
4137  srb->TimeOutValue = fdoExtension->TimeOutValue;
4138 
4139  }
4140  cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
4141 
4143  srb,
4144  NULL,
4145  0,
4146  FALSE);
4147 
4148  if (NT_SUCCESS(status)) {
4149  mediaPresent = TRUE;
4150  }
4151 
4152  modeLength = MODE_DATA_SIZE;
4153  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
4154  modeLength,
4156 
4157  if (modeData == NULL) {
4158  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n"));
4159  FREE_POOL(srb);
4161  }
4162 
4163  RtlZeroMemory(modeData, modeLength);
4164 
4165  //
4166  // Build the MODE SENSE CDB using previous SRB.
4167  //
4168 
4169  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4170  srbEx->SrbStatus = 0;
4171  srbExDataCdb16->ScsiStatus = 0;
4172  srbExDataCdb16->CdbLength = 6;
4173 
4174  //
4175  // Set timeout value from device extension.
4176  //
4177 
4178  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
4179  } else {
4180  srb->SrbStatus = 0;
4181  srb->ScsiStatus = 0;
4182  srb->CdbLength = 6;
4183 
4184  //
4185  // Set timeout value from device extension.
4186  //
4187 
4188  srb->TimeOutValue = fdoExtension->TimeOutValue;
4189  }
4190 
4191  //
4192  // Page code of 0x3F will return all pages.
4193  // This command could fail if the data to be returned is
4194  // more than 256 bytes. In which case, we should get only
4195  // the caching page since we only need the block descriptor.
4196  // DiskFdoProcessError will change the page code to
4197  // MODE_PAGE_CACHING if there is an error.
4198  //
4199 
4200  cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
4201  cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL;
4202  cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
4203 
4204 Retry:
4206  srb,
4207  modeData,
4208  modeLength,
4209  FALSE);
4210 
4211  if (status == STATUS_VERIFY_REQUIRED) {
4212 
4213  if (retries--) {
4214 
4215  //
4216  // Retry request.
4217  //
4218 
4219  goto Retry;
4220  }
4221  } else if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
4223  }
4224 
4226 
4227  //
4228  // Get the block descriptor.
4229  //
4230 
4231  if (modeData->BlockDescriptorLength != 0) {
4232 
4233  blockDescriptor = (PMODE_PARAMETER_BLOCK)((ULONG_PTR)modeData + sizeof(MODE_PARAMETER_HEADER));
4234  densityCode = blockDescriptor->DensityCode;
4235  }
4236 
4237  if (TEST_FLAG(modeData->DeviceSpecificParameter,
4239 
4240  writable = FALSE;
4241  }
4242 
4244  Irp,
4245  modeData->MediumType,
4246  densityCode,
4247  mediaPresent,
4248  writable);
4249  //
4250  // If the buffer was too small, DetermineMediaTypes updated the status and information and the request will fail.
4251  //
4252 
4253  } else {
4254  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Mode sense for header/bd failed. %lx\n", status));
4255  }
4256 
4257  FREE_POOL(srb);
4258  FREE_POOL(modeData);
4259 
4260  return status;
4261 }
4262 
4263 NTSTATUS
4266  IN OUT PIRP Irp
4267  )
4268 
4269 /*++
4270 
4271 Routine Description:
4272 
4273  This routine services IOCTL_STORAGE_PREDICT_FAILURE. If the device
4274  supports SMART then it returns any available failure data.
4275 
4276  This function must be called at IRQL < DISPATCH_LEVEL.
4277 
4278 Arguments:
4279 
4280  DeviceObject - Supplies the device object associated with this request.
4281 
4282  Irp - The IRP to be processed
4283 
4284 Return Value:
4285 
4286  NTSTATUS code
4287 
4288 --*/
4289 
4290 {
4291  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4292  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4293  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
4296 
4297  PSTORAGE_PREDICT_FAILURE checkFailure;
4298  STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
4299  IO_STATUS_BLOCK ioStatus = { 0 };
4300  KEVENT event;
4301 
4302  //
4303  // This function must be called at less than dispatch level.
4304  // Fail if IRQL >= DISPATCH_LEVEL.
4305  //
4306  PAGED_CODE();
4307  CHECK_IRQL();
4308 
4309  //
4310  // Validate the request.
4311  //
4312 
4313  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlPredictFailure: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4314 
4315  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_PREDICT_FAILURE)) {
4316 
4317  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlPredictFailure: Output buffer too small.\n"));
4318  return STATUS_BUFFER_TOO_SMALL;
4319  }
4320 
4321  //
4322  // See if the disk is predicting failure
4323  //
4324 
4325  checkFailure = (PSTORAGE_PREDICT_FAILURE)Irp->AssociatedIrp.SystemBuffer;
4326 
4328  ULONG readBufferSize;
4329  PUCHAR readBuffer;
4330  PIRP readIrp;
4331  PDEVICE_OBJECT topOfStack;
4332 
4333  checkFailure->PredictFailure = 0;
4334 
4336 
4338 
4339  //
4340  // SCSI disks need to have a read sent down to provoke any
4341  // failures to be reported.
4342  //
4343  // Issue a normal read operation. The error-handling code in
4344  // classpnp will take care of a failure prediction by logging the
4345  // correct event.
4346  //
4347 
4348  readBufferSize = fdoExtension->DiskGeometry.BytesPerSector;
4349  readBuffer = ExAllocatePoolWithTag(NonPagedPoolNx,
4350  readBufferSize,
4351  DISK_TAG_SMART);
4352 
4353  if (readBuffer != NULL) {
4355 
4356  offset.QuadPart = 0;
4358  topOfStack,
4359  readBuffer,
4360  readBufferSize,
4361  &offset,
4362  &event,
4363  &ioStatus);
4364 
4365  if (readIrp != NULL) {
4366 
4367  status = IoCallDriver(topOfStack, readIrp);
4368  if (status == STATUS_PENDING) {
4370  status = ioStatus.Status;
4371  }
4372 
4373 
4374  } else {
4376  }
4377 
4378  FREE_POOL(readBuffer);
4379  } else {
4381  }
4382 
4383  ObDereferenceObject(topOfStack);
4384  }
4385 
4387  {
4390 
4391  status = DiskReadFailurePredictStatus(fdoExtension, &diskSmartStatus);
4392 
4393  if (NT_SUCCESS(status)) {
4394 
4395  status = DiskReadFailurePredictData(fdoExtension,
4396  Irp->AssociatedIrp.SystemBuffer);
4397 
4398  if (diskSmartStatus.PredictFailure) {
4399  checkFailure->PredictFailure = 1;
4400  } else {
4401  checkFailure->PredictFailure = 0;
4402  }
4403 
4404  Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE);
4405  }
4406  } else {
4408  }
4409  }
4410  return status;
4411 }
4412 
4413 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
4414 NTSTATUS
4417  IN OUT PIRP Irp
4418  )
4419 
4420 /*++
4421 
4422 Routine Description:
4423 
4424  This routine services IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG. If the device
4425  supports SMART then it returns any available failure data.
4426 
4427  This function must be called at IRQL < DISPATCH_LEVEL.
4428 
4429 Arguments:
4430 
4431  DeviceObject - Supplies the device object associated with this request.
4432 
4433  Irp - The IRP to be processed
4434 
4435 Return Value:
4436 
4437  NTSTATUS code
4438 
4439 --*/
4440 
4441 {
4442  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4443  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4444  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
4447  PSTORAGE_FAILURE_PREDICTION_CONFIG enablePrediction;
4448 
4449  //
4450  // This function must be called at less than dispatch level.
4451  // Fail if IRQL >= DISPATCH_LEVEL.
4452  //
4453  PAGED_CODE();
4454  CHECK_IRQL();
4455 
4456  //
4457  // Validate the request.
4458  //
4459 
4460  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4461 
4462  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG) ||
4463  irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG)) {
4464 
4465  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Buffer too small.\n"));
4466  return STATUS_BUFFER_TOO_SMALL;
4467  }
4468 
4469  enablePrediction = (PSTORAGE_FAILURE_PREDICTION_CONFIG)Irp->AssociatedIrp.SystemBuffer;
4470 
4471  if (enablePrediction->Version != STORAGE_FAILURE_PREDICTION_CONFIG_V1 ||
4472  enablePrediction->Size < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG)) {
4473  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Buffer version or size is incorrect.\n"));
4475  }
4476 
4477  if (enablePrediction->Reserved != 0) {
4478  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Reserved bytes are not zero!\n"));
4480  }
4481 
4482  //
4483  // Default to success. This might get overwritten on failure below.
4484  //
4486 
4487  //
4488  // If this is a "set" and the current state (enabled/disabled) is
4489  // different from the sender's desired state,
4490  //
4491  if (enablePrediction->Set && enablePrediction->Enabled != diskData->FailurePredictionEnabled) {
4494  //
4495  // SMART or IOCTL based failure prediction is being used so call
4496  // the generic function that is normally called in the WMI path.
4497  //
4498  status = DiskEnableDisableFailurePrediction(fdoExtension, enablePrediction->Enabled);
4499  } else if (diskData->ScsiInfoExceptionsSupported) {
4500  //
4501  // If we know that the device supports the Informational Exceptions
4502  // mode page, try to enable/disable failure prediction that way.
4503  //
4504  status = DiskEnableInfoExceptions(fdoExtension, enablePrediction->Enabled);
4505  }
4506  }
4507 
4508  //
4509  // Return the current state regardless if this was a "set" or a "get".
4510  //
4511  enablePrediction->Enabled = diskData->FailurePredictionEnabled;
4512 
4513  if (NT_SUCCESS(status)) {
4514  Irp->IoStatus.Information = sizeof(STORAGE_FAILURE_PREDICTION_CONFIG);
4515  }
4516 
4517  return status;
4518 }
4519 #endif //(NTDDI_VERSION >= NTDDI_WINBLUE)
4520 
4521 NTSTATUS
4524  IN OUT PIRP Irp
4525  )
4526 
4527 /*++
4528 
4529 Routine Description:
4530 
4531  This routine services IOCTL_DISK_VERIFY. After verifying
4532  user input, it starts the worker thread DiskIoctlVerifyThread()
4533  to verify the device.
4534 
4535 Arguments:
4536 
4537  DeviceObject - Supplies the device object associated with this request.
4538 
4539  Irp - The IRP to be processed
4540 
4541 Return Value:
4542 
4543  NTSTATUS code
4544 
4545 --*/
4546 
4547 {
4548  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4549  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4551  PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
4553  PSCSI_REQUEST_BLOCK srb;
4554  LARGE_INTEGER byteOffset;
4555  ULONG srbSize;
4556 
4557  //
4558  // Validate the request.
4559  //
4560 
4561  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4562 
4563  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VERIFY_INFORMATION)) {
4564  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Input buffer length mismatch.\n"));
4566  }
4567 
4568  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4570  } else {
4571  srbSize = SCSI_REQUEST_BLOCK_SIZE;
4572  }
4573  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4574  srbSize,
4575  DISK_TAG_SRB);
4576 
4577  if (srb == NULL) {
4578  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Unable to allocate memory.\n"));
4580  }
4581 
4582  RtlZeroMemory(srb, srbSize);
4583 
4584  //
4585  // Add disk offset to starting sector.
4586  //
4587 
4588  byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart +
4589  verifyInfo->StartingOffset.QuadPart;
4590 
4591  //
4592  // Perform a bounds check on the sector range
4593  //
4594 
4595  if ((verifyInfo->StartingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
4596  (verifyInfo->StartingOffset.QuadPart < 0)) {
4597 
4598  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Verify request to invalid sector.\n"));
4599  FREE_POOL(srb)
4601  } else {
4602 
4603  ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart;
4604 
4605  if ((ULONGLONG)verifyInfo->Length > bytesRemaining) {
4606 
4607  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Verify request to invalid sector.\n"));
4608  FREE_POOL(srb)
4610  }
4611  }
4612 
4613  Context = ExAllocatePoolWithTag(NonPagedPoolNx,
4616  if (Context) {
4617 
4618  Context->Irp = Irp;
4619  Context->Srb = srb;
4621 
4622  if (Context->WorkItem) {
4623 
4624  //
4625  // Queue the work item and return.
4626  //
4627 
4629 
4630  IoQueueWorkItem(Context->WorkItem,
4633  Context);
4634 
4635  return STATUS_PENDING;
4636  }
4637  FREE_POOL(Context);
4638  }
4639  FREE_POOL(srb)
4641 }
4642 
4643 NTSTATUS
4646  IN OUT PIRP Irp
4647  )
4648 
4649 /*++
4650 
4651 Routine Description:
4652 
4653  This routine services IOCTL_DISK_REASSIGN_BLOCKS. This IOCTL
4654  allows the caller to remap the defective blocks to a new
4655  location on the disk.
4656 
4657  This function must be called at IRQL < DISPATCH_LEVEL.
4658 
4659 Arguments:
4660 
4661  DeviceObject - Supplies the device object associated with this request.
4662 
4663  Irp - The IRP to be processed
4664 
4665 Return Value:
4666 
4667  NTSTATUS code
4668 
4669 --*/
4670 
4671 {
4672  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4674  NTSTATUS status;
4675  PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
4676  PSCSI_REQUEST_BLOCK srb;
4677  PCDB cdb;
4678  ULONG bufferSize;
4679  ULONG blockNumber;
4680  ULONG blockCount;
4681  ULONG srbSize;
4682  PSTORAGE_REQUEST_BLOCK srbEx;
4683  PSTOR_ADDR_BTL8 storAddrBtl8;
4684  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
4685 
4686  //
4687  // This function must be called at less than dispatch level.
4688  // Fail if IRQL >= DISPATCH_LEVEL.
4689  //
4690  PAGED_CODE();
4691  CHECK_IRQL();
4692 
4693  //
4694  // Validate the request.
4695  //
4696 
4697  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4698 
4699  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(REASSIGN_BLOCKS)) {
4700  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Input buffer length mismatch.\n"));
4702  }
4703 
4704  //
4705  // Make sure we have some data in the input buffer.
4706  //
4707 
4708  if (badBlocks->Count == 0) {
4709  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Invalid block count\n"));
4710  return STATUS_INVALID_PARAMETER;
4711  }
4712 
4713  bufferSize = sizeof(REASSIGN_BLOCKS) + ((badBlocks->Count - 1) * sizeof(ULONG));
4714 
4715  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < bufferSize) {
4716  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Input buffer length mismatch for bad blocks.\n"));
4718  }
4719 
4720  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4722  } else {
4723  srbSize = SCSI_REQUEST_BLOCK_SIZE;
4724  }
4725  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4726  srbSize,
4727  DISK_TAG_SRB);
4728 
4729  if (srb == NULL) {
4730  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Unable to allocate memory.\n"));
4732  }
4733 
4734  RtlZeroMemory(srb, srbSize);
4735 
4736  //
4737  // Build the data buffer to be transferred in the input buffer.
4738  // The format of the data to the device is:
4739  //
4740  // 2 bytes Reserved
4741  // 2 bytes Length
4742  // x * 4 btyes Block Address
4743  //
4744  // All values are big endian.
4745  //
4746 
4747  badBlocks->Reserved = 0;
4748  blockCount = badBlocks->Count;
4749 
4750  //
4751  // Convert # of entries to # of bytes.
4752  //
4753 
4754  blockCount *= 4;
4755  badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
4756  badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
4757 
4758  //
4759  // Convert back to number of entries.
4760  //
4761 
4762  blockCount /= 4;
4763 
4764  for (; blockCount > 0; blockCount--) {
4765 
4766  blockNumber = badBlocks->BlockNumber[blockCount-1];
4767  REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1], (PFOUR_BYTE) &blockNumber);
4768  }
4769 
4770  //
4771  // Build a SCSI SRB containing a SCSIOP_REASSIGN_BLOCKS cdb
4772  //
4773 
4774  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4775  srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
4776 
4777  //
4778  // Set up STORAGE_REQUEST_BLOCK fields
4779  //
4780 
4782  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
4783  srbEx->Signature = SRB_SIGNATURE;
4784  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
4785  srbEx->SrbLength = srbSize;
4786  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
4787  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
4788  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
4789  srbEx->NumSrbExData = 1;
4790 
4791  // Set timeout value.
4792  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
4793 
4794  //
4795  // Set up address fields
4796  //
4797 
4798  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
4799  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
4800  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
4801 
4802  //
4803  // Set up SCSI SRB extended data fields
4804  //
4805 
4806  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
4807  sizeof(STOR_ADDR_BTL8);
4808  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
4809  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
4810  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
4811  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
4812  srbExDataCdb16->CdbLength = 6;
4813 
4814  cdb = (PCDB)srbExDataCdb16->Cdb;
4815  } else {
4816  // Should not happen
4817  NT_ASSERT(FALSE);
4818 
4819  FREE_POOL(srb);
4820  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Insufficient extended SRB size.\n"));
4821  return STATUS_INTERNAL_ERROR;
4822  }
4823 
4824  } else {
4827  srb->CdbLength = 6;
4828 
4829  //
4830  // Set timeout value.
4831  //
4832 
4833  srb->TimeOutValue = fdoExtension->TimeOutValue;
4834 
4835  cdb = (PCDB)srb->Cdb;
4836  }
4837 
4838  cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
4839 
4841  srb,
4842  badBlocks,
4843  bufferSize,
4844  TRUE);
4845 
4846  FREE_POOL(srb);
4847  return status;
4848 }
4849 
4850 NTSTATUS
4853  IN OUT PIRP Irp
4854  )
4855 
4856 /*++
4857 
4858 Routine Description:
4859 
4860  This routine services IOCTL_DISK_REASSIGN_BLOCKS_EX. This IOCTL
4861  allows the caller to remap the defective blocks to a new
4862  location on the disk. The input buffer contains 8-byte LBAs.
4863 
4864  This function must be called at IRQL < DISPATCH_LEVEL.
4865 
4866 Arguments:
4867 
4868  DeviceObject - Supplies the device object associated with this request.
4869 
4870  Irp - The IRP to be processed
4871 
4872 Return Value:
4873 
4874  NTSTATUS code
4875 
4876 --*/
4877 
4878 {
4879  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4881  NTSTATUS status;
4882  PREASSIGN_BLOCKS_EX badBlocks = Irp->AssociatedIrp.SystemBuffer;
4883  PSCSI_REQUEST_BLOCK srb;
4884  PCDB cdb;
4885  LARGE_INTEGER blockNumber;
4886  ULONG bufferSize;
4887  ULONG blockCount;
4888  ULONG srbSize;
4889  PSTORAGE_REQUEST_BLOCK srbEx;
4890  PSTOR_ADDR_BTL8 storAddrBtl8;
4891  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
4892 
4893  //
4894  // This function must be called at less than dispatch level.
4895  // Fail if IRQL >= DISPATCH_LEVEL.
4896  //
4897  PAGED_CODE();
4898  CHECK_IRQL();
4899 
4900  //
4901  // Validate the request.
4902  //
4903 
4904  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4905 
4906  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(REASSIGN_BLOCKS_EX)) {
4907  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Input buffer length mismatch.\n"));
4909  }
4910 
4911  //
4912  // Make sure we have some data in the input buffer.
4913  //
4914 
4915  if (badBlocks->Count == 0) {
4916  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Invalid block count\n"));
4917  return STATUS_INVALID_PARAMETER;
4918  }
4919 
4920  bufferSize = sizeof(REASSIGN_BLOCKS_EX) + ((badBlocks->Count - 1) * sizeof(LARGE_INTEGER));
4921 
4922  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < bufferSize) {
4923  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Input buffer length mismatch for bad blocks.\n"));
4925  }
4926 
4927  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4929  } else {
4930  srbSize = SCSI_REQUEST_BLOCK_SIZE;
4931  }
4932  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4933  srbSize,
4934  DISK_TAG_SRB);
4935 
4936  if (srb == NULL) {
4937  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Unable to allocate memory.\n"));
4939  }
4940 
4941  RtlZeroMemory(srb, srbSize);
4942 
4943  //
4944  // Build the data buffer to be transferred in the input buffer.
4945  // The format of the data to the device is:
4946  //
4947  // 2 bytes Reserved
4948  // 2 bytes Length
4949  // x * 8 btyes Block Address
4950  //
4951  // All values are big endian.
4952  //
4953 
4954  badBlocks->Reserved = 0;
4955  blockCount = badBlocks->Count;
4956 
4957  //
4958  // Convert # of entries to # of bytes.
4959  //
4960 
4961  blockCount *= 8;
4962  badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
4963  badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
4964 
4965  //
4966  // Convert back to number of entries.
4967  //
4968 
4969  blockCount /= 8;
4970 
4971  for (; blockCount > 0; blockCount--) {
4972 
4973  blockNumber = badBlocks->BlockNumber[blockCount-1];
4974  REVERSE_BYTES_QUAD(&badBlocks->BlockNumber[blockCount-1], &blockNumber);
4975  }
4976 
4977  //
4978  // Build a SCSI SRB containing a SCSIOP_REASSIGN_BLOCKS cdb
4979  //
4980 
4981  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4982  srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
4983 
4984  //
4985  // Set up STORAGE_REQUEST_BLOCK fields
4986  //
4987 
4989  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
4990  srbEx->Signature = SRB_SIGNATURE;
4991  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
4992  srbEx->SrbLength = srbSize;
4993  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
4994  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
4995  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
4996  srbEx->NumSrbExData = 1;
4997 
4998  // Set timeout value.
4999  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
5000 
5001  //
5002  // Set up address fields
5003  //
5004 
5005  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
5006  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
5007  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
5008 
5009  //
5010  // Set up SCSI SRB extended data fields
5011  //
5012 
5013  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
5014  sizeof(STOR_ADDR_BTL8);
5015  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
5016  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
5017  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
5018  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
5019  srbExDataCdb16->CdbLength = 6;
5020 
5021  cdb = (PCDB)srbExDataCdb16->Cdb;
5022  } else {
5023  // Should not happen
5024  NT_ASSERT(FALSE);
5025 
5026  FREE_POOL(srb);
5027  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Insufficient extended SRB size.\n"));
5028  return STATUS_INTERNAL_ERROR;
5029  }
5030 
5031  } else {
5034  srb->CdbLength = 6;
5035 
5036  //
5037  // Set timeout value.
5038  //
5039 
5040  srb->TimeOutValue = fdoExtension->TimeOutValue;
5041 
5042  cdb = (PCDB)srb->Cdb;
5043  }
5044 
5045  cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
5046  cdb->CDB6GENERIC.CommandUniqueBits = 1; // LONGLBA
5047 
5049  srb,
5050  badBlocks,
5051  bufferSize,
5052  TRUE);
5053 
5054  FREE_POOL(srb);
5055  return status;
5056 }
5057 
5058 NTSTATUS
5061  IN OUT PIRP Irp
5062  )
5063 
5064 /*++
5065 
5066 Routine Description:
5067 
5068  This routine services IOCTL_DISK_IS_WRITABLE. This function
5069  returns whether the disk is writable. If the device is not
5070  writable then STATUS_MEDIA_WRITE_PROTECTED will be returned.
5071 
5072  This function must be called at IRQL < DISPATCH_LEVEL.
5073 
5074 Arguments:
5075 
5076  DeviceObject - Supplies the device object associated with this request.
5077 
5078  Irp - The IRP to be processed
5079 
5080 Return Value:
5081 
5082  NTSTATUS code
5083 
5084 --*/
5085 
5086 {
5087  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5089 
5090  PMODE_PARAMETER_HEADER modeData;
5091  PSCSI_REQUEST_BLOCK srb;
5092  PCDB cdb = NULL;
5093  ULONG modeLength;
5094  ULONG retries = 4;
5095  ULONG srbSize;
5096  PSTORAGE_REQUEST_BLOCK srbEx;
5097  PSTOR_ADDR_BTL8 storAddrBtl8;
5098  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
5099 
5100  //
5101  // This function must be called at less than dispatch level.
5102  // Fail if IRQL >= DISPATCH_LEVEL.
5103  //
5104  PAGED_CODE();
5105  CHECK_IRQL();
5106 
5107  //
5108  // Validate the request.
5109  //
5110 
5111  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5112 
5113  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
5115  } else {
5116  srbSize = SCSI_REQUEST_BLOCK_SIZE;
5117  }
5118  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
5119  srbSize,
5120  DISK_TAG_SRB);
5121 
5122  if (srb == NULL) {
5123  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n"));
5125  }
5126 
5127  RtlZeroMemory(srb, srbSize);
5128 
5129  //
5130  // Allocate memory for a mode header and then some
5131  // for port drivers that need to convert to MODE10
5132  // or always return the MODE_PARAMETER_BLOCK (even
5133  // when memory was not allocated for this purpose)
5134  //
5135 
5136  modeLength = MODE_DATA_SIZE;
5137  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
5138  modeLength,
5140 
5141  if (modeData == NULL) {
5142  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n"));
5143  FREE_POOL(srb);
5145  }
5146 
5147  RtlZeroMemory(modeData, modeLength);
5148 
5149  //
5150  // Build the MODE SENSE CDB
5151  //
5152 
5153  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
5154  srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
5155 
5156  //
5157  // Set up STORAGE_REQUEST_BLOCK fields
5158  //
5159 
5161  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
5162  srbEx->Signature = SRB_SIGNATURE;
5163  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
5164  srbEx->SrbLength = srbSize;
5165  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
5166  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
5167  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
5168  srbEx->NumSrbExData = 1;
5169 
5170  // Set timeout value.
5171  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
5172 
5173  //
5174  // Set up address fields
5175  //
5176 
5177  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
5178  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
5179  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
5180 
5181  //
5182  // Set up SCSI SRB extended data fields
5183  //
5184 
5185  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
5186  sizeof(STOR_ADDR_BTL8);
5187  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
5188  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
5189  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
5190  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
5191  srbExDataCdb16->CdbLength = 6;
5192 
5193  cdb = (PCDB)srbExDataCdb16->Cdb;
5194  } else {
5195  // Should not happen
5196  NT_ASSERT(FALSE);
5197 
5198  FREE_POOL(srb);
5199  FREE_POOL(modeData);
5200  return STATUS_INTERNAL_ERROR;
5201  }
5202 
5203  } else {
5206  srb->CdbLength = 6;
5207 
5208  //
5209  // Set timeout value.
5210  //
5211 
5212  srb->TimeOutValue = fdoExtension->TimeOutValue;
5213 
5214  cdb = (PCDB)srb->Cdb;
5215  }
5216 
5217  //
5218  // Page code of 0x3F will return all pages.
5219  // This command could fail if the data to be returned is
5220  // more than 256 bytes. In which case, we should get only
5221  // the caching page since we only need the block descriptor.
5222  // DiskFdoProcessError will change the page code to
5223  // MODE_PAGE_CACHING if there is an error.
5224  //
5225 
5226  cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
5227  cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL;
5228  cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
5229 
5230  while (retries != 0) {
5231 
5233  srb,
5234  modeData,
5235  modeLength,
5236  FALSE);
5237 
5238  if (status != STATUS_VERIFY_REQUIRED) {
5241  }
5242  break;
5243  }
5244  retries--;
5245  }
5246 
5247  if (NT_SUCCESS(status)) {
5248 
5251  }
5252  }
5253 
5254  FREE_POOL(srb);
5255  FREE_POOL(modeData);
5256  return status;
5257 }
5258 
5259 NTSTATUS
5262  IN OUT PIRP Irp
5263  )
5264 
5265 /*++
5266 
5267 Routine Description:
5268 
5269  This routine services IOCTL_DISK_INTERNAL_SET_VERIFY.
5270  This is an internal function used to set the DO_VERIFY_VOLUME
5271  device object flag. Only a kernel mode component can send this
5272  IOCTL.
5273 
5274 Arguments:
5275 
5276  DeviceObject - Supplies the device object associated with this request.
5277 
5278  Irp - The IRP to be processed
5279 
5280 Return Value:
5281 
5282  NTSTATUS code
5283 
5284 --*/
5285 
5286 {
5288 
5289  //
5290  // Validate the request.
5291  //
5292 
5293  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSetVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5294 
5295  //
5296  // If the caller is kernel mode, set the verify bit.
5297  //
5298 
5299  if (Irp->RequestorMode == KernelMode) {
5300 
5303 
5304  }
5305  return status;
5306 }
5307 
5308 NTSTATUS
5311  IN OUT PIRP Irp
5312  )
5313 
5314 /*++
5315 
5316 Routine Description:
5317 
5318  This routine services IOCTL_DISK_INTERNAL_CLEAR_VERIFY.
5319  This is an internal function used to clear the DO_VERIFY_VOLUME
5320  device object flag. Only a kernel mode component can send this
5321  IOCTL.
5322 
5323 Arguments:
5324 
5325  DeviceObject - Supplies the device object associated with this request.
5326 
5327  Irp - The IRP to be processed
5328 
5329 Return Value:
5330 
5331  NTSTATUS code
5332 
5333 --*/
5334 
5335 {
5337 
5338  //
5339  // Validate the request.
5340  //
5341 
5342  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlClearVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5343 
5344  //
5345  // If the caller is kernel mode, set the verify bit.
5346  //
5347 
5348  if (Irp->RequestorMode == KernelMode) {
5349 
5352 
5353  }
5354  return status;
5355 }
5356 
5357 NTSTATUS
5360  IN OUT PIRP Irp
5361  )
5362 
5363 /*++
5364 
5365 Routine Description:
5366 
5367  This routine services IOCTL_DISK_UPDATE_DRIVE_SIZE.
5368  This function is used to inform the disk driver to update
5369  the device geometry information cached in the device extension
5370  This is normally initiated from the drivers layers above disk
5371  driver.
5372 
5373  This function must be called at IRQL < DISPATCH_LEVEL.
5374 
5375 Arguments:
5376 
5377  DeviceObject - Supplies the device object associated with this request.
5378 
5379  Irp - The IRP to be processed
5380 
5381 Return Value:
5382 
5383  NTSTATUS code
5384 
5385 --*/
5386 
5387 {
5388  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5389  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5390  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5393  NTSTATUS status;
5394 
5395  //
5396  // This function must be called at less than dispatch level.
5397  // Fail if IRQL >= DISPATCH_LEVEL.
5398  //
5399  PAGED_CODE();
5400  CHECK_IRQL();
5401 
5402  //
5403  // Validate the request.
5404  //
5405 
5406  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlUpdateDriveSize: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5407 
5408  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) {
5409 
5410  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlUpdateDriveSize: Output buffer too small.\n"));
5411  return STATUS_BUFFER_TOO_SMALL;
5412  }
5413 
5415 
5416  //
5417  // Note whether the drive is ready.
5418  //
5419 
5420  diskData->ReadyStatus = status;
5421 
5422  if (NT_SUCCESS(status)) {
5423 
5424  //
5425  // Copy drive geometry information from the device extension.
5426  //
5427 
5428  RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
5429  &(fdoExtension->DiskGeometry),
5430  sizeof(DISK_GEOMETRY));
5431 
5432  if (((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector == 0) {
5433  ((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector = 512;
5434  }
5435  Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
5437 
5438  //
5439  // Notify everyone that the disk layout may have changed
5440  //
5441 
5442  Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
5443  Notification.Version = 1;
5445  Notification.FileObject = NULL;
5446  Notification.NameBufferOffset = -1;
5447 
5449  &Notification,
5450  NULL,
5451  NULL);
5452  }
5453  return status;
5454 }
5455 
5456 NTSTATUS
5459  IN OUT PIRP Irp
5460  )
5461 
5462 /*++
5463 
5464 Routine Description:
5465 
5466  This routine services IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
5467  and IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN. This function
5468  returns the physical location of a volume.
5469 
5470  This function must be called at IRQL < DISPATCH_LEVEL.
5471 
5472 Arguments:
5473 
5474  DeviceObject - Supplies the device object associated with this request.
5475 
5476  Irp - The IRP to be processed
5477 
5478 Return Value:
5479 
5480  NTSTATUS code
5481 
5482 --*/
5483 
5484 {
5485  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5486  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5489 
5490  //
5491  // This function must be called at less than dispatch level.
5492  // Fail if IRQL >= DISPATCH_LEVEL.
5493  //
5494  PAGED_CODE();
5495  CHECK_IRQL();
5496 
5497  //
5498  // Validate the request.
5499  //
5500 
5501  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetVolumeDiskExtents: DeviceObject %p Irp %p\n",