ReactOS  0.4.15-dev-2502-g9f3ed60
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 #ifndef __REACTOS__
1262  // ReactOS hits this assert, because CurrIrp can already be freed at this point
1263  // and it's possible that NextIrp has the same pointer value
1264  NT_ASSERT(diskData->FlushContext.CurrIrp != diskData->FlushContext.NextIrp);
1265 #endif
1266  diskData->FlushContext.CurrIrp = diskData->FlushContext.NextIrp;
1267  diskData->FlushContext.NextIrp = NULL;
1268 
1270 
1271  //
1272  // Send this request down to the device
1273  //
1275  }
1276 
1277  } else {
1278 
1279  diskData->FlushContext.CurrIrp = Irp;
1281 
1282  NT_ASSERT(diskData->FlushContext.NextIrp == NULL);
1284 
1285 
1287 
1289  }
1290 
1291  } else {
1292 
1293  //
1294  // Allocate SCSI request block.
1295  //
1296 
1297  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1299  } else {
1300  srbSize = sizeof(SCSI_REQUEST_BLOCK);
1301  }
1302 
1303  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
1304  srbSize,
1305  DISK_TAG_SRB);
1306  if (srb == NULL) {
1307 
1308  //
1309  // Set the status and complete the request.
1310  //
1311 
1312  Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1316  }
1317 
1318  RtlZeroMemory(srb, srbSize);
1319  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1320 
1321  srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
1322 
1323  //
1324  // Set up STORAGE_REQUEST_BLOCK fields
1325  //
1326 
1327  srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
1328  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
1329  srbEx->Signature = SRB_SIGNATURE;
1330  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
1331  srbEx->SrbLength = srbSize;
1332  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1333  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
1334  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
1335  srbEx->NumSrbExData = 1;
1336 
1337  // Set timeout value and mark the request as not being a tagged request.
1338  srbEx->TimeOutValue = fdoExtension->TimeOutValue * 4;
1339  srbEx->RequestTag = SP_UNTAGGED;
1340  srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST;
1341  srbEx->SrbFlags = fdoExtension->SrbFlags;
1342 
1343  //
1344  // Set up address fields
1345  //
1346 
1347  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
1348  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
1349  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
1350 
1351  //
1352  // Set up SCSI SRB extended data fields
1353  //
1354 
1355  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
1356  sizeof(STOR_ADDR_BTL8);
1357  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
1358  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
1359  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
1360  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
1361 
1362  cdb = (PCDB)srbExDataCdb16->Cdb;
1363  } else {
1364  // Should not happen
1365  NT_ASSERT(FALSE);
1366 
1367  //
1368  // Set the status and complete the request.
1369  //
1370 
1371  Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
1374  return(STATUS_INTERNAL_ERROR);
1375  }
1376 
1377  } else {
1378 
1379  //
1380  // Write length to SRB.
1381  //
1382 
1383  srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1384 
1385  //
1386  // Set timeout value and mark the request as not being a tagged request.
1387  //
1388 
1389  srb->TimeOutValue = fdoExtension->TimeOutValue * 4;
1390  srb->QueueTag = SP_UNTAGGED;
1391  srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
1392  srb->SrbFlags = fdoExtension->SrbFlags;
1393  srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1394 
1395  cdb = (PCDB)srb->Cdb;
1396  }
1397 
1398  //
1399  // If the write cache is enabled then send a synchronize cache request.
1400  //
1401 
1402  if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE)) {
1403 
1404  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1405  srbExDataCdb16->CdbLength = 10;
1406  } else {
1407  srb->CdbLength = 10;
1408  }
1409 
1410  cdb->CDB10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE;
1411 
1413  srb,
1414  NULL,
1415  0,
1416  TRUE);
1417 
1418  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status));
1419  }
1420 
1421  //
1422  // Unlock the device if it contains removable media
1423  //
1424 
1425  if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
1426  {
1427 
1428  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1429 
1430  //
1431  // Reinitialize status fields to 0 in case there was a previous request
1432  //
1433 
1434  srbEx->SrbStatus = 0;
1435  srbExDataCdb16->ScsiStatus = 0;
1436 
1437  srbExDataCdb16->CdbLength = 6;
1438 
1439  //
1440  // Set timeout value
1441  //
1442 
1443  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
1444 
1445  } else {
1446 
1447  //
1448  // Reinitialize status fields to 0 in case there was a previous request
1449  //
1450 
1451  srb->SrbStatus = 0;
1452  srb->ScsiStatus = 0;
1453 
1454  srb->CdbLength = 6;
1455 
1456  //
1457  // Set timeout value.
1458  //
1459 
1460  srb->TimeOutValue = fdoExtension->TimeOutValue;
1461  }
1462 
1463  cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
1464  cdb->MEDIA_REMOVAL.Prevent = FALSE;
1465 
1467  srb,
1468  NULL,
1469  0,
1470  TRUE);
1471 
1472  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "DiskShutdownFlush: Unlock device request sent. Status = %lx\n", status));
1473  }
1474 
1475  //
1476  // Set up a SHUTDOWN SRB
1477  //
1478 
1479  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1480  srbEx->NumSrbExData = 0;
1481  srbEx->SrbExDataOffset[0] = 0;
1482  srbEx->SrbFunction = SRB_FUNCTION_SHUTDOWN;
1483  srbEx->OriginalRequest = Irp;
1484  srbEx->SrbLength = CLASS_SRBEX_NO_SRBEX_DATA_BUFFER_SIZE;
1485  srbEx->SrbStatus = 0;
1486  } else {
1487  srb->CdbLength = 0;
1488  srb->Function = SRB_FUNCTION_SHUTDOWN;
1489  srb->SrbStatus = 0;
1490  srb->OriginalRequest = Irp;
1491  }
1492 
1493  //
1494  // Set the retry count to zero.
1495  //
1496 
1497  irpStack->Parameters.Others.Argument4 = (PVOID) 0;
1498 
1499  //
1500  // Set up IoCompletion routine address.
1501  //
1502 
1504 
1505  //
1506  // Get next stack location and
1507  // set major function code.
1508  //
1509 
1510  irpStack = IoGetNextIrpStackLocation(Irp);
1511 
1512  irpStack->MajorFunction = IRP_MJ_SCSI;
1513 
1514  //
1515  // Set up SRB for execute scsi request.
1516  // Save SRB address in next stack for port driver.
1517  //
1518 
1519  irpStack->Parameters.Scsi.Srb = srb;
1520 
1521  //
1522  // Call the port driver to process the request.
1523  //
1524 
1526  IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1527  }
1528 
1529  return STATUS_PENDING;
1530 }
1531 
1532 
1533 VOID
1536  IN PDISK_GROUP_CONTEXT FlushContext
1537  )
1538 
1539 /*++
1540 
1541 Routine Description:
1542 
1543  This routine is the handler for flush requests. It sends down a synch
1544  cache command to the device if its cache is enabled. This is followed
1545  by an SRB_FUNCTION_FLUSH
1546 
1547 Arguments:
1548 
1549  Fdo - The device object processing the flush request
1550  FlushContext - The flush group context
1551 
1552 Return Value:
1553 
1554  None
1555 
1556 --*/
1557 
1558 {
1559  PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
1560  PSCSI_REQUEST_BLOCK srb = &FlushContext->Srb.Srb;
1561  PSTORAGE_REQUEST_BLOCK srbEx = &FlushContext->Srb.SrbEx;
1563  PSTOR_ADDR_BTL8 storAddrBtl8;
1564  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
1565  NTSTATUS SyncCacheStatus = STATUS_SUCCESS;
1566 
1567  //
1568  // Fill in the srb fields appropriately
1569  //
1570  if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1571  RtlZeroMemory(srbEx, sizeof(FlushContext->Srb.SrbExBuffer));
1572 
1573  srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
1574  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
1575  srbEx->Signature = SRB_SIGNATURE;
1576  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
1577  srbEx->SrbLength = sizeof(FlushContext->Srb.SrbExBuffer);
1578  srbEx->RequestPriority = IoGetIoPriorityHint(FlushContext->CurrIrp);
1579  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
1580  srbEx->TimeOutValue = fdoExt->TimeOutValue * 4;
1581  srbEx->RequestTag = SP_UNTAGGED;
1582  srbEx->RequestAttribute = SRB_SIMPLE_TAG_REQUEST;
1583  srbEx->SrbFlags = fdoExt->SrbFlags;
1584 
1585  //
1586  // Set up address fields
1587  //
1588 
1589  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
1590  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
1591  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
1592 
1593  } else {
1595 
1597  srb->TimeOutValue = fdoExt->TimeOutValue * 4;
1598  srb->QueueTag = SP_UNTAGGED;
1600  srb->SrbFlags = fdoExt->SrbFlags;
1601  }
1602 
1603  //
1604  // If write caching is enabled then send down a synchronize cache request
1605  //
1606  if (TEST_FLAG(fdoExt->DeviceFlags, DEV_WRITE_CACHE))
1607  {
1608 
1609  if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1610  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1611  srbEx->NumSrbExData = 1;
1612 
1613  //
1614  // Set up SCSI SRB extended data fields
1615  //
1616 
1617  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
1618  sizeof(STOR_ADDR_BTL8);
1619  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
1620  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
1621  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
1622  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
1623  srbExDataCdb16->CdbLength = 10;
1624  srbExDataCdb16->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
1625  } else {
1626  // Should not happen
1627  NT_ASSERT(FALSE);
1628  return;
1629  }
1630 
1631  } else {
1633  srb->CdbLength = 10;
1634  srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
1635  }
1636 
1637  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending sync cache\n"));
1638 
1639  SyncCacheStatus = ClassSendSrbSynchronous(Fdo, srb, NULL, 0, TRUE);
1640  }
1641 
1642  //
1643  // Set up a FLUSH SRB
1644  //
1645  if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1646  srbEx->SrbFunction = SRB_FUNCTION_FLUSH;
1647  srbEx->NumSrbExData = 0;
1648  srbEx->SrbExDataOffset[0] = 0;
1649  srbEx->OriginalRequest = FlushContext->CurrIrp;
1650  srbEx->SrbStatus = 0;
1651 
1652  //
1653  // Make sure that this srb does not get freed
1654  //
1655  SET_FLAG(srbEx->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT);
1656 
1657  } else {
1659  srb->CdbLength = 0;
1660  srb->OriginalRequest = FlushContext->CurrIrp;
1661  srb->SrbStatus = 0;
1662  srb->ScsiStatus = 0;
1663 
1664  //
1665  // Make sure that this srb does not get freed
1666  //
1668  }
1669 
1670  //
1671  // Make sure that this request does not get retried
1672  //
1673  irpSp = IoGetCurrentIrpStackLocation(FlushContext->CurrIrp);
1674 
1675  irpSp->Parameters.Others.Argument4 = (PVOID) 0;
1676 
1677  //
1678  // Fill in the irp fields appropriately
1679  //
1680  irpSp = IoGetNextIrpStackLocation(FlushContext->CurrIrp);
1681 
1682  irpSp->MajorFunction = IRP_MJ_SCSI;
1683  irpSp->Parameters.Scsi.Srb = srb;
1684 
1685  IoSetCompletionRoutine(FlushContext->CurrIrp, DiskFlushComplete, (PVOID)(ULONG_PTR)SyncCacheStatus, TRUE, TRUE, TRUE);
1686 
1687  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending srb flush on irp %p\n", FlushContext->CurrIrp));
1688 
1689  //
1690  // Send down the flush request
1691  //
1692  IoCallDriver(((PCOMMON_DEVICE_EXTENSION)fdoExt)->LowerDeviceObject, FlushContext->CurrIrp);
1693 }
1694 
1695 
1696 
1697 NTSTATUS
1698 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
1701  IN PIRP Irp,
1702  IN PVOID Context
1703  )
1704 
1705 /*++
1706 
1707 Routine Description:
1708 
1709  This completion routine is a wrapper around ClassIoComplete. It
1710  will complete all the flush requests that are tagged to it, set
1711  an event to signal the next group to proceed and return
1712 
1713 Arguments:
1714 
1715  Fdo - The device object which requested the completion routine
1716  Irp - The irp that is being completed
1717  Context - If disk had write cache enabled and SYNC CACHE command was sent as 1st part of FLUSH processing
1718  then context must carry the completion status of SYNC CACHE request,
1719  else context must be set to STATUS_SUCCESS.
1720 
1721 Return Value:
1722 
1723  STATUS_SUCCESS if successful, an error code otherwise
1724 
1725 --*/
1726 
1727 {
1728  PDISK_GROUP_CONTEXT FlushContext;
1729  NTSTATUS status;
1731  PDISK_DATA diskData;
1732 #ifdef _MSC_VER
1733  #pragma warning(suppress:4311) // pointer truncation from 'PVOID' to 'NTSTATUS'
1734 #endif
1735  NTSTATUS SyncCacheStatus = (NTSTATUS)(ULONG_PTR)Context;
1736 
1737  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DiskFlushComplete: %p %p\n", Fdo, Irp));
1738 
1739  //
1740  // Get the flush context from the device extension
1741  //
1742  fdoExt = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension;
1743  diskData = (PDISK_DATA)fdoExt->CommonExtension.DriverData;
1744  NT_ASSERT(diskData != NULL);
1745  _Analysis_assume_(diskData != NULL);
1746 
1747  FlushContext = &diskData->FlushContext;
1748 
1749  //
1750  // Make sure everything is in order
1751  //
1752  NT_ASSERT(Irp == FlushContext->CurrIrp);
1753 
1754  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushComplete: completing irp %p\n", Irp));
1755  status = ClassIoComplete(Fdo, Irp, &FlushContext->Srb.Srb);
1756 
1757  //
1758  // Make sure that ClassIoComplete did not decide to retry this request
1759  //
1761 
1762  //
1763  // If sync cache failed earlier, final status of the flush request needs to be failure
1764  // even if SRB_FUNCTION_FLUSH srb request succeeded
1765  //
1766  if (NT_SUCCESS(status) &&
1767  (!NT_SUCCESS(SyncCacheStatus))) {
1768  Irp->IoStatus.Status = status = SyncCacheStatus;
1769  }
1770 
1771  //
1772  // Complete the flush requests tagged to this one
1773  //
1774 
1775  while (!IsListEmpty(&FlushContext->CurrList)) {
1776 
1777  PLIST_ENTRY listEntry = RemoveHeadList(&FlushContext->CurrList);
1778  PIRP tempIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
1779 
1780  InitializeListHead(&tempIrp->Tail.Overlay.ListEntry);
1781  tempIrp->IoStatus = Irp->IoStatus;
1782 
1783  ClassReleaseRemoveLock(Fdo, tempIrp);
1785  }
1786 
1787 
1788  //
1789  // Notify the next group's representative that it may go ahead now
1790  //
1791  KeSetEvent(&FlushContext->Event, IO_NO_INCREMENT, FALSE);
1792 
1793 
1794  TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushComplete: irp %p status = 0x%x\n", Irp, status));
1795 
1796  return status;
1797 }
1798 
1799 
1800 
1801 NTSTATUS
1804  _In_reads_bytes_(Length) PCHAR ModeSelectBuffer,
1805  IN ULONG Length,
1806  IN BOOLEAN SavePage
1807  )
1808 
1809 /*++
1810 
1811 Routine Description:
1812 
1813  This routine sends a mode select command.
1814 
1815 Arguments:
1816 
1817  DeviceObject - Supplies the device object associated with this request.
1818 
1819  ModeSelectBuffer - Supplies a buffer containing the page data.
1820 
1821  Length - Supplies the length in bytes of the mode select buffer.
1822 
1823  SavePage - Indicates that parameters should be written to disk.
1824 
1825 Return Value:
1826 
1827  Length of the transferred data is returned.
1828 
1829 --*/
1830 
1831 {
1832  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
1833  PCDB cdb;
1834  SCSI_REQUEST_BLOCK srb = {0};
1835  ULONG retries = 1;
1836  ULONG length2;
1837  NTSTATUS status;
1838  PULONG buffer;
1839  PMODE_PARAMETER_BLOCK blockDescriptor;
1840  UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0};
1841  PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer;
1842  PSTOR_ADDR_BTL8 storAddrBtl8;
1843  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
1844  PSCSI_REQUEST_BLOCK srbPtr;
1845 
1846  PAGED_CODE();
1847 
1848  //
1849  // Check whether block length is available
1850  //
1851 
1852  if (fdoExtension->DiskGeometry.BytesPerSector == 0) {
1853 
1854  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskModeSelect: Block length is not available. Unable to send mode select\n"));
1855  NT_ASSERT(fdoExtension->DiskGeometry.BytesPerSector != 0);
1856  return STATUS_INVALID_PARAMETER;
1857  }
1858 
1859 
1860 
1861  length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
1862 
1863  //
1864  // Allocate buffer for mode select header, block descriptor, and mode page.
1865  //
1866 
1867  buffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
1868  length2,
1870 
1871  if (buffer == NULL) {
1873  }
1874 
1875  RtlZeroMemory(buffer, length2);
1876 
1877  //
1878  // Set length in header to size of mode page.
1879  //
1880 
1881  ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
1882 
1883  blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
1884 
1885  //
1886  // Set block length from the cached disk geometry
1887  //
1888 
1889  blockDescriptor->BlockLength[2] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector >> 16);
1890  blockDescriptor->BlockLength[1] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector >> 8);
1891  blockDescriptor->BlockLength[0] = (UCHAR) (fdoExtension->DiskGeometry.BytesPerSector);
1892 
1893  //
1894  // Copy mode page to buffer.
1895  //
1896 
1897  RtlCopyMemory(buffer + 3, ModeSelectBuffer, Length);
1898 
1899  //
1900  // Build the MODE SELECT CDB.
1901  //
1902 
1903  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1904 
1905  //
1906  // Set up STORAGE_REQUEST_BLOCK fields
1907  //
1908 
1909  srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
1910  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
1911  srbEx->Signature = SRB_SIGNATURE;
1912  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
1913  srbEx->SrbLength = sizeof(srbExBuffer);
1914  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
1915  srbEx->RequestPriority = IoPriorityNormal;
1916  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
1917  srbEx->NumSrbExData = 1;
1918 
1919  // Set timeout value from device extension.
1920  srbEx->TimeOutValue = fdoExtension->TimeOutValue * 2;
1921 
1922  //
1923  // Set up address fields
1924  //
1925 
1926  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
1927  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
1928  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
1929 
1930  //
1931  // Set up SCSI SRB extended data fields
1932  //
1933 
1934  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
1935  sizeof(STOR_ADDR_BTL8);
1936  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
1937  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
1938  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
1939  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
1940  srbExDataCdb16->CdbLength = 6;
1941 
1942  cdb = (PCDB)srbExDataCdb16->Cdb;
1943  } else {
1944  // Should not happen
1945  NT_ASSERT(FALSE);
1946 
1947  FREE_POOL(buffer);
1948  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskModeSelect: Insufficient extended SRB size\n"));
1949  return STATUS_INTERNAL_ERROR;
1950  }
1951 
1952  srbPtr = (PSCSI_REQUEST_BLOCK)srbEx;
1953 
1954  } else {
1955 
1956  srb.CdbLength = 6;
1957  cdb = (PCDB)srb.Cdb;
1958 
1959  //
1960  // Set timeout value from device extension.
1961  //
1962 
1963  srb.TimeOutValue = fdoExtension->TimeOutValue * 2;
1964 
1965  srbPtr = &srb;
1966  }
1967 
1968  cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1969  cdb->MODE_SELECT.SPBit = SavePage;
1970  cdb->MODE_SELECT.PFBit = 1;
1971  cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
1972 
1973 Retry:
1974 
1976  srbPtr,
1977  buffer,
1978  length2,
1979  TRUE);
1980 
1981  if (status == STATUS_VERIFY_REQUIRED) {
1982 
1983  //
1984  // Routine ClassSendSrbSynchronous does not retry requests returned with
1985  // this status.
1986  //
1987 
1988  if (retries--) {
1989 
1990  //
1991  // Retry request.
1992  //
1993 
1994  goto Retry;
1995  }
1996 
1997  } else if (SRB_STATUS(srbPtr->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
1999  }
2000 
2001  FREE_POOL(buffer);
2002 
2003  return status;
2004 } // end DiskModeSelect()
2005 
2006 
2007 //
2008 // This routine is structured as a work-item routine
2009 //
2010 VOID
2011 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2014  IN PVOID Context
2015  )
2016 
2017 {
2018  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension;
2019  DISK_CACHE_INFORMATION cacheInfo = { 0 };
2020  NTSTATUS status;
2022 
2023  PAGED_CODE();
2024 
2025  NT_ASSERT(WorkItem != NULL);
2027 
2028  status = DiskGetCacheInformation(fdoExtension, &cacheInfo);
2029 
2030  if (NT_SUCCESS(status) && (cacheInfo.WriteCacheEnabled == TRUE)) {
2031 
2032  cacheInfo.WriteCacheEnabled = FALSE;
2033 
2034  DiskSetCacheInformation(fdoExtension, &cacheInfo);
2035  }
2036 
2038 }
2039 
2040 
2041 //
2042 // This routine is structured as a work-item routine
2043 //
2044 VOID
2045 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2048  IN PVOID Context
2049  )
2050 {
2052  PIRP Irp = NULL;
2054  PDISK_DATA DiskData = (PDISK_DATA)FdoExtension->CommonExtension.DriverData;
2055  PVERIFY_INFORMATION verifyInfo = NULL;
2057  PCDB Cdb = NULL;
2058  LARGE_INTEGER byteOffset;
2059  LARGE_INTEGER sectorOffset;
2062  PSTORAGE_REQUEST_BLOCK srbEx = NULL;
2063  PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
2064  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL;
2065 
2066  PAGED_CODE();
2067 
2068  NT_ASSERT(WorkContext != NULL);
2069  _Analysis_assume_(WorkContext != NULL);
2070 
2071  Srb = WorkContext->Srb;
2072  Irp = WorkContext->Irp;
2073  verifyInfo = (PVERIFY_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
2074 
2075  //
2076  // We don't need to hold on to this memory as
2077  // the following operation may take some time
2078  //
2079 
2080  IoFreeWorkItem(WorkContext->WorkItem);
2081 
2082  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlVerifyThread: Spliting up the request\n"));
2083 
2084  //
2085  // Add disk offset to starting the sector
2086  //
2087 
2088  byteOffset.QuadPart = FdoExtension->CommonExtension.StartingOffset.QuadPart +
2089  verifyInfo->StartingOffset.QuadPart;
2090 
2091  //
2092  // Convert byte offset to the sector offset
2093  //
2094 
2095  sectorOffset.QuadPart = byteOffset.QuadPart >> FdoExtension->SectorShift;
2096 
2097  //
2098  // Convert byte count to sector count.
2099  //
2100 
2101  sectorCount = verifyInfo->Length >> FdoExtension->SectorShift;
2102 
2103  //
2104  // Make sure that all previous verify requests have indeed completed
2105  // This greatly reduces the possibility of a Denial-of-Service attack
2106  //
2107 
2108  KeWaitForMutexObject(&DiskData->VerifyMutex,
2109  Executive,
2110  KernelMode,
2111  FALSE,
2112  NULL);
2113 
2114  //
2115  // Initialize SCSI SRB for a verify CDB
2116  //
2117  if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2119  srbEx = (PSTORAGE_REQUEST_BLOCK)Srb;
2120 
2121  //
2122  // Set up STORAGE_REQUEST_BLOCK fields
2123  //
2124 
2125  srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
2126  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
2127  srbEx->Signature = SRB_SIGNATURE;
2128  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
2129  srbEx->SrbLength = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
2130  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
2131  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
2132  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
2133  srbEx->NumSrbExData = 1;
2134 
2135  //
2136  // Set up address fields
2137  //
2138 
2139  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
2140  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
2141  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
2142 
2143  //
2144  // Set up SCSI SRB extended data fields
2145  //
2146 
2147  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
2148  sizeof(STOR_ADDR_BTL8);
2149  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
2150  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
2151  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
2152  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
2153 
2154  Cdb = (PCDB)srbExDataCdb16->Cdb;
2155  if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
2156  srbExDataCdb16->CdbLength = 16;
2157  Cdb->CDB16.OperationCode = SCSIOP_VERIFY16;
2158  } else {
2159  srbExDataCdb16->CdbLength = 10;
2160  Cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2161  }
2162  } else {
2163  // Should not happen
2164  NT_ASSERT(FALSE);
2165 
2166  FREE_POOL(Srb);
2167  FREE_POOL(WorkContext);
2169  }
2170 
2171  } else {
2173 
2174  Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
2175  Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2176 
2177  Cdb = (PCDB)Srb->Cdb;
2178  if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
2179  Srb->CdbLength = 16;
2180  Cdb->CDB16.OperationCode = SCSIOP_VERIFY16;
2181  } else {
2182  Srb->CdbLength = 10;
2183  Cdb->CDB10.OperationCode = SCSIOP_VERIFY;
2184  }
2185 
2186  }
2187 
2188  while (NT_SUCCESS(status) && (sectorCount != 0)) {
2189 
2191 
2192  if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2193 
2194  //
2195  // Reset status fields
2196  //
2197 
2198  srbEx->SrbStatus = 0;
2199  srbExDataCdb16->ScsiStatus = 0;
2200 
2201  //
2202  // Calculate the request timeout value based
2203  // on the number of sectors being verified
2204  //
2205 
2206  srbEx->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue;
2207  } else {
2208 
2209  //
2210  // Reset status fields
2211  //
2212 
2213  Srb->SrbStatus = 0;
2214  Srb->ScsiStatus = 0;
2215 
2216  //
2217  // Calculate the request timeout value based
2218  // on the number of sectors being verified
2219  //
2220 
2221  Srb->TimeOutValue = ((numSectors + 0x7F) >> 7) * FdoExtension->TimeOutValue;
2222  }
2223 
2224  //
2225  // Update verify CDB info.
2226  // NOTE - CDB opcode and length has been initialized prior to entering
2227  // the while loop
2228  //
2229 
2230  if (TEST_FLAG(FdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
2231 
2232  REVERSE_BYTES_QUAD(&Cdb->CDB16.LogicalBlock, &sectorOffset);
2233  REVERSE_BYTES_SHORT(&Cdb->CDB16.TransferLength[2], &numSectors);
2234  } else {
2235 
2236  //
2237  // Move little endian values into CDB in big endian format
2238  //
2239 
2240  Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
2241  Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
2242  Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
2243  Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
2244 
2245  Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numSectors)->Byte1;
2246  Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numSectors)->Byte0;
2247  }
2248 
2250  Srb,
2251  NULL,
2252  0,
2253  FALSE);
2254 
2256 
2257  sectorCount -= numSectors;
2258  sectorOffset.QuadPart += numSectors;
2259  }
2260 
2261  KeReleaseMutex(&DiskData->VerifyMutex, FALSE);
2262 
2263  Irp->IoStatus.Status = status;
2264  Irp->IoStatus.Information = 0;
2265 
2268 
2269  FREE_POOL(Srb);
2270  FREE_POOL(WorkContext);
2271 }
2272 
2273 
2274 VOID
2275 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2279  NTSTATUS *Status,
2280  BOOLEAN *Retry
2281  )
2282 
2283 /*++
2284 
2285 Routine Description:
2286 
2287  This routine checks the type of error. If the error indicates an underrun
2288  then indicate the request should be retried.
2289 
2290 Arguments:
2291 
2292  Fdo - Supplies a pointer to the functional device object.
2293 
2294  Srb - Supplies a pointer to the failing Srb.
2295 
2296  Status - Status with which the IRP will be completed.
2297 
2298  Retry - Indication of whether the request will be retried.
2299 
2300 Return Value:
2301 
2302  None.
2303 
2304 --*/
2305 
2306 {
2307  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2308  PSTORAGE_REQUEST_BLOCK srbEx;
2309  PCDB cdb = NULL;
2310  UCHAR scsiStatus = 0;
2311  UCHAR senseBufferLength = 0;
2312  PVOID senseBuffer = NULL;
2313  CDB noOp = {0};
2314 
2315  //
2316  // Get relevant fields from SRB
2317  //
2318  if (Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) {
2319 
2320  srbEx = (PSTORAGE_REQUEST_BLOCK)Srb;
2321 
2322  //
2323  // Look for SCSI SRB specific fields
2324  //
2325  if ((srbEx->SrbFunction == SRB_FUNCTION_EXECUTE_SCSI) &&
2326  (srbEx->NumSrbExData > 0)) {
2327  cdb = GetSrbScsiData(srbEx, NULL, NULL, &scsiStatus, &senseBuffer, &senseBufferLength);
2328 
2329  //
2330  // cdb and sense buffer should not be NULL
2331  //
2332  NT_ASSERT(cdb != NULL);
2333  NT_ASSERT(senseBuffer != NULL);
2334 
2335  }
2336 
2337  if (cdb == NULL) {
2338 
2339  //
2340  // Use a cdb that is all 0s
2341  //
2342  cdb = &noOp;
2343  }
2344 
2345  } else {
2346 
2347  cdb = (PCDB)(Srb->Cdb);
2348  scsiStatus = Srb->ScsiStatus;
2349  senseBufferLength = Srb->SenseInfoBufferLength;
2350  senseBuffer = Srb->SenseInfoBuffer;
2351  }
2352 
2353  if (*Status == STATUS_DATA_OVERRUN &&
2354  (cdb != NULL) &&
2355  (IS_SCSIOP_READWRITE(cdb->CDB10.OperationCode))) {
2356 
2357  *Retry = TRUE;
2358 
2359  //
2360  // Update the error count for the device.
2361  //
2362 
2363  fdoExtension->ErrorCount++;
2364 
2365  } else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
2366  scsiStatus == SCSISTAT_BUSY) {
2367 
2368  //
2369  // a disk drive should never be busy this long. Reset the scsi bus
2370  // maybe this will clear the condition.
2371  //
2372 
2373  ResetBus(Fdo);
2374 
2375  //
2376  // Update the error count for the device.
2377  //
2378 
2379  fdoExtension->ErrorCount++;
2380 
2381  } else {
2382 
2383  BOOLEAN invalidatePartitionTable = FALSE;
2384 
2385  //
2386  // See if this might indicate that something on the drive has changed.
2387  //
2388 
2389  if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
2390  (senseBuffer != NULL) && (cdb != NULL)) {
2391 
2393  UCHAR senseKey = 0;
2394  UCHAR asc = 0;
2395  UCHAR ascq = 0;
2396 
2397  validSense = ScsiGetSenseKeyAndCodes(senseBuffer,
2398  senseBufferLength,
2400  &senseKey,
2401  &asc,
2402  &ascq);
2403 
2404  if (validSense) {
2405 
2406  switch (senseKey) {
2407 
2409 
2410  switch (asc) {
2411 
2413  {
2414  //
2415  // Look to see if this is an Io request with the ForceUnitAccess flag set
2416  //
2417  if (((cdb->CDB10.OperationCode == SCSIOP_WRITE) ||
2418  (cdb->CDB10.OperationCode == SCSIOP_WRITE16)) &&
2419  (cdb->CDB10.ForceUnitAccess))
2420  {
2421  PDISK_DATA diskData = (PDISK_DATA)fdoExtension->CommonExtension.DriverData;
2422 
2424  {
2425  PIO_ERROR_LOG_PACKET logEntry = NULL;
2426 
2427  //
2428  // The user has explicitly requested that write caching be turned on.
2429  // Warn the user that writes with FUA enabled are not working and that
2430  // they should disable write cache.
2431  //
2432 
2433  logEntry = IoAllocateErrorLogEntry(fdoExtension->DeviceObject,
2434  sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG)));
2435 
2436  if (logEntry != NULL)
2437  {
2438  logEntry->FinalStatus = *Status;
2440  logEntry->SequenceNumber = 0;
2441  logEntry->MajorFunctionCode = IRP_MJ_SCSI;
2442  logEntry->IoControlCode = 0;
2443  logEntry->RetryCount = 0;
2444  logEntry->UniqueErrorValue = 0;
2445  logEntry->DumpDataSize = 4 * sizeof(ULONG);
2446 
2447  logEntry->DumpData[0] = diskData->ScsiAddress.PortNumber;
2448  logEntry->DumpData[1] = diskData->ScsiAddress.PathId;
2449  logEntry->DumpData[2] = diskData->ScsiAddress.TargetId;
2450  logEntry->DumpData[3] = diskData->ScsiAddress.Lun;
2451 
2452  //
2453  // Write the error log packet.
2454  //
2455 
2456  IoWriteErrorLogEntry(logEntry);
2457  }
2458  }
2459  else
2460  {
2461  //
2462  // Turn off write caching on this device. This is so that future
2463  // critical requests need not be sent down with ForceUnitAccess
2464  //
2465  PIO_WORKITEM workItem = IoAllocateWorkItem(Fdo);
2466 
2467  if (workItem)
2468  {
2469  IoQueueWorkItem(workItem, DisableWriteCache, CriticalWorkQueue, workItem);
2470  }
2471  }
2472 
2474  ADJUST_FUA_FLAG(fdoExtension);
2475 
2476 
2477  cdb->CDB10.ForceUnitAccess = FALSE;
2478  *Retry = TRUE;
2479 
2480  } else if ((cdb->CDB6FORMAT.OperationCode == SCSIOP_MODE_SENSE) &&
2481  (cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL)) {
2482 
2483  //
2484  // Mode sense for all pages failed. This command could fail with
2485  // SCSI_SENSE_ILLEGAL_REQUEST / SCSI_ADSENSE_INVALID_CDB if the data
2486  // to be returned is more than 256 bytes. In which case, try to get
2487  // only MODE_PAGE_CACHING since we only need the block descriptor.
2488  //
2489  // Simply change the page code and retry the request
2490  //
2491 
2492  cdb->MODE_SENSE.PageCode = MODE_PAGE_CACHING;
2493  *Retry = TRUE;
2494  }
2495 
2496  break;
2497  }
2498  } // end switch(asc)
2499  break;
2500  }
2501 
2502  case SCSI_SENSE_NOT_READY: {
2503 
2504  switch (asc) {
2506  switch (ascq) {
2510  invalidatePartitionTable = TRUE;
2511  break;
2512  }
2513  } // end switch(ascq)
2514  break;
2515  }
2516 
2518  invalidatePartitionTable = TRUE;
2519  break;
2520  }
2521  } // end switch(asc)
2522  break;
2523  }
2524 
2525  case SCSI_SENSE_MEDIUM_ERROR: {
2526  invalidatePartitionTable = TRUE;
2527  break;
2528  }
2529 
2531  invalidatePartitionTable = TRUE;
2532  break;
2533  }
2534 
2536  {
2537  invalidatePartitionTable = TRUE;
2538  break;
2539  }
2540 
2542  invalidatePartitionTable = TRUE;
2543  break;
2544  }
2545 
2546  } // end switch(senseKey)
2547  } // end if (validSense)
2548  } else {
2549 
2550  //
2551  // On any exceptional scsi condition which might indicate that the
2552  // device was changed we will flush out the state of the partition
2553  // table.
2554  //
2555 
2556  switch (SRB_STATUS(Srb->SrbStatus)) {
2559  case SRB_STATUS_NO_DEVICE:
2560  case SRB_STATUS_NO_HBA:
2563  case SRB_STATUS_TIMEOUT:
2568  {
2569  invalidatePartitionTable = TRUE;
2570  break;
2571  }
2572 
2573  case SRB_STATUS_ERROR:
2574  {
2575  if (scsiStatus == SCSISTAT_RESERVATION_CONFLICT)
2576  {
2577  invalidatePartitionTable = TRUE;
2578  }
2579 
2580  break;
2581  }
2582  } // end switch(Srb->SrbStatus)
2583  }
2584 
2585  if (invalidatePartitionTable && TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
2586 
2587  //
2588  // Inform the upper layers that the volume
2589  // on this disk is in need of verification
2590  //
2591 
2592  SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME);
2593  }
2594  }
2595 
2596  return;
2597 }
2598 
2599 
2600 VOID
2601 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2604  IN ULONG_PTR Data
2605  )
2606 
2607 /*++
2608 
2609 Routine Description:
2610 
2611  This function checks to see if an SCSI logical unit requires speical
2612  flags to be set.
2613 
2614 Arguments:
2615 
2616  Fdo - Supplies the device object to be tested.
2617 
2618  InquiryData - Supplies the inquiry data returned by the device of interest.
2619 
2620  AdapterDescriptor - Supplies the capabilities of the device object.
2621 
2622 Return Value:
2623 
2624  None.
2625 
2626 --*/
2627 
2628 {
2629  PDEVICE_OBJECT fdo = FdoExtension->DeviceObject;
2630 
2631  PAGED_CODE();
2632 
2633  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "Disk SetSpecialHacks, Setting Hacks %p\n", (void*) Data));
2634 
2635  //
2636  // Found a listed controller. Determine what must be done.
2637  //
2638 
2640 
2641  //
2642  // Disable tagged queuing.
2643  //
2644 
2646  }
2647 
2649 
2650  //
2651  // Disable synchronous data transfers.
2652  //
2653 
2655 
2656  }
2657 
2659 
2660  //
2661  // Disable spinning down of drives.
2662  //
2663 
2664  SET_FLAG(FdoExtension->ScanForSpecialFlags,
2666 
2667  }
2668 
2670 
2671  //
2672  // Disable the drive's write cache
2673  //
2674 
2675  SET_FLAG(FdoExtension->ScanForSpecialFlags,
2677 
2678  }
2679 
2681 
2682  SET_FLAG(FdoExtension->ScanForSpecialFlags,
2684  }
2685 
2686  if (TEST_FLAG(fdo->Characteristics, FILE_REMOVABLE_MEDIA) &&
2688  ) {
2689 
2690  //
2691  // this is a list of vendors who require the START_UNIT command
2692  //
2693 
2694  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "DiskScanForSpecial (%p) => This unit requires "
2695  " START_UNITS\n", fdo));
2696  SET_FLAG(FdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
2697 
2698  }
2699 
2700  return;
2701 }
2702 
2703 
2704 VOID
2707  )
2708 
2709 /*++
2710 
2711 Routine Description:
2712 
2713  This command sends a reset bus command to the SCSI port driver.
2714 
2715 Arguments:
2716 
2717  Fdo - The functional device object for the logical unit with hardware problem.
2718 
2719 Return Value:
2720 
2721  None.
2722 
2723 --*/
2724 
2725 {
2726  PIO_STACK_LOCATION irpStack;
2727  PIRP irp;
2728 
2729  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2730  PSCSI_REQUEST_BLOCK srb;
2732  PSTORAGE_REQUEST_BLOCK srbEx = NULL;
2733  PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
2734 
2735  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "Disk ResetBus: Sending reset bus request to port driver.\n"));
2736 
2737  //
2738  // Allocate Srb from nonpaged pool.
2739  //
2740 
2741  context = ExAllocatePoolWithTag(NonPagedPoolNx,
2742  sizeof(COMPLETION_CONTEXT),
2744 
2745  if(context == NULL) {
2746  return;
2747  }
2748 
2749  //
2750  // Save the device object in the context for use by the completion
2751  // routine.
2752  //
2753 
2754  context->DeviceObject = Fdo;
2755  srb = &context->Srb.Srb;
2756 
2757  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2758  srbEx = &context->Srb.SrbEx;
2759 
2760  //
2761  // Zero out srb
2762  //
2763 
2764  RtlZeroMemory(srbEx, sizeof(context->Srb.SrbExBuffer));
2765 
2766  //
2767  // Set up STORAGE_REQUEST_BLOCK fields
2768  //
2769 
2770  srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
2771  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
2772  srbEx->Signature = SRB_SIGNATURE;
2773  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
2774  srbEx->SrbLength = sizeof(context->Srb.SrbExBuffer);
2775  srbEx->SrbFunction = SRB_FUNCTION_RESET_BUS;
2776  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
2777 
2778  //
2779  // Set up address fields
2780  //
2781 
2782  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
2783  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
2784  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
2785 
2786  } else {
2787 
2788  //
2789  // Zero out srb.
2790  //
2791 
2793 
2794  //
2795  // Write length to SRB.
2796  //
2797 
2799 
2801 
2802  }
2803 
2804  //
2805  // Build the asynchronous request to be sent to the port driver.
2806  // Since this routine is called from a DPC the IRP should always be
2807  // available.
2808  //
2809 
2810  irp = IoAllocateIrp(Fdo->StackSize, FALSE);
2811 
2812  if (irp == NULL) {
2813  FREE_POOL(context);
2814  return;
2815  }
2816 
2818 
2821  context,
2822  TRUE,
2823  TRUE,
2824  TRUE);
2825 
2826  irpStack = IoGetNextIrpStackLocation(irp);
2827 
2828  irpStack->MajorFunction = IRP_MJ_SCSI;
2829 
2830  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2831  srbEx->RequestPriority = IoGetIoPriorityHint(irp);
2832  srbEx->OriginalRequest = irp;
2833  } else {
2834  srb->OriginalRequest = irp;
2835  }
2836 
2837  //
2838  // Store the SRB address in next stack for port driver.
2839  //
2840 
2841  irpStack->Parameters.Scsi.Srb = srb;
2842 
2843  //
2844  // Call the port driver with the IRP.
2845  //
2846 
2847  IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
2848 
2849  return;
2850 
2851 } // end ResetBus()
2852 
2853 
2854 
2855 VOID
2858  IN PDISK_CACHE_INFORMATION CacheInfo,
2860  )
2861 {
2862  PIO_ERROR_LOG_PACKET logEntry = NULL;
2863 
2864  PAGED_CODE();
2865 
2866  logEntry = IoAllocateErrorLogEntry(FdoExtension->DeviceObject, sizeof(IO_ERROR_LOG_PACKET) + (4 * sizeof(ULONG)));
2867 
2868  if (logEntry != NULL)
2869  {
2870  PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
2871  BOOLEAN bIsEnabled = TEST_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
2872 
2873  logEntry->FinalStatus = Status;
2874  logEntry->ErrorCode = (bIsEnabled) ? IO_WRITE_CACHE_ENABLED : IO_WRITE_CACHE_DISABLED;
2875  logEntry->SequenceNumber = 0;
2876  logEntry->MajorFunctionCode = IRP_MJ_SCSI;
2877  logEntry->IoControlCode = 0;
2878  logEntry->RetryCount = 0;
2879  logEntry->UniqueErrorValue = 0x1;
2880  logEntry->DumpDataSize = 4 * sizeof(ULONG);
2881 
2882  logEntry->DumpData[0] = diskData->ScsiAddress.PathId;
2883  logEntry->DumpData[1] = diskData->ScsiAddress.TargetId;
2884  logEntry->DumpData[2] = diskData->ScsiAddress.Lun;
2885  logEntry->DumpData[3] = CacheInfo->WriteCacheEnabled;
2886 
2887  //
2888  // Write the error log packet.
2889  //
2890 
2891  IoWriteErrorLogEntry(logEntry);
2892  }
2893 }
2894 
2895 NTSTATUS
2898  IN PMODE_INFO_EXCEPTIONS ReturnPageData
2899  )
2900 {
2901  PMODE_PARAMETER_HEADER modeData;
2902  PMODE_INFO_EXCEPTIONS pageData;
2903  ULONG length;
2904 
2905  NTSTATUS status;
2906 
2907  PAGED_CODE();
2908 
2909  //
2910  // ReturnPageData is allocated by the caller
2911  //
2912 
2913  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
2916 
2917  if (modeData == NULL) {
2918 
2919  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Unable to allocate mode "
2920  "data buffer\n"));
2922  }
2923 
2924  RtlZeroMemory(modeData, MODE_DATA_SIZE);
2925 
2926  length = ClassModeSense(FdoExtension->DeviceObject,
2927  (PCHAR) modeData,
2930 
2931  if (length < sizeof(MODE_PARAMETER_HEADER)) {
2932 
2933  //
2934  // Retry the request in case of a check condition.
2935  //
2936 
2937  length = ClassModeSense(FdoExtension->DeviceObject,
2938  (PCHAR) modeData,
2941 
2942  if (length < sizeof(MODE_PARAMETER_HEADER)) {
2943  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Mode Sense failed\n"));
2944  FREE_POOL(modeData);
2945  return STATUS_IO_DEVICE_ERROR;
2946  }
2947  }
2948 
2949  //
2950  // If the length is greater than length indicated by the mode data reset
2951  // the data to the mode data.
2952  //
2953 
2954  if (length > (ULONG) (modeData->ModeDataLength + 1)) {
2955  length = modeData->ModeDataLength + 1;
2956  }
2957 
2958  //
2959  // Find the mode page for info exceptions
2960  //
2961 
2962  pageData = ClassFindModePage((PCHAR) modeData,
2963  length,
2965  TRUE);
2966 
2967  if (pageData != NULL) {
2968  RtlCopyMemory(ReturnPageData, pageData, sizeof(MODE_INFO_EXCEPTIONS));
2970  } else {
2972  }
2973 
2974  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: %s support SMART for device %p\n",
2975  NT_SUCCESS(status) ? "does" : "does not",
2976  FdoExtension->DeviceObject));
2977 
2978  FREE_POOL(modeData);
2979 
2980  return(status);
2981 }
2982 
2983 
2984 NTSTATUS
2987  IN PMODE_INFO_EXCEPTIONS PageData
2988  )
2989 
2990 {
2991  ULONG i;
2993 
2994  PAGED_CODE();
2995 
2996  //
2997  // We will attempt (twice) to issue the mode select with the page.
2998  // Make the setting persistant so that we don't have to turn it back
2999  // on after a bus reset.
3000  //
3001 
3002  for (i = 0; i < 2; i++)
3003  {
3004  status = DiskModeSelect(FdoExtension->DeviceObject,
3005  (PCHAR) PageData,
3006  sizeof(MODE_INFO_EXCEPTIONS),
3007  TRUE);
3008  }
3009 
3010  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_WMI, "DiskSetInfoExceptionInformation: %s for device %p\n",
3011  NT_SUCCESS(status) ? "succeeded" : "failed",
3012  FdoExtension->DeviceObject));
3013 
3014  return status;
3015 }
3016 
3017 NTSTATUS
3018 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3021  IN PDISK_CACHE_INFORMATION CacheInfo
3022  )
3023 /*++
3024 
3025 Routine Description:
3026 
3027  This function gets the caching mode page from the drive. This function
3028  is called from DiskIoctlGetCacheInformation() in response to the IOCTL
3029  IOCTL_DISK_GET_CACHE_INFORMATION. This is also called from the
3030  DisableWriteCache() worker thread to disable caching when write commands fail.
3031 
3032 Arguments:
3033 
3034  FdoExtension - The device extension for this device.
3035 
3036  CacheInfo - Buffer to receive the Cache Information.
3037 
3038 Return Value:
3039 
3040  NTSTATUS code
3041 
3042 --*/
3043 
3044 {
3045  PMODE_PARAMETER_HEADER modeData;
3046  PMODE_CACHING_PAGE pageData;
3047 
3048  ULONG length;
3049 
3050  PAGED_CODE();
3051 
3052 
3053 
3054  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
3057 
3058  if (modeData == NULL) {
3059 
3060  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetSetCacheInformation: Unable to allocate mode "
3061  "data buffer\n"));
3063  }
3064 
3065  RtlZeroMemory(modeData, MODE_DATA_SIZE);
3066 
3067  length = ClassModeSense(FdoExtension->DeviceObject,
3068  (PCHAR) modeData,
3071 
3072  if (length < sizeof(MODE_PARAMETER_HEADER)) {
3073 
3074  //
3075  // Retry the request in case of a check condition.
3076  //
3077 
3078  length = ClassModeSense(FdoExtension->DeviceObject,
3079  (PCHAR) modeData,
3082 
3083  if (length < sizeof(MODE_PARAMETER_HEADER)) {
3084 
3085  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetCacheInformation: Mode Sense failed\n"));
3086 
3087  FREE_POOL(modeData);
3088  return STATUS_IO_DEVICE_ERROR;
3089  }
3090  }
3091 
3092  //
3093  // If the length is greater than length indicated by the mode data reset
3094  // the data to the mode data.
3095  //
3096 
3097  if (length > (ULONG) (modeData->ModeDataLength + 1)) {
3098  length = modeData->ModeDataLength + 1;
3099  }
3100 
3101  //
3102  // Check to see if the write cache is enabled.
3103  //
3104 
3105  pageData = ClassFindModePage((PCHAR) modeData,
3106  length,
3108  TRUE);
3109 
3110  //
3111  // Check if valid caching page exists.
3112  //
3113 
3114  if (pageData == NULL) {
3115  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetCacheInformation: Unable to find caching mode page.\n"));
3116  FREE_POOL(modeData);
3117  return STATUS_NOT_SUPPORTED;
3118  }
3119 
3120  //
3121  // Copy the parameters over.
3122  //
3123 
3124  RtlZeroMemory(CacheInfo, sizeof(DISK_CACHE_INFORMATION));
3125 
3126  CacheInfo->ParametersSavable = pageData->PageSavable;
3127 
3128  CacheInfo->ReadCacheEnabled = !(pageData->ReadDisableCache);
3129  CacheInfo->WriteCacheEnabled = pageData->WriteCacheEnable;
3130 
3131 
3132  //
3133  // Translate the values in the mode page into the ones defined in
3134  // ntdddisk.h.
3135  //
3136 
3137  CacheInfo->ReadRetentionPriority =
3139  CacheInfo->WriteRetentionPriority =
3141 
3142  CacheInfo->DisablePrefetchTransferLength =
3143  ((pageData->DisablePrefetchTransfer[0] << 8) +
3144  pageData->DisablePrefetchTransfer[1]);
3145 
3146  CacheInfo->ScalarPrefetch.Minimum =
3147  ((pageData->MinimumPrefetch[0] << 8) + pageData->MinimumPrefetch[1]);
3148 
3149  CacheInfo->ScalarPrefetch.Maximum =
3150  ((pageData->MaximumPrefetch[0] << 8) + pageData->MaximumPrefetch[1]);
3151 
3152  if(pageData->MultiplicationFactor) {
3153  CacheInfo->PrefetchScalar = TRUE;
3154  CacheInfo->ScalarPrefetch.MaximumBlocks =
3155  ((pageData->MaximumPrefetchCeiling[0] << 8) +
3156  pageData->MaximumPrefetchCeiling[1]);
3157  }
3158 
3159 
3160  FREE_POOL(modeData);
3161  return STATUS_SUCCESS;
3162 }
3163 
3164 
3165 NTSTATUS
3166 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3169  IN PDISK_CACHE_INFORMATION CacheInfo
3170  )
3171 /*++
3172 
3173 Routine Description:
3174 
3175  This function sets the caching mode page in the drive. This function
3176  is also called from the DisableWriteCache() worker thread to disable
3177  caching when write commands fail.
3178 
3179 Arguments:
3180 
3181  FdoExtension - The device extension for this device.
3182 
3183  CacheInfo - Buffer the contains the Cache Information to be set on the drive.
3184 
3185 Return Value:
3186 
3187  NTSTATUS code
3188 
3189 --*/
3190 {
3191  PMODE_PARAMETER_HEADER modeData;
3192  ULONG length;
3193  PMODE_CACHING_PAGE pageData;
3194  ULONG i;
3196 
3197  PAGED_CODE();
3198 
3199  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
3202 
3203  if (modeData == NULL) {
3204 
3205  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Unable to allocate mode "
3206  "data buffer\n"));
3208  }
3209 
3210  RtlZeroMemory(modeData, MODE_DATA_SIZE);
3211 
3212  length = ClassModeSense(FdoExtension->DeviceObject,
3213  (PCHAR) modeData,
3216 
3217  if (length < sizeof(MODE_PARAMETER_HEADER)) {
3218 
3219  //
3220  // Retry the request in case of a check condition.
3221  //
3222 
3223  length = ClassModeSense(FdoExtension->DeviceObject,
3224  (PCHAR) modeData,
3227 
3228  if (length < sizeof(MODE_PARAMETER_HEADER)) {
3229 
3230  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Mode Sense failed\n"));
3231 
3232  FREE_POOL(modeData);
3233  return STATUS_IO_DEVICE_ERROR;
3234  }
3235  }
3236 
3237  //
3238  // If the length is greater than length indicated by the mode data reset
3239  // the data to the mode data.
3240  //
3241 
3242  if (length > (ULONG) (modeData->ModeDataLength + 1)) {
3243  length = modeData->ModeDataLength + 1;
3244  }
3245 
3246  //
3247  // Check to see if the write cache is enabled.
3248  //
3249 
3250  pageData = ClassFindModePage((PCHAR) modeData,
3251  length,
3253  TRUE);
3254 
3255  //
3256  // Check if valid caching page exists.
3257  //
3258 
3259  if (pageData == NULL) {
3260  FREE_POOL(modeData);
3261  return STATUS_NOT_SUPPORTED;
3262  }
3263 
3264  //
3265  // Don't touch any of the normal parameters - not all drives actually
3266  // use the correct size of caching mode page. Just change the things
3267  // which the user could have modified.
3268  //
3269 
3270  pageData->PageSavable = FALSE;
3271 
3272  pageData->ReadDisableCache = !(CacheInfo->ReadCacheEnabled);
3273  pageData->MultiplicationFactor = CacheInfo->PrefetchScalar;
3274  pageData->WriteCacheEnable = CacheInfo->WriteCacheEnabled;
3275 
3276  pageData->WriteRetensionPriority = (UCHAR)
3277  TRANSLATE_RETENTION_PRIORITY(CacheInfo->WriteRetentionPriority);
3278  pageData->ReadRetensionPriority = (UCHAR)
3279  TRANSLATE_RETENTION_PRIORITY(CacheInfo->ReadRetentionPriority);
3280 
3281  pageData->DisablePrefetchTransfer[0] =
3282  (UCHAR) (CacheInfo->DisablePrefetchTransferLength >> 8);
3283  pageData->DisablePrefetchTransfer[1] =
3284  (UCHAR) (CacheInfo->DisablePrefetchTransferLength & 0x00ff);
3285 
3286  pageData->MinimumPrefetch[0] =
3287  (UCHAR) (CacheInfo->ScalarPrefetch.Minimum >> 8);
3288  pageData->MinimumPrefetch[1] =
3289  (UCHAR) (CacheInfo->ScalarPrefetch.Minimum & 0x00ff);
3290 
3291  pageData->MaximumPrefetch[0] =
3292  (UCHAR) (CacheInfo->ScalarPrefetch.Maximum >> 8);
3293  pageData->MaximumPrefetch[1] =
3294  (UCHAR) (CacheInfo->ScalarPrefetch.Maximum & 0x00ff);
3295 
3296  if(pageData->MultiplicationFactor) {
3297 
3298  pageData->MaximumPrefetchCeiling[0] =
3299  (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks >> 8);
3300  pageData->MaximumPrefetchCeiling[1] =
3301  (UCHAR) (CacheInfo->ScalarPrefetch.MaximumBlocks & 0x00ff);
3302  }
3303 
3304  //
3305  // We will attempt (twice) to issue the mode select with the page.
3306  //
3307 
3308  for (i = 0; i < 2; i++) {
3309 
3310  status = DiskModeSelect(FdoExtension->DeviceObject,
3311  (PCHAR) pageData,
3312  (pageData->PageLength + 2),
3313  CacheInfo->ParametersSavable);
3314 
3315  if (NT_SUCCESS(status)) {
3316 
3317  if (CacheInfo->WriteCacheEnabled)
3318  {
3319  SET_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3320  }
3321  else
3322  {
3323  CLEAR_FLAG(FdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3324  }
3326 
3327  break;
3328  }
3329  }
3330 
3331  if (NT_SUCCESS(status))
3332  {
3333  } else {
3334 
3335  //
3336  // We were unable to modify the disk write cache setting
3337  //
3338 
3340  }
3341 
3342  FREE_POOL(modeData);
3343  return status;
3344 }
3345 
3346 NTSTATUS
3349  IN PIRP Irp
3350  )
3351 
3352 /*++
3353 
3354 Routine description:
3355 
3356  This routine services IOCTL_DISK_GET_CACHE_SETTING. It looks to
3357  see if there are any issues with the disk cache and whether the
3358  user had previously indicated that the cache is power-protected
3359 
3360 Arguments:
3361 
3362  Fdo - The functional device object processing the request
3363  Irp - The ioctl to be processed
3364 
3365 Return Value:
3366 
3367  STATUS_SUCCESS if successful, an error code otherwise
3368 
3369 --*/
3370 
3371 {
3372  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3375 
3376  PAGED_CODE();
3377 
3378  if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_SETTING))
3379  {
3381  }
3382  else
3383  {
3384  PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer;
3385 
3386  cacheSetting->Version = sizeof(DISK_CACHE_SETTING);
3387  cacheSetting->State = DiskCacheNormal;
3388 
3389  //
3390  // Determine whether it is safe to turn on the cache
3391  //
3393  {
3394  cacheSetting->State = DiskCacheWriteThroughNotSupported;
3395  }
3396 
3397  //
3398  // Determine whether it is possible to modify the cache setting
3399  //
3401  {
3402  cacheSetting->State = DiskCacheModifyUnsuccessful;
3403  }
3404 
3405  cacheSetting->IsPowerProtected = TEST_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
3406 
3407  Irp->IoStatus.Information = sizeof(DISK_CACHE_SETTING);
3408  }
3409 
3410  return status;
3411 }
3412 
3413 
3414 NTSTATUS
3417  IN PIRP Irp
3418  )
3419 
3420 /*++
3421 
3422 Routine description:
3423 
3424  This routine services IOCTL_DISK_SET_CACHE_SETTING. It allows
3425  the user to specify whether the disk cache is power-protected
3426  or not
3427 
3428  This function must be called at IRQL < DISPATCH_LEVEL.
3429 
3430 Arguments:
3431 
3432  Fdo - The functional device object processing the request
3433  Irp - The ioctl to be processed
3434 
3435 Return Value:
3436 
3437  STATUS_SUCCESS if successful, an error code otherwise
3438 
3439 --*/
3440 
3441 {
3442  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3445 
3446  //
3447  // This function must be called at less than dispatch level.
3448  // Fail if IRQL >= DISPATCH_LEVEL.
3449  //
3450  PAGED_CODE();
3451  CHECK_IRQL();
3452 
3453  if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_SETTING))
3454  {
3456  }
3457  else
3458  {
3459  PDISK_CACHE_SETTING cacheSetting = (PDISK_CACHE_SETTING)Irp->AssociatedIrp.SystemBuffer;
3460 
3461  if (cacheSetting->Version == sizeof(DISK_CACHE_SETTING))
3462  {
3463  ULONG isPowerProtected;
3464 
3465  //
3466  // Save away the user-defined override in our extension and the registry
3467  //
3468  if (cacheSetting->IsPowerProtected)
3469  {
3470  SET_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
3471  isPowerProtected = 1;
3472  }
3473  else
3474  {
3475  CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_POWER_PROTECTED);
3476  isPowerProtected = 0;
3477  }
3478  ADJUST_FUA_FLAG(fdoExtension);
3479 
3480  ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey, DiskDeviceCacheIsPowerProtected, isPowerProtected);
3481  }
3482  else
3483  {
3485  }
3486  }
3487 
3488  return status;
3489 }
3490 
3491 NTSTATUS
3494  IN OUT PIRP Irp
3495  )
3496 
3497 /*++
3498 
3499 Routine Description:
3500 
3501  This routine services IOCTL_DISK_GET_LENGTH_INFO. It returns
3502  the disk geometry to the caller.
3503 
3504  This function must be called at IRQL < DISPATCH_LEVEL.
3505 
3506 Arguments:
3507 
3508  DeviceObject - Supplies the device object associated with this request.
3509 
3510  Irp - The IRP to be processed
3511 
3512 Return Value:
3513 
3514  NTSTATUS code
3515 
3516 --*/
3517 
3518 {
3519  NTSTATUS status;
3520  PIO_STACK_LOCATION irpStack;
3521  PGET_LENGTH_INFORMATION lengthInfo;
3522  PFUNCTIONAL_DEVICE_EXTENSION p0Extension;
3523  PCOMMON_DEVICE_EXTENSION commonExtension;
3524  PDISK_DATA partitionZeroData;
3525  NTSTATUS oldReadyStatus;
3526 
3527  //
3528  // This function must be called at less than dispatch level.
3529  // Fail if IRQL >= DISPATCH_LEVEL.
3530  //
3531  PAGED_CODE();
3532  CHECK_IRQL();
3533 
3534  //
3535  // Initialization
3536  //
3537 
3538  commonExtension = DeviceObject->DeviceExtension;
3539  irpStack = IoGetCurrentIrpStackLocation(Irp);
3540  p0Extension = commonExtension->PartitionZeroExtension;
3541  partitionZeroData = ((PDISK_DATA) p0Extension->CommonExtension.DriverData);
3542 
3543  //
3544  // Check that the buffer is large enough.
3545  //
3546 
3547  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_LENGTH_INFORMATION)) {
3548  return STATUS_BUFFER_TOO_SMALL;
3549  }
3550 
3551  //
3552  // Update the geometry in case it has changed
3553  //
3554 
3555  status = DiskReadDriveCapacity(p0Extension->DeviceObject);
3556 
3557  //
3558  // Note whether the drive is ready. If the status has changed then
3559  // notify pnp.
3560  //
3561 
3562  oldReadyStatus = InterlockedExchange(&(partitionZeroData->ReadyStatus), status);
3563 
3564  if(partitionZeroData->ReadyStatus != oldReadyStatus) {
3566  }
3567 
3568  if(!NT_SUCCESS(status)) {
3569  return status;
3570  }
3571  lengthInfo = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
3572 
3573  lengthInfo->Length = commonExtension->PartitionLength;
3574 
3576  Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
3577 
3578  return status;
3579 }
3580 
3581 NTSTATUS
3584  IN OUT PIRP Irp
3585  )
3586 
3587 /*++
3588 
3589 Routine Description:
3590 
3591  This routine services IOCTL_DISK_GET_DRIVE_GEOMETRY. It returns
3592  the disk geometry to the caller.
3593 
3594  This function must be called at IRQL < DISPATCH_LEVEL.
3595 
3596 Arguments:
3597 
3598  DeviceObject - Supplies the device object associated with this request.
3599 
3600  Irp - IRP with a return buffer large enough to receive the
3601  extended geometry information.
3602 
3603 Return Value:
3604 
3605  NTSTATUS code
3606 
3607 --*/
3608 
3609 {
3610  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3611  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3612  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
3614  NTSTATUS status;
3615 
3616  //
3617  // This function must be called at less than dispatch level.
3618  // Fail if IRQL >= DISPATCH_LEVEL.
3619  //
3620  PAGED_CODE();
3621  CHECK_IRQL();
3622 
3623  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) {
3624 
3625  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetDriveGeometry: Output buffer too small.\n"));
3626  return STATUS_BUFFER_TOO_SMALL;
3627  }
3628 
3629  if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
3630 
3631  //
3632  // Issue ReadCapacity to update device extension
3633  // with information for current media.
3634  //
3635 
3636  status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
3637 
3638  //
3639  // Note whether the drive is ready.
3640  //
3641 
3642  diskData->ReadyStatus = status;
3643 
3644  if (!NT_SUCCESS(status)) {
3645  return status;
3646  }
3647  }
3648 
3649  //
3650  // Copy drive geometry information from device extension.
3651  //
3652 
3653  RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
3654  &(fdoExtension->DiskGeometry),
3655  sizeof(DISK_GEOMETRY));
3656 
3657  if (((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector == 0) {
3658  ((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector = 512;
3659  }
3660  Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
3661  return STATUS_SUCCESS;
3662 }
3663 
3667  DISK_PARTITION_INFO Partition;
3668  DISK_DETECTION_INFO Detection;
3670 
3671 NTSTATUS
3674  IN OUT PIRP Irp
3675  )
3676 
3677 /*++
3678 
3679 Routine Description:
3680 
3681  This routine services IOCTL_DISK_GET_DRIVE_GEOMETRY_EX. It returns
3682  the extended disk geometry to the caller.
3683 
3684  This function must be called at IRQL < DISPATCH_LEVEL.
3685 
3686 Arguments:
3687 
3688  DeviceObject - The device object to obtain the geometry for.
3689 
3690  Irp - IRP with a return buffer large enough to receive the
3691  extended geometry information.
3692 
3693 Return Value:
3694 
3695  NTSTATUS code
3696 
3697 --*/
3698 
3699 {
3700  NTSTATUS status;
3701  PIO_STACK_LOCATION irpStack;
3702  PCOMMON_DEVICE_EXTENSION commonExtension;
3703  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
3704  PDISK_DATA diskData;
3705  PDISK_GEOMETRY_EX_INTERNAL geometryEx;
3707 
3708  //
3709  // This function must be called at less than dispatch level.
3710  // Fail if IRQL >= DISPATCH_LEVEL.
3711  //
3712  PAGED_CODE();
3713  CHECK_IRQL();
3714 
3715  //
3716  // Setup parameters
3717  //
3718 
3719  commonExtension = DeviceObject->DeviceExtension;
3720  fdoExtension = DeviceObject->DeviceExtension;
3721  diskData = (PDISK_DATA)(commonExtension->DriverData);
3722  irpStack = IoGetCurrentIrpStackLocation ( Irp );
3723  geometryEx = NULL;
3724  OutputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
3725 
3726  //
3727  // Check that the buffer is large enough. It must be large enough
3728  // to hold at lest the Geometry and DiskSize fields of of the
3729  // DISK_GEOMETRY_EX structure.
3730  //
3731 
3733 
3734  //
3735  // Buffer too small. Bail out, telling the caller the required
3736  // size.
3737  //
3738 
3739  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetDriveGeometryEx: Output buffer too small.\n"));
3741  return status;
3742  }
3743 
3744  if (TEST_FLAG (DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
3745 
3746  //
3747  // Issue a ReadCapacity to update device extension
3748  // with information for the current media.
3749  //
3750 
3751  status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
3752 
3753  diskData->ReadyStatus = status;
3754 
3755  if (!NT_SUCCESS (status)) {
3756  return status;
3757  }
3758  }
3759 
3760  //
3761  // Copy drive geometry.
3762  //
3763 
3764  geometryEx = (PDISK_GEOMETRY_EX_INTERNAL)Irp->AssociatedIrp.SystemBuffer;
3765  geometryEx->Geometry = fdoExtension->DiskGeometry;
3766  if (geometryEx->Geometry.BytesPerSector == 0) {
3767  geometryEx->Geometry.BytesPerSector = 512;
3768  }
3769  geometryEx->DiskSize = commonExtension->PartitionZeroExtension->CommonExtension.PartitionLength;
3770 
3771  //
3772  // If the user buffer is large enough to hold the partition information
3773  // then add that as well.
3774  //
3775 
3777 
3778  geometryEx->Partition.SizeOfPartitionInfo = sizeof (geometryEx->Partition);
3779  geometryEx->Partition.PartitionStyle = diskData->PartitionStyle;
3780 
3781  switch ( diskData->PartitionStyle ) {
3782 
3783  case PARTITION_STYLE_GPT:
3784 
3785  //
3786  // Copy GPT signature.
3787  //
3788 
3789  geometryEx->Partition.Gpt.DiskId = diskData->Efi.DiskId;
3790  break;
3791 
3792  case PARTITION_STYLE_MBR:
3793 
3794  //
3795  // Copy MBR signature and checksum.
3796  //
3797 
3798  geometryEx->Partition.Mbr.Signature = diskData->Mbr.Signature;
3799  geometryEx->Partition.Mbr.CheckSum = diskData->Mbr.MbrCheckSum;
3800  break;
3801 
3802  default:
3803 
3804  //
3805  // This is a raw disk. Zero out the signature area so
3806  // nobody gets confused.
3807  //
3808 
3809  RtlZeroMemory(&geometryEx->Partition, sizeof (geometryEx->Partition));
3810  }
3811  }
3812 
3813  //
3814  // If the buffer is large enough to hold the detection information,
3815  // then also add that.
3816  //
3817 
3819 
3820  geometryEx->Detection.SizeOfDetectInfo = sizeof (geometryEx->Detection);
3821 
3822  status = DiskGetDetectInfo(fdoExtension, &geometryEx->Detection);
3823 
3824  //
3825  // Failed to obtain detection information, set to none.
3826  //
3827 
3828  if (!NT_SUCCESS (status)) {
3829  geometryEx->Detection.DetectionType = DetectNone;
3830  }
3831  }
3832 
3834  Irp->IoStatus.Information = min (OutputBufferLength, sizeof (DISK_GEOMETRY_EX_INTERNAL));
3835 
3836  return status;
3837 }
3838 
3839 NTSTATUS
3842  IN OUT PIRP Irp
3843  )
3844 
3845 /*++
3846 
3847 Routine Description:
3848 
3849  This routine services IOCTL_DISK_GET_CACHE_INFORMATION. It reads
3850  the caching mode page from the device and returns information to
3851  the caller. After validating the user parameter it calls the
3852  DiskGetCacheInformation() function to get the mode page.
3853 
3854  This function must be called at IRQL < DISPATCH_LEVEL.
3855 
3856 Arguments:
3857 
3858  DeviceObject - Supplies the device object associated with this request.
3859 
3860  Irp - The IRP to be processed
3861 
3862 Return Value:
3863 
3864  NTSTATUS code
3865 
3866 --*/
3867 
3868 {
3869  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3871  PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer;
3872  NTSTATUS status;
3873 
3874  //
3875  // This function must be called at less than dispatch level.
3876  // Fail if IRQL >= DISPATCH_LEVEL.
3877  //
3878  PAGED_CODE();
3879  CHECK_IRQL();
3880 
3881  //
3882  // Validate the request.
3883  //
3884 
3885  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetCacheInformation: DeviceObject %p Irp %p\n", DeviceObject, Irp));
3886 
3887  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_INFORMATION)) {
3888 
3889  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetCacheInformation: Output buffer too small.\n"));
3890  return STATUS_BUFFER_TOO_SMALL;
3891  }
3892 
3893  status = DiskGetCacheInformation(fdoExtension, cacheInfo);
3894 
3895  if (NT_SUCCESS(status)) {
3896  Irp->IoStatus.Information = sizeof(DISK_CACHE_INFORMATION);
3897 
3898  //
3899  // Make sure write cache setting is reflected in device extension
3900  //
3901  if (cacheInfo->WriteCacheEnabled)
3902  {
3903  SET_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3904  }
3905  else
3906  {
3907  CLEAR_FLAG(fdoExtension->DeviceFlags, DEV_WRITE_CACHE);
3908  }
3909  ADJUST_FUA_FLAG(fdoExtension);
3910 
3911  }
3912  return status;
3913 }
3914 
3915 
3916 NTSTATUS
3919  IN OUT PIRP Irp
3920  )
3921 
3922 /*++
3923 
3924 Routine Description:
3925 
3926  This routine services IOCTL_DISK_SET_CACHE_INFORMATION. It allows
3927  the caller to set the caching mode page on the device. This function
3928  validates the user parameter and calls the DiskSetCacheInformation()
3929  function to set the mode page. It also stores the cache value in the
3930  device extension and registry.
3931 
3932  This function must be called at IRQL < DISPATCH_LEVEL.
3933 
3934 Arguments:
3935 
3936  DeviceObject - Supplies the device object associated with this request.
3937 
3938  Irp - The IRP to be processed
3939 
3940 Return Value:
3941 
3942  NTSTATUS code
3943 
3944 --*/
3945 
3946 {
3947  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
3948  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3949  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
3951  PDISK_CACHE_INFORMATION cacheInfo = Irp->AssociatedIrp.SystemBuffer;
3952  NTSTATUS status;
3953 
3954  //
3955  // This function must be called at less than dispatch level.
3956  // Fail if IRQL is equal or above DISPATCH_LEVEL.
3957  //
3958 
3959  PAGED_CODE();
3960  CHECK_IRQL();
3961 
3962  //
3963  // Validate the request.
3964  //
3965 
3966  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSetCacheInformation: DeviceObject %p Irp %p\n", DeviceObject, Irp));
3967 
3968  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(DISK_CACHE_INFORMATION)) {
3969 
3970  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSetCacheInformation: Input buffer length mismatch.\n"));
3972  }
3973 
3974  status = DiskSetCacheInformation(fdoExtension, cacheInfo);
3975 
3976  //
3977  // Save away the user-defined override in our extension and the registry
3978  //
3979  if (cacheInfo->WriteCacheEnabled) {
3981  } else {
3983  }
3984 
3985  ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey,
3987 
3988  DiskLogCacheInformation(fdoExtension, cacheInfo, status);
3989 
3990  return status;
3991 }
3992 
3993 NTSTATUS
3996  IN OUT PIRP Irp
3997  )
3998 
3999 /*++
4000 
4001 Routine Description:
4002 
4003  This routine services IOCTL_STORAGE_GET_MEDIA_TYPES_EX. It returns
4004  the media type information to the caller. After validating the user
4005  parameter it calls DiskDetermineMediaTypes() to get the media type.
4006 
4007  This function must be called at IRQL < DISPATCH_LEVEL.
4008 
4009 Arguments:
4010 
4011  DeviceObject - Supplies the device object associated with this request.
4012 
4013  Irp - The IRP to be processed
4014 
4015 Return Value:
4016 
4017  NTSTATUS code
4018 
4019 --*/
4020 
4021 {
4022  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4024  NTSTATUS status;
4025 
4026  PMODE_PARAMETER_HEADER modeData;
4027  PMODE_PARAMETER_BLOCK blockDescriptor;
4028  PSCSI_REQUEST_BLOCK srb;
4029  PCDB cdb;
4030  ULONG modeLength;
4031  ULONG retries = 4;
4032  UCHAR densityCode = 0;
4033  BOOLEAN writable = TRUE;
4034  BOOLEAN mediaPresent = FALSE;
4035  ULONG srbSize;
4036  PSTORAGE_REQUEST_BLOCK srbEx = NULL;
4037  PSTOR_ADDR_BTL8 storAddrBtl8 = NULL;
4038  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16 = NULL;
4039 
4040  //
4041  // This function must be called at less than dispatch level.
4042  // Fail if IRQL >= DISPATCH_LEVEL.
4043  //
4044  PAGED_CODE();
4045  CHECK_IRQL();
4046 
4047  //
4048  // Validate the request.
4049  //
4050 
4051  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4052 
4053  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_MEDIA_TYPES)) {
4054 
4055  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Output buffer too small.\n"));
4056  return STATUS_BUFFER_TOO_SMALL;
4057  }
4058 
4059  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4061  } else {
4062  srbSize = SCSI_REQUEST_BLOCK_SIZE;
4063  }
4064 
4065  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4066  srbSize,
4067  DISK_TAG_SRB);
4068 
4069  if (srb == NULL) {
4070  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n"));
4072  }
4073 
4074  RtlZeroMemory(srb, srbSize);
4075 
4076  //
4077  // Send a TUR to determine if media is present.
4078  //
4079 
4080  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4081  srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
4082 
4083  //
4084  // Set up STORAGE_REQUEST_BLOCK fields
4085  //
4086 
4088  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
4089  srbEx->Signature = SRB_SIGNATURE;
4090  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
4091  srbEx->SrbLength = srbSize;
4092  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
4093  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
4094  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
4095  srbEx->NumSrbExData = 1;
4096 
4097  // Set timeout value.
4098  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
4099 
4100  //
4101  // Set up address fields
4102  //
4103 
4104  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
4105  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
4106  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
4107 
4108  //
4109  // Set up SCSI SRB extended data fields
4110  //
4111 
4112  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
4113  sizeof(STOR_ADDR_BTL8);
4114  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
4115  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
4116  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
4117  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
4118  srbExDataCdb16->CdbLength = 6;
4119 
4120  cdb = (PCDB)srbExDataCdb16->Cdb;
4121  } else {
4122  // Should not happen
4123  NT_ASSERT(FALSE);
4124 
4125  FREE_POOL(srb);
4126  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Insufficient extended SRB size.\n"));
4127  return STATUS_INTERNAL_ERROR;
4128  }
4129 
4130  } else {
4131 
4134  srb->CdbLength = 6;
4135  cdb = (PCDB)srb->Cdb;
4136 
4137  //
4138  // Set timeout value.
4139  //
4140 
4141  srb->TimeOutValue = fdoExtension->TimeOutValue;
4142 
4143  }
4144  cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
4145 
4147  srb,
4148  NULL,
4149  0,
4150  FALSE);
4151 
4152  if (NT_SUCCESS(status)) {
4153  mediaPresent = TRUE;
4154  }
4155 
4156  modeLength = MODE_DATA_SIZE;
4157  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
4158  modeLength,
4160 
4161  if (modeData == NULL) {
4162  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n"));
4163  FREE_POOL(srb);
4165  }
4166 
4167  RtlZeroMemory(modeData, modeLength);
4168 
4169  //
4170  // Build the MODE SENSE CDB using previous SRB.
4171  //
4172 
4173  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4174  srbEx->SrbStatus = 0;
4175  srbExDataCdb16->ScsiStatus = 0;
4176  srbExDataCdb16->CdbLength = 6;
4177 
4178  //
4179  // Set timeout value from device extension.
4180  //
4181 
4182  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
4183  } else {
4184  srb->SrbStatus = 0;
4185  srb->ScsiStatus = 0;
4186  srb->CdbLength = 6;
4187 
4188  //
4189  // Set timeout value from device extension.
4190  //
4191 
4192  srb->TimeOutValue = fdoExtension->TimeOutValue;
4193  }
4194 
4195  //
4196  // Page code of 0x3F will return all pages.
4197  // This command could fail if the data to be returned is
4198  // more than 256 bytes. In which case, we should get only
4199  // the caching page since we only need the block descriptor.
4200  // DiskFdoProcessError will change the page code to
4201  // MODE_PAGE_CACHING if there is an error.
4202  //
4203 
4204  cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
4205  cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL;
4206  cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
4207 
4208 Retry:
4210  srb,
4211  modeData,
4212  modeLength,
4213  FALSE);
4214 
4215  if (status == STATUS_VERIFY_REQUIRED) {
4216 
4217  if (retries--) {
4218 
4219  //
4220  // Retry request.
4221  //
4222 
4223  goto Retry;
4224  }
4225  } else if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
4227  }
4228 
4230 
4231  //
4232  // Get the block descriptor.
4233  //
4234 
4235  if (modeData->BlockDescriptorLength != 0) {
4236 
4237  blockDescriptor = (PMODE_PARAMETER_BLOCK)((ULONG_PTR)modeData + sizeof(MODE_PARAMETER_HEADER));
4238  densityCode = blockDescriptor->DensityCode;
4239  }
4240 
4241  if (TEST_FLAG(modeData->DeviceSpecificParameter,
4243 
4244  writable = FALSE;
4245  }
4246 
4248  Irp,
4249  modeData->MediumType,
4250  densityCode,
4251  mediaPresent,
4252  writable);
4253  //
4254  // If the buffer was too small, DetermineMediaTypes updated the status and information and the request will fail.
4255  //
4256 
4257  } else {
4258  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Mode sense for header/bd failed. %lx\n", status));
4259  }
4260 
4261  FREE_POOL(srb);
4262  FREE_POOL(modeData);
4263 
4264  return status;
4265 }
4266 
4267 NTSTATUS
4270  IN OUT PIRP Irp
4271  )
4272 
4273 /*++
4274 
4275 Routine Description:
4276 
4277  This routine services IOCTL_STORAGE_PREDICT_FAILURE. If the device
4278  supports SMART then it returns any available failure data.
4279 
4280  This function must be called at IRQL < DISPATCH_LEVEL.
4281 
4282 Arguments:
4283 
4284  DeviceObject - Supplies the device object associated with this request.
4285 
4286  Irp - The IRP to be processed
4287 
4288 Return Value:
4289 
4290  NTSTATUS code
4291 
4292 --*/
4293 
4294 {
4295  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4296  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4297  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
4300 
4301  PSTORAGE_PREDICT_FAILURE checkFailure;
4302  STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
4303  IO_STATUS_BLOCK ioStatus = { 0 };
4304  KEVENT event;
4305 
4306  //
4307  // This function must be called at less than dispatch level.
4308  // Fail if IRQL >= DISPATCH_LEVEL.
4309  //
4310  PAGED_CODE();
4311  CHECK_IRQL();
4312 
4313  //
4314  // Validate the request.
4315  //
4316 
4317  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlPredictFailure: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4318 
4319  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_PREDICT_FAILURE)) {
4320 
4321  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlPredictFailure: Output buffer too small.\n"));
4322  return STATUS_BUFFER_TOO_SMALL;
4323  }
4324 
4325  //
4326  // See if the disk is predicting failure
4327  //
4328 
4329  checkFailure = (PSTORAGE_PREDICT_FAILURE)Irp->AssociatedIrp.SystemBuffer;
4330 
4332  ULONG readBufferSize;
4333  PUCHAR readBuffer;
4334  PIRP readIrp;
4335  PDEVICE_OBJECT topOfStack;
4336 
4337  checkFailure->PredictFailure = 0;
4338 
4340 
4342 
4343  //
4344  // SCSI disks need to have a read sent down to provoke any
4345  // failures to be reported.
4346  //
4347  // Issue a normal read operation. The error-handling code in
4348  // classpnp will take care of a failure prediction by logging the
4349  // correct event.
4350  //
4351 
4352  readBufferSize = fdoExtension->DiskGeometry.BytesPerSector;
4353  readBuffer = ExAllocatePoolWithTag(NonPagedPoolNx,
4354  readBufferSize,
4355  DISK_TAG_SMART);
4356 
4357  if (readBuffer != NULL) {
4359 
4360  offset.QuadPart = 0;
4362  topOfStack,
4363  readBuffer,
4364  readBufferSize,
4365  &offset,
4366  &event,
4367  &ioStatus);
4368 
4369  if (readIrp != NULL) {
4370 
4371  status = IoCallDriver(topOfStack, readIrp);
4372  if (status == STATUS_PENDING) {
4374  status = ioStatus.Status;
4375  }
4376 
4377 
4378  } else {
4380  }
4381 
4382  FREE_POOL(readBuffer);
4383  } else {
4385  }
4386 
4387  ObDereferenceObject(topOfStack);
4388  }
4389 
4391  {
4394 
4395  status = DiskReadFailurePredictStatus(fdoExtension, &diskSmartStatus);
4396 
4397  if (NT_SUCCESS(status)) {
4398 
4399  status = DiskReadFailurePredictData(fdoExtension,
4400  Irp->AssociatedIrp.SystemBuffer);
4401 
4402  if (diskSmartStatus.PredictFailure) {
4403  checkFailure->PredictFailure = 1;
4404  } else {
4405  checkFailure->PredictFailure = 0;
4406  }
4407 
4408  Irp->IoStatus.Information = sizeof(STORAGE_PREDICT_FAILURE);
4409  }
4410  } else {
4412  }
4413  }
4414  return status;
4415 }
4416 
4417 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
4418 NTSTATUS
4421  IN OUT PIRP Irp
4422  )
4423 
4424 /*++
4425 
4426 Routine Description:
4427 
4428  This routine services IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG. If the device
4429  supports SMART then it returns any available failure data.
4430 
4431  This function must be called at IRQL < DISPATCH_LEVEL.
4432 
4433 Arguments:
4434 
4435  DeviceObject - Supplies the device object associated with this request.
4436 
4437  Irp - The IRP to be processed
4438 
4439 Return Value:
4440 
4441  NTSTATUS code
4442 
4443 --*/
4444 
4445 {
4446  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4447  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4448  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
4451  PSTORAGE_FAILURE_PREDICTION_CONFIG enablePrediction;
4452 
4453  //
4454  // This function must be called at less than dispatch level.
4455  // Fail if IRQL >= DISPATCH_LEVEL.
4456  //
4457  PAGED_CODE();
4458  CHECK_IRQL();
4459 
4460  //
4461  // Validate the request.
4462  //
4463 
4464  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4465 
4466  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG) ||
4467  irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG)) {
4468 
4469  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Buffer too small.\n"));
4470  return STATUS_BUFFER_TOO_SMALL;
4471  }
4472 
4473  enablePrediction = (PSTORAGE_FAILURE_PREDICTION_CONFIG)Irp->AssociatedIrp.SystemBuffer;
4474 
4475  if (enablePrediction->Version != STORAGE_FAILURE_PREDICTION_CONFIG_V1 ||
4476  enablePrediction->Size < sizeof(STORAGE_FAILURE_PREDICTION_CONFIG)) {
4477  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Buffer version or size is incorrect.\n"));
4479  }
4480 
4481  if (enablePrediction->Reserved != 0) {
4482  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Reserved bytes are not zero!\n"));
4484  }
4485 
4486  //
4487  // Default to success. This might get overwritten on failure below.
4488  //
4490 
4491  //
4492  // If this is a "set" and the current state (enabled/disabled) is
4493  // different from the sender's desired state,
4494  //
4495  if (enablePrediction->Set && enablePrediction->Enabled != diskData->FailurePredictionEnabled) {
4498  //
4499  // SMART or IOCTL based failure prediction is being used so call
4500  // the generic function that is normally called in the WMI path.
4501  //
4502  status = DiskEnableDisableFailurePrediction(fdoExtension, enablePrediction->Enabled);
4503  } else if (diskData->ScsiInfoExceptionsSupported) {
4504  //
4505  // If we know that the device supports the Informational Exceptions
4506  // mode page, try to enable/disable failure prediction that way.
4507  //
4508  status = DiskEnableInfoExceptions(fdoExtension, enablePrediction->Enabled);
4509  }
4510  }
4511 
4512  //
4513  // Return the current state regardless if this was a "set" or a "get".
4514  //
4515  enablePrediction->Enabled = diskData->FailurePredictionEnabled;
4516 
4517  if (NT_SUCCESS(status)) {
4518  Irp->IoStatus.Information = sizeof(STORAGE_FAILURE_PREDICTION_CONFIG);
4519  }
4520 
4521  return status;
4522 }
4523 #endif //(NTDDI_VERSION >= NTDDI_WINBLUE)
4524 
4525 NTSTATUS
4528  IN OUT PIRP Irp
4529  )
4530 
4531 /*++
4532 
4533 Routine Description:
4534 
4535  This routine services IOCTL_DISK_VERIFY. After verifying
4536  user input, it starts the worker thread DiskIoctlVerifyThread()
4537  to verify the device.
4538 
4539 Arguments:
4540 
4541  DeviceObject - Supplies the device object associated with this request.
4542 
4543  Irp - The IRP to be processed
4544 
4545 Return Value:
4546 
4547  NTSTATUS code
4548 
4549 --*/
4550 
4551 {
4552  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4553  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4555  PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
4557  PSCSI_REQUEST_BLOCK srb;
4558  LARGE_INTEGER byteOffset;
4559  ULONG srbSize;
4560 
4561  //
4562  // Validate the request.
4563  //
4564 
4565  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4566 
4567  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(VERIFY_INFORMATION)) {
4568  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Input buffer length mismatch.\n"));
4570  }
4571 
4572  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4574  } else {
4575  srbSize = SCSI_REQUEST_BLOCK_SIZE;
4576  }
4577  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4578  srbSize,
4579  DISK_TAG_SRB);
4580 
4581  if (srb == NULL) {
4582  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Unable to allocate memory.\n"));
4584  }
4585 
4586  RtlZeroMemory(srb, srbSize);
4587 
4588  //
4589  // Add disk offset to starting sector.
4590  //
4591 
4592  byteOffset.QuadPart = commonExtension->StartingOffset.QuadPart +
4593  verifyInfo->StartingOffset.QuadPart;
4594 
4595  //
4596  // Perform a bounds check on the sector range
4597  //
4598 
4599  if ((verifyInfo->StartingOffset.QuadPart > commonExtension->PartitionLength.QuadPart) ||
4600  (verifyInfo->StartingOffset.QuadPart < 0)) {
4601 
4602  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Verify request to invalid sector.\n"));
4603  FREE_POOL(srb)
4605  } else {
4606 
4607  ULONGLONG bytesRemaining = commonExtension->PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart;
4608 
4609  if ((ULONGLONG)verifyInfo->Length > bytesRemaining) {
4610 
4611  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlVerify: Verify request to invalid sector.\n"));
4612  FREE_POOL(srb)
4614  }
4615  }
4616 
4617  Context = ExAllocatePoolWithTag(NonPagedPoolNx,
4620  if (Context) {
4621 
4622  Context->Irp = Irp;
4623  Context->Srb = srb;
4625 
4626  if (Context->WorkItem) {
4627 
4628  //
4629  // Queue the work item and return.
4630  //
4631 
4633 
4634  IoQueueWorkItem(Context->WorkItem,
4637  Context);
4638 
4639  return STATUS_PENDING;
4640  }
4641  FREE_POOL(Context);
4642  }
4643  FREE_POOL(srb)
4645 }
4646 
4647 NTSTATUS
4650  IN OUT PIRP Irp
4651  )
4652 
4653 /*++
4654 
4655 Routine Description:
4656 
4657  This routine services IOCTL_DISK_REASSIGN_BLOCKS. This IOCTL
4658  allows the caller to remap the defective blocks to a new
4659  location on the disk.
4660 
4661  This function must be called at IRQL < DISPATCH_LEVEL.
4662 
4663 Arguments:
4664 
4665  DeviceObject - Supplies the device object associated with this request.
4666 
4667  Irp - The IRP to be processed
4668 
4669 Return Value:
4670 
4671  NTSTATUS code
4672 
4673 --*/
4674 
4675 {
4676  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4678  NTSTATUS status;
4679  PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
4680  PSCSI_REQUEST_BLOCK srb;
4681  PCDB cdb;
4682  ULONG bufferSize;
4683  ULONG blockNumber;
4684  ULONG blockCount;
4685  ULONG srbSize;
4686  PSTORAGE_REQUEST_BLOCK srbEx;
4687  PSTOR_ADDR_BTL8 storAddrBtl8;
4688  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
4689 
4690  //
4691  // This function must be called at less than dispatch level.
4692  // Fail if IRQL >= DISPATCH_LEVEL.
4693  //
4694  PAGED_CODE();
4695  CHECK_IRQL();
4696 
4697  //
4698  // Validate the request.
4699  //
4700 
4701  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4702 
4703  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(REASSIGN_BLOCKS)) {
4704  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Input buffer length mismatch.\n"));
4706  }
4707 
4708  //
4709  // Make sure we have some data in the input buffer.
4710  //
4711 
4712  if (badBlocks->Count == 0) {
4713  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Invalid block count\n"));
4714  return STATUS_INVALID_PARAMETER;
4715  }
4716 
4717  bufferSize = sizeof(REASSIGN_BLOCKS) + ((badBlocks->Count - 1) * sizeof(ULONG));
4718 
4719  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < bufferSize) {
4720  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Input buffer length mismatch for bad blocks.\n"));
4722  }
4723 
4724  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4726  } else {
4727  srbSize = SCSI_REQUEST_BLOCK_SIZE;
4728  }
4729  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4730  srbSize,
4731  DISK_TAG_SRB);
4732 
4733  if (srb == NULL) {
4734  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Unable to allocate memory.\n"));
4736  }
4737 
4738  RtlZeroMemory(srb, srbSize);
4739 
4740  //
4741  // Build the data buffer to be transferred in the input buffer.
4742  // The format of the data to the device is:
4743  //
4744  // 2 bytes Reserved
4745  // 2 bytes Length
4746  // x * 4 btyes Block Address
4747  //
4748  // All values are big endian.
4749  //
4750 
4751  badBlocks->Reserved = 0;
4752  blockCount = badBlocks->Count;
4753 
4754  //
4755  // Convert # of entries to # of bytes.
4756  //
4757 
4758  blockCount *= 4;
4759  badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
4760  badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
4761 
4762  //
4763  // Convert back to number of entries.
4764  //
4765 
4766  blockCount /= 4;
4767 
4768  for (; blockCount > 0; blockCount--) {
4769 
4770  blockNumber = badBlocks->BlockNumber[blockCount-1];
4771  REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1], (PFOUR_BYTE) &blockNumber);
4772  }
4773 
4774  //
4775  // Build a SCSI SRB containing a SCSIOP_REASSIGN_BLOCKS cdb
4776  //
4777 
4778  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4779  srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
4780 
4781  //
4782  // Set up STORAGE_REQUEST_BLOCK fields
4783  //
4784 
4786  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
4787  srbEx->Signature = SRB_SIGNATURE;
4788  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
4789  srbEx->SrbLength = srbSize;
4790  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
4791  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
4792  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
4793  srbEx->NumSrbExData = 1;
4794 
4795  // Set timeout value.
4796  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
4797 
4798  //
4799  // Set up address fields
4800  //
4801 
4802  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
4803  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
4804  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
4805 
4806  //
4807  // Set up SCSI SRB extended data fields
4808  //
4809 
4810  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
4811  sizeof(STOR_ADDR_BTL8);
4812  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
4813  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
4814  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
4815  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
4816  srbExDataCdb16->CdbLength = 6;
4817 
4818  cdb = (PCDB)srbExDataCdb16->Cdb;
4819  } else {
4820  // Should not happen
4821  NT_ASSERT(FALSE);
4822 
4823  FREE_POOL(srb);
4824  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Insufficient extended SRB size.\n"));
4825  return STATUS_INTERNAL_ERROR;
4826  }
4827 
4828  } else {
4831  srb->CdbLength = 6;
4832 
4833  //
4834  // Set timeout value.
4835  //
4836 
4837  srb->TimeOutValue = fdoExtension->TimeOutValue;
4838 
4839  cdb = (PCDB)srb->Cdb;
4840  }
4841 
4842  cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
4843 
4845  srb,
4846  badBlocks,
4847  bufferSize,
4848  TRUE);
4849 
4850  FREE_POOL(srb);
4851  return status;
4852 }
4853 
4854 NTSTATUS
4857  IN OUT PIRP Irp
4858  )
4859 
4860 /*++
4861 
4862 Routine Description:
4863 
4864  This routine services IOCTL_DISK_REASSIGN_BLOCKS_EX. This IOCTL
4865  allows the caller to remap the defective blocks to a new
4866  location on the disk. The input buffer contains 8-byte LBAs.
4867 
4868  This function must be called at IRQL < DISPATCH_LEVEL.
4869 
4870 Arguments:
4871 
4872  DeviceObject - Supplies the device object associated with this request.
4873 
4874  Irp - The IRP to be processed
4875 
4876 Return Value:
4877 
4878  NTSTATUS code
4879 
4880 --*/
4881 
4882 {
4883  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
4885  NTSTATUS status;
4886  PREASSIGN_BLOCKS_EX badBlocks = Irp->AssociatedIrp.SystemBuffer;
4887  PSCSI_REQUEST_BLOCK srb;
4888  PCDB cdb;
4889  LARGE_INTEGER blockNumber;
4890  ULONG bufferSize;
4891  ULONG blockCount;
4892  ULONG srbSize;
4893  PSTORAGE_REQUEST_BLOCK srbEx;
4894  PSTOR_ADDR_BTL8 storAddrBtl8;
4895  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
4896 
4897  //
4898  // This function must be called at less than dispatch level.
4899  // Fail if IRQL >= DISPATCH_LEVEL.
4900  //
4901  PAGED_CODE();
4902  CHECK_IRQL();
4903 
4904  //
4905  // Validate the request.
4906  //
4907 
4908  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: DeviceObject %p Irp %p\n", DeviceObject, Irp));
4909 
4910  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(REASSIGN_BLOCKS_EX)) {
4911  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Input buffer length mismatch.\n"));
4913  }
4914 
4915  //
4916  // Make sure we have some data in the input buffer.
4917  //
4918 
4919  if (badBlocks->Count == 0) {
4920  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Invalid block count\n"));
4921  return STATUS_INVALID_PARAMETER;
4922  }
4923 
4924  bufferSize = sizeof(REASSIGN_BLOCKS_EX) + ((badBlocks->Count - 1) * sizeof(LARGE_INTEGER));
4925 
4926  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < bufferSize) {
4927  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocksEx: Input buffer length mismatch for bad blocks.\n"));
4929  }
4930 
4931  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4933  } else {
4934  srbSize = SCSI_REQUEST_BLOCK_SIZE;
4935  }
4936  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
4937  srbSize,
4938  DISK_TAG_SRB);
4939 
4940  if (srb == NULL) {
4941  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Unable to allocate memory.\n"));
4943  }
4944 
4945  RtlZeroMemory(srb, srbSize);
4946 
4947  //
4948  // Build the data buffer to be transferred in the input buffer.
4949  // The format of the data to the device is:
4950  //
4951  // 2 bytes Reserved
4952  // 2 bytes Length
4953  // x * 8 btyes Block Address
4954  //
4955  // All values are big endian.
4956  //
4957 
4958  badBlocks->Reserved = 0;
4959  blockCount = badBlocks->Count;
4960 
4961  //
4962  // Convert # of entries to # of bytes.
4963  //
4964 
4965  blockCount *= 8;
4966  badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
4967  badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
4968 
4969  //
4970  // Convert back to number of entries.
4971  //
4972 
4973  blockCount /= 8;
4974 
4975  for (; blockCount > 0; blockCount--) {
4976 
4977  blockNumber = badBlocks->BlockNumber[blockCount-1];
4978  REVERSE_BYTES_QUAD(&badBlocks->BlockNumber[blockCount-1], &blockNumber);
4979  }
4980 
4981  //
4982  // Build a SCSI SRB containing a SCSIOP_REASSIGN_BLOCKS cdb
4983  //
4984 
4985  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4986  srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
4987 
4988  //
4989  // Set up STORAGE_REQUEST_BLOCK fields
4990  //
4991 
4993  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
4994  srbEx->Signature = SRB_SIGNATURE;
4995  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
4996  srbEx->SrbLength = srbSize;
4997  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
4998  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
4999  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
5000  srbEx->NumSrbExData = 1;
5001 
5002  // Set timeout value.
5003  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
5004 
5005  //
5006  // Set up address fields
5007  //
5008 
5009  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
5010  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
5011  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
5012 
5013  //
5014  // Set up SCSI SRB extended data fields
5015  //
5016 
5017  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
5018  sizeof(STOR_ADDR_BTL8);
5019  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
5020  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
5021  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
5022  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
5023  srbExDataCdb16->CdbLength = 6;
5024 
5025  cdb = (PCDB)srbExDataCdb16->Cdb;
5026  } else {
5027  // Should not happen
5028  NT_ASSERT(FALSE);
5029 
5030  FREE_POOL(srb);
5031  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlReassignBlocks: Insufficient extended SRB size.\n"));
5032  return STATUS_INTERNAL_ERROR;
5033  }
5034 
5035  } else {
5038  srb->CdbLength = 6;
5039 
5040  //
5041  // Set timeout value.
5042  //
5043 
5044  srb->TimeOutValue = fdoExtension->TimeOutValue;
5045 
5046  cdb = (PCDB)srb->Cdb;
5047  }
5048 
5049  cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
5050  cdb->CDB6GENERIC.CommandUniqueBits = 1; // LONGLBA
5051 
5053  srb,
5054  badBlocks,
5055  bufferSize,
5056  TRUE);
5057 
5058  FREE_POOL(srb);
5059  return status;
5060 }
5061 
5062 NTSTATUS
5065  IN OUT PIRP Irp
5066  )
5067 
5068 /*++
5069 
5070 Routine Description:
5071 
5072  This routine services IOCTL_DISK_IS_WRITABLE. This function
5073  returns whether the disk is writable. If the device is not
5074  writable then STATUS_MEDIA_WRITE_PROTECTED will be returned.
5075 
5076  This function must be called at IRQL < DISPATCH_LEVEL.
5077 
5078 Arguments:
5079 
5080  DeviceObject - Supplies the device object associated with this request.
5081 
5082  Irp - The IRP to be processed
5083 
5084 Return Value:
5085 
5086  NTSTATUS code
5087 
5088 --*/
5089 
5090 {
5091  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5093 
5094  PMODE_PARAMETER_HEADER modeData;
5095  PSCSI_REQUEST_BLOCK srb;
5096  PCDB cdb = NULL;
5097  ULONG modeLength;
5098  ULONG retries = 4;
5099  ULONG srbSize;
5100  PSTORAGE_REQUEST_BLOCK srbEx;
5101  PSTOR_ADDR_BTL8 storAddrBtl8;
5102  PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16;
5103 
5104  //
5105  // This function must be called at less than dispatch level.
5106  // Fail if IRQL >= DISPATCH_LEVEL.
5107  //
5108  PAGED_CODE();
5109  CHECK_IRQL();
5110 
5111  //
5112  // Validate the request.
5113  //
5114 
5115  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5116 
5117  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
5119  } else {
5120  srbSize = SCSI_REQUEST_BLOCK_SIZE;
5121  }
5122  srb = ExAllocatePoolWithTag(NonPagedPoolNx,
5123  srbSize,
5124  DISK_TAG_SRB);
5125 
5126  if (srb == NULL) {
5127  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n"));
5129  }
5130 
5131  RtlZeroMemory(srb, srbSize);
5132 
5133  //
5134  // Allocate memory for a mode header and then some
5135  // for port drivers that need to convert to MODE10
5136  // or always return the MODE_PARAMETER_BLOCK (even
5137  // when memory was not allocated for this purpose)
5138  //
5139 
5140  modeLength = MODE_DATA_SIZE;
5141  modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
5142  modeLength,
5144 
5145  if (modeData == NULL) {
5146  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n"));
5147  FREE_POOL(srb);
5149  }
5150 
5151  RtlZeroMemory(modeData, modeLength);
5152 
5153  //
5154  // Build the MODE SENSE CDB
5155  //
5156 
5157  if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
5158  srbEx = (PSTORAGE_REQUEST_BLOCK)srb;
5159 
5160  //
5161  // Set up STORAGE_REQUEST_BLOCK fields
5162  //
5163 
5165  srbEx->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK;
5166  srbEx->Signature = SRB_SIGNATURE;
5167  srbEx->Version = STORAGE_REQUEST_BLOCK_VERSION_1;
5168  srbEx->SrbLength = srbSize;
5169  srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
5170  srbEx->RequestPriority = IoGetIoPriorityHint(Irp);
5171  srbEx->AddressOffset = sizeof(STORAGE_REQUEST_BLOCK);
5172  srbEx->NumSrbExData = 1;
5173 
5174  // Set timeout value.
5175  srbEx->TimeOutValue = fdoExtension->TimeOutValue;
5176 
5177  //
5178  // Set up address fields
5179  //
5180 
5181  storAddrBtl8 = (PSTOR_ADDR_BTL8) ((PUCHAR)srbEx + srbEx->AddressOffset);
5182  storAddrBtl8->Type = STOR_ADDRESS_TYPE_BTL8;
5183  storAddrBtl8->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH;
5184 
5185  //
5186  // Set up SCSI SRB extended data fields
5187  //
5188 
5189  srbEx->SrbExDataOffset[0] = sizeof(STORAGE_REQUEST_BLOCK) +
5190  sizeof(STOR_ADDR_BTL8);
5191  if ((srbEx->SrbExDataOffset[0] + sizeof(SRBEX_DATA_SCSI_CDB16)) <= srbEx->SrbLength) {
5192  srbExDataCdb16 = (PSRBEX_DATA_SCSI_CDB16)((PUCHAR)srbEx + srbEx->SrbExDataOffset[0]);
5193  srbExDataCdb16->Type = SrbExDataTypeScsiCdb16;
5194  srbExDataCdb16->Length = SRBEX_DATA_SCSI_CDB16_LENGTH;
5195  srbExDataCdb16->CdbLength = 6;
5196 
5197  cdb = (PCDB)srbExDataCdb16->Cdb;
5198  } else {
5199  // Should not happen
5200  NT_ASSERT(FALSE);
5201 
5202  FREE_POOL(srb);
5203  FREE_POOL(modeData);
5204  return STATUS_INTERNAL_ERROR;
5205  }
5206 
5207  } else {
5210  srb->CdbLength = 6;
5211 
5212  //
5213  // Set timeout value.
5214  //
5215 
5216  srb->TimeOutValue = fdoExtension->TimeOutValue;
5217 
5218  cdb = (PCDB)srb->Cdb;
5219  }
5220 
5221  //
5222  // Page code of 0x3F will return all pages.
5223  // This command could fail if the data to be returned is
5224  // more than 256 bytes. In which case, we should get only
5225  // the caching page since we only need the block descriptor.
5226  // DiskFdoProcessError will change the page code to
5227  // MODE_PAGE_CACHING if there is an error.
5228  //
5229 
5230  cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
5231  cdb->MODE_SENSE.PageCode = MODE_SENSE_RETURN_ALL;
5232  cdb->MODE_SENSE.AllocationLength = (UCHAR)modeLength;
5233 
5234  while (retries != 0) {
5235 
5237  srb,
5238  modeData,
5239  modeLength,
5240  FALSE);
5241 
5242  if (status != STATUS_VERIFY_REQUIRED) {
5245  }
5246  break;
5247  }
5248  retries--;
5249  }
5250 
5251  if (NT_SUCCESS(status)) {
5252 
5255  }
5256  }
5257 
5258  FREE_POOL(srb);
5259  FREE_POOL(modeData);
5260  return status;
5261 }
5262 
5263 NTSTATUS
5266  IN OUT PIRP Irp
5267  )
5268 
5269 /*++
5270 
5271 Routine Description:
5272 
5273  This routine services IOCTL_DISK_INTERNAL_SET_VERIFY.
5274  This is an internal function used to set the DO_VERIFY_VOLUME
5275  device object flag. Only a kernel mode component can send this
5276  IOCTL.
5277 
5278 Arguments:
5279 
5280  DeviceObject - Supplies the device object associated with this request.
5281 
5282  Irp - The IRP to be processed
5283 
5284 Return Value:
5285 
5286  NTSTATUS code
5287 
5288 --*/
5289 
5290 {
5292 
5293  //
5294  // Validate the request.
5295  //
5296 
5297  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSetVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5298 
5299  //
5300  // If the caller is kernel mode, set the verify bit.
5301  //
5302 
5303  if (Irp->RequestorMode == KernelMode) {
5304 
5307 
5308  }
5309  return status;
5310 }
5311 
5312 NTSTATUS
5315  IN OUT PIRP Irp
5316  )
5317 
5318 /*++
5319 
5320 Routine Description:
5321 
5322  This routine services IOCTL_DISK_INTERNAL_CLEAR_VERIFY.
5323  This is an internal function used to clear the DO_VERIFY_VOLUME
5324  device object flag. Only a kernel mode component can send this
5325  IOCTL.
5326 
5327 Arguments:
5328 
5329  DeviceObject - Supplies the device object associated with this request.
5330 
5331  Irp - The IRP to be processed
5332 
5333 Return Value:
5334 
5335  NTSTATUS code
5336 
5337 --*/
5338 
5339 {
5341 
5342  //
5343  // Validate the request.
5344  //
5345 
5346  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlClearVerify: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5347 
5348  //
5349  // If the caller is kernel mode, set the verify bit.
5350  //
5351 
5352  if (Irp->RequestorMode == KernelMode) {
5353 
5356 
5357  }
5358  return status;
5359 }
5360 
5361 NTSTATUS
5364  IN OUT PIRP Irp
5365  )
5366 
5367 /*++
5368 
5369 Routine Description:
5370 
5371  This routine services IOCTL_DISK_UPDATE_DRIVE_SIZE.
5372  This function is used to inform the disk driver to update
5373  the device geometry information cached in the device extension
5374  This is normally initiated from the drivers layers above disk
5375  driver.
5376 
5377  This function must be called at IRQL < DISPATCH_LEVEL.
5378 
5379 Arguments:
5380 
5381  DeviceObject - Supplies the device object associated with this request.
5382 
5383  Irp - The IRP to be processed
5384 
5385 Return Value:
5386 
5387  NTSTATUS code
5388 
5389 --*/
5390 
5391 {
5392  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5393  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5394  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5397  NTSTATUS status;
5398 
5399  //
5400  // This function must be called at less than dispatch level.
5401  // Fail if IRQL >= DISPATCH_LEVEL.
5402  //
5403  PAGED_CODE();
5404  CHECK_IRQL();
5405 
5406  //
5407  // Validate the request.
5408  //
5409 
5410  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlUpdateDriveSize: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5411 
5412  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) {
5413 
5414  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlUpdateDriveSize: Output buffer too small.\n"));
5415  return STATUS_BUFFER_TOO_SMALL;
5416  }
5417 
5419 
5420  //
5421  // Note whether the drive is ready.
5422  //
5423 
5424  diskData->ReadyStatus = status;
5425 
5426  if (NT_SUCCESS(status)) {
5427 
5428  //
5429  // Copy drive geometry information from the device extension.
5430  //
5431 
5432  RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
5433  &(fdoExtension->DiskGeometry),
5434  sizeof(DISK_GEOMETRY));
5435 
5436  if (((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector == 0) {
5437  ((PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer)->BytesPerSector = 512;
5438  }
5439  Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
5441 
5442  //
5443  // Notify everyone that the disk layout may have changed
5444  //
5445 
5446  Notification.Event = GUID_IO_DISK_LAYOUT_CHANGE;
5447  Notification.Version = 1;
5449  Notification.FileObject = NULL;
5450  Notification.NameBufferOffset = -1;
5451 
5453  &Notification,
5454  NULL,
5455  NULL);
5456  }
5457  return status;
5458 }
5459 
5460 NTSTATUS
5463  IN OUT PIRP Irp
5464  )
5465 
5466 /*++
5467 
5468 Routine Description:
5469 
5470  This routine services IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
5471  and IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN. This function
5472  returns the physical location of a volume.
5473 
5474  This function must be called at IRQL < DISPATCH_LEVEL.
5475 
5476 Arguments:
5477 
5478  DeviceObject - Supplies the device object associated with this request.
5479 
5480  Irp - The IRP to be processed
5481 
5482 Return Value:
5483 
5484  NTSTATUS code
5485 
5486 --*/
5487 
5488 {
5489  PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5490  PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5493 
5494  //
5495  // This function must be called at less than dispatch level.
5496  // Fail if IRQL >= DISPATCH_LEVEL.
5497  //
5498  PAGED_CODE();
5499  CHECK_IRQL();
5500 
5501  //
5502  // Validate the request.
5503  //
5504 
5505  TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlGetVolumeDiskExtents: DeviceObject %p Irp %p\n", DeviceObject,