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 //
79 BOOLEAN DiskETWEnabled = FALSE;
80
81 BOOLEAN DiskIsPastReinit = FALSE;
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 */
DiskDriverReinit(IN PDRIVER_OBJECT DriverObject,IN PVOID Nothing,IN ULONG Count)108 DiskDriverReinit(
109 IN PDRIVER_OBJECT DriverObject,
110 IN PVOID Nothing,
111 IN ULONG Count
112 )
113 {
114 UNREFERENCED_PARAMETER(DriverObject);
115 UNREFERENCED_PARAMETER(Nothing);
116 UNREFERENCED_PARAMETER(Count);
117
118 DiskIsPastReinit = TRUE;
119 }
120
121 VOID
122 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskBootDriverReinit(IN PDRIVER_OBJECT DriverObject,IN PVOID Nothing,IN ULONG Count)123 DiskBootDriverReinit(
124 IN PDRIVER_OBJECT DriverObject,
125 IN PVOID Nothing,
126 IN ULONG Count
127 )
128 {
129 IoRegisterDriverReinitialization(DriverObject, DiskDriverReinit, NULL);
130
131 #if defined(_X86_) || defined(_AMD64_)
132
133 DiskDriverReinitialization(DriverObject, Nothing, Count);
134
135 #else
136
137 UNREFERENCED_PARAMETER(Nothing);
138 UNREFERENCED_PARAMETER(Count);
139
140 #endif
141
142 }
143
144 NTSTATUS
145 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)146 DriverEntry(
147 IN PDRIVER_OBJECT DriverObject,
148 IN PUNICODE_STRING RegistryPath
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 {
170 CLASS_INIT_DATA InitializationData = { 0 };
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
176 NTSTATUS status;
177
178 //
179 // Initializes tracing
180 //
181 WPP_INIT_TRACING(DriverObject, RegistryPath);
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
233 DiskInitializeReregistration();
234
235 //
236 // Call the class init routine
237 //
238
239 status = ClassInitialize(DriverObject, RegistryPath, &InitializationData);
240
241 if (NT_SUCCESS(status)) {
242
243 IoRegisterBootDriverReinitialization(DriverObject,
244 DiskBootDriverReinit,
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 //
263 srbSupport = CLASS_SRB_SCSI_REQUEST_BLOCK | CLASS_SRB_STORAGE_REQUEST_BLOCK;
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 */
DiskUnload(IN PDRIVER_OBJECT DriverObject)281 DiskUnload(
282 IN PDRIVER_OBJECT DriverObject
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.
293 UNREFERENCED_PARAMETER(DriverObject);
294 #endif
295
296
297 //
298 // Cleans up tracing
299 //
300 WPP_CLEANUP(DriverObject);
301
302 return;
303 }
304
305
306 NTSTATUS
DiskCreateFdo(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject,IN PULONG DeviceCount,IN BOOLEAN DasdAccessOnly)307 DiskCreateFdo(
308 IN PDRIVER_OBJECT DriverObject,
309 IN PDEVICE_OBJECT PhysicalDeviceObject,
310 IN PULONG DeviceCount,
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;
344 PDEVICE_OBJECT deviceObject = NULL;
345 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
346 NTSTATUS status;
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,
373 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
374 NULL,
375 NULL);
376
377 status = ZwCreateDirectoryObject(&handle,
378 DIRECTORY_ALL_ACCESS,
379 &objectAttribs);
380
381 (*DeviceCount)++;
382
383 } while((status == STATUS_OBJECT_NAME_COLLISION) ||
384 (status == STATUS_OBJECT_NAME_EXISTS));
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
403 lowerDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
404
405 status = ClassClaimDevice(lowerDevice, FALSE);
406
407 if (!NT_SUCCESS(status)) {
408 ZwMakeTemporaryObject(handle);
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,
432 PhysicalDeviceObject,
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
447 SET_FLAG(deviceObject->Flags, DO_DIRECT_IO);
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 =
496 IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
497
498
499 if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
500
501 //
502 // Uh - oh, we couldn't attach
503 // cleanup and return
504 //
505
506 status = STATUS_UNSUCCESSFUL;
507 goto DiskCreateFdoExit;
508 }
509
510 //
511 // Clear the init flag.
512 //
513
514 CLEAR_FLAG(deviceObject->Flags, DO_DEVICE_INITIALIZING);
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 {
530 IoDeleteDevice(deviceObject);
531 }
532
533 FREE_POOL(deviceName);
534
535 ObDereferenceObject(lowerDevice);
536
537 ZwMakeTemporaryObject(handle);
538 ZwClose(handle);
539
540 return status;
541 }
542
543
544 NTSTATUS
545 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskReadWriteVerification(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)546 DiskReadWriteVerification(
547 IN PDEVICE_OBJECT DeviceObject,
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;
570 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
571 ULONG residualBytes;
572 ULONG residualOffset;
573 NTSTATUS status = STATUS_SUCCESS;
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);
590 status = STATUS_INVALID_PARAMETER;
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 {
598 status = STATUS_INVALID_PARAMETER;
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) {
619 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
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
634 status = STATUS_SUCCESS;
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
643 status = STATUS_INVALID_PARAMETER;
644 }
645 }
646
647 Irp->IoStatus.Status = status;
648
649 return status;
650
651 } // end DiskReadWrite()
652
653
654 NTSTATUS
DiskDetermineMediaTypes(IN PDEVICE_OBJECT Fdo,IN PIRP Irp,IN UCHAR MediumType,IN UCHAR DensityCode,IN BOOLEAN MediaPresent,IN BOOLEAN IsWritable)655 DiskDetermineMediaTypes(
656 IN PDEVICE_OBJECT Fdo,
657 IN PIRP Irp,
658 IN UCHAR MediumType,
659 IN UCHAR DensityCode,
660 IN BOOLEAN MediaPresent,
661 IN BOOLEAN IsWritable
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;
687 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
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,
727 MEDIA_WRITE_PROTECTED);
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;
814 return 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 */
DiskDeviceControl(PDEVICE_OBJECT DeviceObject,PIRP Irp)937 DiskDeviceControl(
938 PDEVICE_OBJECT DeviceObject,
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 {
960 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
961 NTSTATUS status = STATUS_SUCCESS;
962 ULONG ioctlCode;
963
964 NT_ASSERT(DeviceObject != NULL);
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
975 case IOCTL_DISK_GET_CACHE_INFORMATION: {
976 status = DiskIoctlGetCacheInformation(DeviceObject, Irp);
977 break;
978 }
979
980 case IOCTL_DISK_SET_CACHE_INFORMATION: {
981 status = DiskIoctlSetCacheInformation(DeviceObject, Irp);
982 break;
983 }
984
985 case IOCTL_DISK_GET_CACHE_SETTING: {
986 status = DiskIoctlGetCacheSetting(DeviceObject, Irp);
987 break;
988 }
989
990 case IOCTL_DISK_SET_CACHE_SETTING: {
991 status = DiskIoctlSetCacheSetting(DeviceObject, Irp);
992 break;
993 }
994
995 case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
996 status = DiskIoctlGetDriveGeometry(DeviceObject, Irp);
997 break;
998 }
999
1000 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: {
1001 status = DiskIoctlGetDriveGeometryEx( DeviceObject, Irp );
1002 break;
1003 }
1004
1005 case IOCTL_DISK_VERIFY: {
1006 status = DiskIoctlVerify(DeviceObject, Irp);
1007 break;
1008 }
1009
1010 case IOCTL_DISK_GET_LENGTH_INFO: {
1011 status = DiskIoctlGetLengthInfo(DeviceObject, Irp);
1012 break;
1013 }
1014
1015 case IOCTL_DISK_IS_WRITABLE: {
1016 status = DiskIoctlIsWritable(DeviceObject, Irp);
1017 break;
1018 }
1019
1020 case IOCTL_DISK_UPDATE_DRIVE_SIZE: {
1021 status = DiskIoctlUpdateDriveSize(DeviceObject, Irp);
1022 break;
1023 }
1024
1025 case IOCTL_DISK_REASSIGN_BLOCKS: {
1026 status = DiskIoctlReassignBlocks(DeviceObject, Irp);
1027 break;
1028 }
1029
1030 case IOCTL_DISK_REASSIGN_BLOCKS_EX: {
1031 status = DiskIoctlReassignBlocksEx(DeviceObject, Irp);
1032 break;
1033 }
1034
1035 case IOCTL_DISK_INTERNAL_SET_VERIFY: {
1036 status = DiskIoctlSetVerify(DeviceObject, Irp);
1037 break;
1038 }
1039
1040 case IOCTL_DISK_INTERNAL_CLEAR_VERIFY: {
1041 status = DiskIoctlClearVerify(DeviceObject, Irp);
1042 break;
1043 }
1044
1045 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: {
1046 status = DiskIoctlGetMediaTypesEx(DeviceObject, Irp);
1047 break;
1048 }
1049
1050 case IOCTL_STORAGE_PREDICT_FAILURE : {
1051 status = DiskIoctlPredictFailure(DeviceObject, Irp);
1052 break;
1053 }
1054
1055 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
1056 case IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG : {
1057 status = DiskIoctlEnableFailurePrediction(DeviceObject, Irp);
1058 break;
1059 }
1060 #endif
1061
1062 case SMART_GET_VERSION: {
1063 status = DiskIoctlSmartGetVersion(DeviceObject, Irp);
1064 break;
1065 }
1066
1067 case SMART_RCV_DRIVE_DATA: {
1068 status = DiskIoctlSmartReceiveDriveData(DeviceObject, Irp);
1069 break;
1070 }
1071
1072 case SMART_SEND_DRIVE_COMMAND: {
1073 status = DiskIoctlSmartSendDriveCommand(DeviceObject, Irp);
1074 break;
1075 }
1076
1077 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
1078 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN: {
1079 status = DiskIoctlGetVolumeDiskExtents(DeviceObject, Irp);
1080 break;
1081 }
1082
1083 default: {
1084
1085 //
1086 // Pass the request to the common device control routine.
1087 //
1088 return(ClassDeviceControl(DeviceObject, Irp));
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));
1097 if (IoIsErrorUserInduced(status) &&
1098 (Irp->Tail.Overlay.Thread != NULL)) {
1099 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
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;
1113 ClassReleaseRemoveLock(DeviceObject, Irp);
1114 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1115 }
1116
1117 return(status);
1118 } // end DiskDeviceControl()
1119
1120 NTSTATUS
1121 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
DiskShutdownFlush(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)1122 DiskShutdownFlush(
1123 IN PDEVICE_OBJECT DeviceObject,
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;
1155 NTSTATUS status = STATUS_SUCCESS;
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;
1180 ClassReleaseRemoveLock(DeviceObject, Irp);
1181 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1182 return STATUS_SUCCESS;
1183 }
1184
1185 KeAcquireSpinLock(&diskData->FlushContext.Spinlock, &irql);
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 //
1192 IoMarkIrpPending(Irp);
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
1213 KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql);
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;
1232 NT_ASSERT(IsListEmpty(&diskData->FlushContext.NextList));
1233
1234
1235 KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql);
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 //
1243 KeWaitForSingleObject(&diskData->FlushContext.Event, Executive, KernelMode, FALSE, NULL);
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
1251 KeAcquireSpinLock(&diskData->FlushContext.Spinlock, &irql);
1252
1253 NT_ASSERT(IsListEmpty(&diskData->FlushContext.CurrList));
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
1269 KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql);
1270
1271 //
1272 // Send this request down to the device
1273 //
1274 DiskFlushDispatch(DeviceObject, &diskData->FlushContext);
1275 }
1276
1277 } else {
1278
1279 diskData->FlushContext.CurrIrp = Irp;
1280 NT_ASSERT(IsListEmpty(&diskData->FlushContext.CurrList));
1281
1282 NT_ASSERT(diskData->FlushContext.NextIrp == NULL);
1283 NT_ASSERT(IsListEmpty(&diskData->FlushContext.NextList));
1284
1285
1286 KeReleaseSpinLock(&diskData->FlushContext.Spinlock, irql);
1287
1288 DiskFlushDispatch(DeviceObject, &diskData->FlushContext);
1289 }
1290
1291 } else {
1292
1293 //
1294 // Allocate SCSI request block.
1295 //
1296
1297 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1298 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
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;
1313 ClassReleaseRemoveLock(DeviceObject, Irp);
1314 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1315 return(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;
1372 ClassReleaseRemoveLock(DeviceObject, Irp);
1373 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
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
1412 status = ClassSendSrbSynchronous(DeviceObject,
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
1466 status = ClassSendSrbSynchronous(DeviceObject,
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
1503 IoSetCompletionRoutine(Irp, ClassIoComplete, srb, TRUE, TRUE, TRUE);
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
1525 IoMarkIrpPending(Irp);
1526 IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1527 }
1528
1529 return STATUS_PENDING;
1530 }
1531
1532
1533 VOID
DiskFlushDispatch(IN PDEVICE_OBJECT Fdo,IN PDISK_GROUP_CONTEXT FlushContext)1534 DiskFlushDispatch(
1535 IN PDEVICE_OBJECT Fdo,
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;
1562 PIO_STACK_LOCATION irpSp = NULL;
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 {
1594 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1595
1596 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1597 srb->TimeOutValue = fdoExt->TimeOutValue * 4;
1598 srb->QueueTag = SP_UNTAGGED;
1599 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
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 {
1632 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
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 {
1658 srb->Function = SRB_FUNCTION_FLUSH;
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 //
1667 SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT);
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 */
DiskFlushComplete(IN PDEVICE_OBJECT Fdo,IN PIRP Irp,IN PVOID Context)1699 DiskFlushComplete(
1700 IN PDEVICE_OBJECT Fdo,
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;
1730 PFUNCTIONAL_DEVICE_EXTENSION fdoExt;
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 //
1760 NT_ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED);
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);
1784 ClassCompleteRequest(Fdo, tempIrp, IO_NO_INCREMENT);
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
DiskModeSelect(IN PDEVICE_OBJECT Fdo,_In_reads_bytes_ (Length)PCHAR ModeSelectBuffer,IN ULONG Length,IN BOOLEAN SavePage)1802 DiskModeSelect(
1803 IN PDEVICE_OBJECT Fdo,
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,
1869 DISK_TAG_MODE_DATA);
1870
1871 if (buffer == NULL) {
1872 return STATUS_INSUFFICIENT_RESOURCES;
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
1975 status = ClassSendSrbSynchronous(Fdo,
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) {
1998 status = STATUS_SUCCESS;
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 */
DisableWriteCache(IN PDEVICE_OBJECT Fdo,IN PVOID Context)2012 DisableWriteCache(
2013 IN PDEVICE_OBJECT Fdo,
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;
2021 PIO_WORKITEM WorkItem = (PIO_WORKITEM)Context;
2022
2023 PAGED_CODE();
2024
2025 NT_ASSERT(WorkItem != NULL);
2026 _Analysis_assume_(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
2037 IoFreeWorkItem(WorkItem);
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 */
DiskIoctlVerifyThread(IN PDEVICE_OBJECT Fdo,IN PVOID Context)2046 DiskIoctlVerifyThread(
2047 IN PDEVICE_OBJECT Fdo,
2048 IN PVOID Context
2049 )
2050 {
2051 PDISK_VERIFY_WORKITEM_CONTEXT WorkContext = (PDISK_VERIFY_WORKITEM_CONTEXT)Context;
2052 PIRP Irp = NULL;
2053 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)Fdo->DeviceExtension;
2054 PDISK_DATA DiskData = (PDISK_DATA)FdoExtension->CommonExtension.DriverData;
2055 PVERIFY_INFORMATION verifyInfo = NULL;
2056 PSCSI_REQUEST_BLOCK Srb = NULL;
2057 PCDB Cdb = NULL;
2058 LARGE_INTEGER byteOffset;
2059 LARGE_INTEGER sectorOffset;
2060 ULONG sectorCount;
2061 NTSTATUS status = STATUS_SUCCESS;
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) {
2118 RtlZeroMemory(Srb, CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE);
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);
2168 status = STATUS_INTERNAL_ERROR;
2169 }
2170
2171 } else {
2172 RtlZeroMemory(Srb, SCSI_REQUEST_BLOCK_SIZE);
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
2190 USHORT numSectors = (USHORT) min(sectorCount, MAX_SECTORS_PER_VERIFY);
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, §orOffset);
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)§orOffset)->Byte3;
2241 Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2;
2242 Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1;
2243 Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0;
2244
2245 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numSectors)->Byte1;
2246 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numSectors)->Byte0;
2247 }
2248
2249 status = ClassSendSrbSynchronous(Fdo,
2250 Srb,
2251 NULL,
2252 0,
2253 FALSE);
2254
2255 NT_ASSERT(status != STATUS_NONEXISTENT_SECTOR);
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
2266 ClassReleaseRemoveLock(Fdo, Irp);
2267 ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT);
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 */
DiskFdoProcessError(PDEVICE_OBJECT Fdo,PSCSI_REQUEST_BLOCK Srb,NTSTATUS * Status,BOOLEAN * Retry)2276 DiskFdoProcessError(
2277 PDEVICE_OBJECT Fdo,
2278 PSCSI_REQUEST_BLOCK Srb,
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
2392 BOOLEAN validSense = FALSE;
2393 UCHAR senseKey = 0;
2394 UCHAR asc = 0;
2395 UCHAR ascq = 0;
2396
2397 validSense = ScsiGetSenseKeyAndCodes(senseBuffer,
2398 senseBufferLength,
2399 SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
2400 &senseKey,
2401 &asc,
2402 &ascq);
2403
2404 if (validSense) {
2405
2406 switch (senseKey) {
2407
2408 case SCSI_SENSE_ILLEGAL_REQUEST: {
2409
2410 switch (asc) {
2411
2412 case SCSI_ADSENSE_INVALID_CDB:
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
2423 if (diskData->WriteCacheOverride == DiskWriteCacheEnable)
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;
2439 logEntry->ErrorCode = IO_WARNING_WRITE_FUA_PROBLEM;
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
2473 SET_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_FUA_NOT_SUPPORTED);
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) {
2505 case SCSI_ADSENSE_LUN_NOT_READY: {
2506 switch (ascq) {
2507 case SCSI_SENSEQ_BECOMING_READY:
2508 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
2509 case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: {
2510 invalidatePartitionTable = TRUE;
2511 break;
2512 }
2513 } // end switch(ascq)
2514 break;
2515 }
2516
2517 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: {
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
2530 case SCSI_SENSE_HARDWARE_ERROR: {
2531 invalidatePartitionTable = TRUE;
2532 break;
2533 }
2534
2535 case SCSI_SENSE_UNIT_ATTENTION:
2536 {
2537 invalidatePartitionTable = TRUE;
2538 break;
2539 }
2540
2541 case SCSI_SENSE_RECOVERED_ERROR: {
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)) {
2557 case SRB_STATUS_INVALID_LUN:
2558 case SRB_STATUS_INVALID_TARGET_ID:
2559 case SRB_STATUS_NO_DEVICE:
2560 case SRB_STATUS_NO_HBA:
2561 case SRB_STATUS_INVALID_PATH_ID:
2562 case SRB_STATUS_COMMAND_TIMEOUT:
2563 case SRB_STATUS_TIMEOUT:
2564 case SRB_STATUS_SELECTION_TIMEOUT:
2565 case SRB_STATUS_REQUEST_FLUSHED:
2566 case SRB_STATUS_UNEXPECTED_BUS_FREE:
2567 case SRB_STATUS_PARITY_ERROR:
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 */
DiskSetSpecialHacks(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN ULONG_PTR Data)2602 DiskSetSpecialHacks(
2603 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
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
2639 if (TEST_FLAG(Data, HackDisableTaggedQueuing)) {
2640
2641 //
2642 // Disable tagged queuing.
2643 //
2644
2645 CLEAR_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
2646 }
2647
2648 if (TEST_FLAG(Data, HackDisableSynchronousTransfers)) {
2649
2650 //
2651 // Disable synchronous data transfers.
2652 //
2653
2654 SET_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2655
2656 }
2657
2658 if (TEST_FLAG(Data, HackDisableSpinDown)) {
2659
2660 //
2661 // Disable spinning down of drives.
2662 //
2663
2664 SET_FLAG(FdoExtension->ScanForSpecialFlags,
2665 CLASS_SPECIAL_DISABLE_SPIN_DOWN);
2666
2667 }
2668
2669 if (TEST_FLAG(Data, HackDisableWriteCache)) {
2670
2671 //
2672 // Disable the drive's write cache
2673 //
2674
2675 SET_FLAG(FdoExtension->ScanForSpecialFlags,
2676 CLASS_SPECIAL_DISABLE_WRITE_CACHE);
2677
2678 }
2679
2680 if (TEST_FLAG(Data, HackCauseNotReportableHack)) {
2681
2682 SET_FLAG(FdoExtension->ScanForSpecialFlags,
2683 CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK);
2684 }
2685
2686 if (TEST_FLAG(fdo->Characteristics, FILE_REMOVABLE_MEDIA) &&
2687 TEST_FLAG(Data, HackRequiresStartUnitCommand)
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
ResetBus(IN PDEVICE_OBJECT Fdo)2705 ResetBus(
2706 IN PDEVICE_OBJECT Fdo
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;
2731 PCOMPLETION_CONTEXT context;
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),
2743 DISK_TAG_CCONTEXT);
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
2792 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2793
2794 //
2795 // Write length to SRB.
2796 //
2797
2798 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2799
2800 srb->Function = SRB_FUNCTION_RESET_BUS;
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
2817 ClassAcquireRemoveLock(Fdo, irp);
2818
2819 IoSetCompletionRoutine(irp,
2820 (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
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
DiskLogCacheInformation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN PDISK_CACHE_INFORMATION CacheInfo,IN NTSTATUS Status)2856 DiskLogCacheInformation(
2857 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
2858 IN PDISK_CACHE_INFORMATION CacheInfo,
2859 IN NTSTATUS Status
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
DiskGetInfoExceptionInformation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN PMODE_INFO_EXCEPTIONS ReturnPageData)2896 DiskGetInfoExceptionInformation(
2897 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
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,
2914 MODE_DATA_SIZE,
2915 DISK_TAG_INFO_EXCEPTION);
2916
2917 if (modeData == NULL) {
2918
2919 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_WMI, "DiskGetInfoExceptionInformation: Unable to allocate mode "
2920 "data buffer\n"));
2921 return STATUS_INSUFFICIENT_RESOURCES;
2922 }
2923
2924 RtlZeroMemory(modeData, MODE_DATA_SIZE);
2925
2926 length = ClassModeSense(FdoExtension->DeviceObject,
2927 (PCHAR) modeData,
2928 MODE_DATA_SIZE,
2929 MODE_PAGE_FAULT_REPORTING);
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,
2939 MODE_DATA_SIZE,
2940 MODE_PAGE_FAULT_REPORTING);
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,
2964 MODE_PAGE_FAULT_REPORTING,
2965 TRUE);
2966
2967 if (pageData != NULL) {
2968 RtlCopyMemory(ReturnPageData, pageData, sizeof(MODE_INFO_EXCEPTIONS));
2969 status = STATUS_SUCCESS;
2970 } else {
2971 status = STATUS_NOT_SUPPORTED;
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
DiskSetInfoExceptionInformation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN PMODE_INFO_EXCEPTIONS PageData)2985 DiskSetInfoExceptionInformation(
2986 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
2987 IN PMODE_INFO_EXCEPTIONS PageData
2988 )
2989
2990 {
2991 ULONG i;
2992 NTSTATUS status = STATUS_SUCCESS;
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 */
DiskGetCacheInformation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN PDISK_CACHE_INFORMATION CacheInfo)3019 DiskGetCacheInformation(
3020 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
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,
3055 MODE_DATA_SIZE,
3056 DISK_TAG_DISABLE_CACHE);
3057
3058 if (modeData == NULL) {
3059
3060 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskGetSetCacheInformation: Unable to allocate mode "
3061 "data buffer\n"));
3062 return STATUS_INSUFFICIENT_RESOURCES;
3063 }
3064
3065 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3066
3067 length = ClassModeSense(FdoExtension->DeviceObject,
3068 (PCHAR) modeData,
3069 MODE_DATA_SIZE,
3070 MODE_PAGE_CACHING);
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,
3080 MODE_DATA_SIZE,
3081 MODE_PAGE_CACHING);
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,
3107 MODE_PAGE_CACHING,
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 =
3138 TRANSLATE_RETENTION_PRIORITY(pageData->ReadRetensionPriority);
3139 CacheInfo->WriteRetentionPriority =
3140 TRANSLATE_RETENTION_PRIORITY(pageData->WriteRetensionPriority);
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 */
DiskSetCacheInformation(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,IN PDISK_CACHE_INFORMATION CacheInfo)3167 DiskSetCacheInformation(
3168 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
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;
3195 NTSTATUS status = STATUS_SUCCESS;
3196
3197 PAGED_CODE();
3198
3199 modeData = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
3200 MODE_DATA_SIZE,
3201 DISK_TAG_DISABLE_CACHE);
3202
3203 if (modeData == NULL) {
3204
3205 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskSetCacheInformation: Unable to allocate mode "
3206 "data buffer\n"));
3207 return STATUS_INSUFFICIENT_RESOURCES;
3208 }
3209
3210 RtlZeroMemory(modeData, MODE_DATA_SIZE);
3211
3212 length = ClassModeSense(FdoExtension->DeviceObject,
3213 (PCHAR) modeData,
3214 MODE_DATA_SIZE,
3215 MODE_PAGE_CACHING);
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,
3225 MODE_DATA_SIZE,
3226 MODE_PAGE_CACHING);
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,
3252 MODE_PAGE_CACHING,
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 }
3325 ADJUST_FUA_FLAG(FdoExtension);
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
3339 SET_FLAG(FdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_MODIFY_CACHE_UNSUCCESSFUL);
3340 }
3341
3342 FREE_POOL(modeData);
3343 return status;
3344 }
3345
3346 NTSTATUS
DiskIoctlGetCacheSetting(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)3347 DiskIoctlGetCacheSetting(
3348 IN PDEVICE_OBJECT DeviceObject,
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;
3373 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
3374 NTSTATUS status = STATUS_SUCCESS;
3375
3376 PAGED_CODE();
3377
3378 if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_CACHE_SETTING))
3379 {
3380 status = STATUS_BUFFER_TOO_SMALL;
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 //
3392 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_FUA_NOT_SUPPORTED))
3393 {
3394 cacheSetting->State = DiskCacheWriteThroughNotSupported;
3395 }
3396
3397 //
3398 // Determine whether it is possible to modify the cache setting
3399 //
3400 if (TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_MODIFY_CACHE_UNSUCCESSFUL))
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
DiskIoctlSetCacheSetting(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)3415 DiskIoctlSetCacheSetting(
3416 IN PDEVICE_OBJECT DeviceObject,
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;
3443 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
3444 NTSTATUS status = STATUS_SUCCESS;
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 {
3455 status = STATUS_INFO_LENGTH_MISMATCH;
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 {
3484 status = STATUS_INVALID_PARAMETER;
3485 }
3486 }
3487
3488 return status;
3489 }
3490
3491 NTSTATUS
DiskIoctlGetLengthInfo(IN OUT PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3492 DiskIoctlGetLengthInfo(
3493 IN OUT PDEVICE_OBJECT DeviceObject,
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) {
3565 IoInvalidateDeviceRelations(p0Extension->LowerPdo, BusRelations);
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
3575 status = STATUS_SUCCESS;
3576 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
3577
3578 return status;
3579 }
3580
3581 NTSTATUS
DiskIoctlGetDriveGeometry(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3582 DiskIoctlGetDriveGeometry(
3583 IN PDEVICE_OBJECT DeviceObject,
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);
3613 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
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
3664 typedef struct _DISK_GEOMETRY_EX_INTERNAL {
3665 DISK_GEOMETRY Geometry;
3666 LARGE_INTEGER DiskSize;
3667 DISK_PARTITION_INFO Partition;
3668 DISK_DETECTION_INFO Detection;
3669 } DISK_GEOMETRY_EX_INTERNAL, *PDISK_GEOMETRY_EX_INTERNAL;
3670
3671 NTSTATUS
DiskIoctlGetDriveGeometryEx(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3672 DiskIoctlGetDriveGeometryEx(
3673 IN PDEVICE_OBJECT DeviceObject,
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;
3706 ULONG OutputBufferLength;
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
3732 if ( (LONG)OutputBufferLength < FIELD_OFFSET (DISK_GEOMETRY_EX, Data) ) {
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"));
3740 status = STATUS_BUFFER_TOO_SMALL;
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
3776 if ((LONG)OutputBufferLength >= FIELD_OFFSET (DISK_GEOMETRY_EX_INTERNAL, Detection)) {
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
3818 if (OutputBufferLength >= sizeof (DISK_GEOMETRY_EX_INTERNAL)) {
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
3833 status = STATUS_SUCCESS;
3834 Irp->IoStatus.Information = min (OutputBufferLength, sizeof (DISK_GEOMETRY_EX_INTERNAL));
3835
3836 return status;
3837 }
3838
3839 NTSTATUS
DiskIoctlGetCacheInformation(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3840 DiskIoctlGetCacheInformation(
3841 IN PDEVICE_OBJECT DeviceObject,
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;
3870 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
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
DiskIoctlSetCacheInformation(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3917 DiskIoctlSetCacheInformation(
3918 IN PDEVICE_OBJECT DeviceObject,
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);
3950 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
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"));
3971 return STATUS_INFO_LENGTH_MISMATCH;
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) {
3980 diskData->WriteCacheOverride = DiskWriteCacheEnable;
3981 } else {
3982 diskData->WriteCacheOverride = DiskWriteCacheDisable;
3983 }
3984
3985 ClassSetDeviceParameter(fdoExtension, DiskDeviceParameterSubkey,
3986 DiskDeviceUserWriteCacheSetting, diskData->WriteCacheOverride);
3987
3988 DiskLogCacheInformation(fdoExtension, cacheInfo, status);
3989
3990 return status;
3991 }
3992
3993 NTSTATUS
DiskIoctlGetMediaTypesEx(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)3994 DiskIoctlGetMediaTypesEx(
3995 IN PDEVICE_OBJECT DeviceObject,
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;
4023 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
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) {
4060 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
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"));
4071 return STATUS_INSUFFICIENT_RESOURCES;
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
4087 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
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
4132 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4133 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
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
4146 status = ClassSendSrbSynchronous(DeviceObject,
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,
4159 DISK_TAG_MODE_DATA);
4160
4161 if (modeData == NULL) {
4162 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetMediaTypesEx: Unable to allocate memory.\n"));
4163 FREE_POOL(srb);
4164 return STATUS_INSUFFICIENT_RESOURCES;
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:
4209 status = ClassSendSrbSynchronous(DeviceObject,
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) {
4226 status = STATUS_SUCCESS;
4227 }
4228
4229 if (NT_SUCCESS(status) || (status == STATUS_NO_MEDIA_IN_DEVICE)) {
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,
4242 MODE_DSP_WRITE_PROTECT)) {
4243
4244 writable = FALSE;
4245 }
4246
4247 status = DiskDetermineMediaTypes(DeviceObject,
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
DiskIoctlPredictFailure(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)4268 DiskIoctlPredictFailure(
4269 IN PDEVICE_OBJECT DeviceObject,
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);
4298 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
4299 NTSTATUS status = STATUS_SUCCESS;
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
4331 if (diskData->FailurePredictionCapability == FailurePredictionSense) {
4332 ULONG readBufferSize;
4333 PUCHAR readBuffer;
4334 PIRP readIrp;
4335 PDEVICE_OBJECT topOfStack;
4336
4337 checkFailure->PredictFailure = 0;
4338
4339 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
4340
4341 topOfStack = IoGetAttachedDeviceReference(DeviceObject);
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) {
4358 LARGE_INTEGER offset;
4359
4360 offset.QuadPart = 0;
4361 readIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
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) {
4373 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
4374 status = ioStatus.Status;
4375 }
4376
4377
4378 } else {
4379 status = STATUS_INSUFFICIENT_RESOURCES;
4380 }
4381
4382 FREE_POOL(readBuffer);
4383 } else {
4384 status = STATUS_INSUFFICIENT_RESOURCES;
4385 }
4386
4387 ObDereferenceObject(topOfStack);
4388 }
4389
4390 if (status != STATUS_INSUFFICIENT_RESOURCES)
4391 {
4392 if ((diskData->FailurePredictionCapability == FailurePredictionSmart) ||
4393 (diskData->FailurePredictionCapability == FailurePredictionSense)) {
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 {
4411 status = STATUS_INVALID_DEVICE_REQUEST;
4412 }
4413 }
4414 return status;
4415 }
4416
4417 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
4418 NTSTATUS
DiskIoctlEnableFailurePrediction(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)4419 DiskIoctlEnableFailurePrediction(
4420 IN PDEVICE_OBJECT DeviceObject,
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);
4449 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
4450 NTSTATUS status = STATUS_SUCCESS;
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"));
4478 status = STATUS_INVALID_PARAMETER;
4479 }
4480
4481 if (enablePrediction->Reserved != 0) {
4482 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlEnableFailurePrediction: Reserved bytes are not zero!\n"));
4483 status = STATUS_INVALID_PARAMETER;
4484 }
4485
4486 //
4487 // Default to success. This might get overwritten on failure below.
4488 //
4489 status = STATUS_SUCCESS;
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) {
4496 if (diskData->FailurePredictionCapability == FailurePredictionSmart ||
4497 diskData->FailurePredictionCapability == FailurePredictionIoctl) {
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
DiskIoctlVerify(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)4526 DiskIoctlVerify(
4527 IN PDEVICE_OBJECT DeviceObject,
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;
4554 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
4555 PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
4556 PDISK_VERIFY_WORKITEM_CONTEXT Context = NULL;
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"));
4569 return STATUS_INFO_LENGTH_MISMATCH;
4570 }
4571
4572 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4573 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
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"));
4583 return STATUS_INSUFFICIENT_RESOURCES;
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)
4604 return STATUS_NONEXISTENT_SECTOR;
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)
4613 return STATUS_NONEXISTENT_SECTOR;
4614 }
4615 }
4616
4617 Context = ExAllocatePoolWithTag(NonPagedPoolNx,
4618 sizeof(DISK_VERIFY_WORKITEM_CONTEXT),
4619 DISK_TAG_WI_CONTEXT);
4620 if (Context) {
4621
4622 Context->Irp = Irp;
4623 Context->Srb = srb;
4624 Context->WorkItem = IoAllocateWorkItem(DeviceObject);
4625
4626 if (Context->WorkItem) {
4627
4628 //
4629 // Queue the work item and return.
4630 //
4631
4632 IoMarkIrpPending(Irp);
4633
4634 IoQueueWorkItem(Context->WorkItem,
4635 DiskIoctlVerifyThread,
4636 DelayedWorkQueue,
4637 Context);
4638
4639 return STATUS_PENDING;
4640 }
4641 FREE_POOL(Context);
4642 }
4643 FREE_POOL(srb)
4644 return STATUS_INSUFFICIENT_RESOURCES;
4645 }
4646
4647 NTSTATUS
DiskIoctlReassignBlocks(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)4648 DiskIoctlReassignBlocks(
4649 IN PDEVICE_OBJECT DeviceObject,
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;
4677 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
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"));
4705 return STATUS_INFO_LENGTH_MISMATCH;
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"));
4721 return STATUS_INFO_LENGTH_MISMATCH;
4722 }
4723
4724 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4725 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
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"));
4735 return STATUS_INSUFFICIENT_RESOURCES;
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
4785 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
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 {
4829 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
4830 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
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
4844 status = ClassSendSrbSynchronous(DeviceObject,
4845 srb,
4846 badBlocks,
4847 bufferSize,
4848 TRUE);
4849
4850 FREE_POOL(srb);
4851 return status;
4852 }
4853
4854 NTSTATUS
DiskIoctlReassignBlocksEx(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)4855 DiskIoctlReassignBlocksEx(
4856 IN PDEVICE_OBJECT DeviceObject,
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;
4884 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
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"));
4912 return STATUS_INFO_LENGTH_MISMATCH;
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"));
4928 return STATUS_INFO_LENGTH_MISMATCH;
4929 }
4930
4931 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
4932 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
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"));
4942 return STATUS_INSUFFICIENT_RESOURCES;
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
4992 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
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 {
5036 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5037 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
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
5052 status = ClassSendSrbSynchronous(DeviceObject,
5053 srb,
5054 badBlocks,
5055 bufferSize,
5056 TRUE);
5057
5058 FREE_POOL(srb);
5059 return status;
5060 }
5061
5062 NTSTATUS
DiskIoctlIsWritable(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5063 DiskIoctlIsWritable(
5064 IN PDEVICE_OBJECT DeviceObject,
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;
5092 NTSTATUS status = STATUS_SUCCESS;
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) {
5118 srbSize = CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE;
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"));
5128 return STATUS_INSUFFICIENT_RESOURCES;
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,
5143 DISK_TAG_MODE_DATA);
5144
5145 if (modeData == NULL) {
5146 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlIsWritable: Unable to allocate memory.\n"));
5147 FREE_POOL(srb);
5148 return STATUS_INSUFFICIENT_RESOURCES;
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
5164 srbEx->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature);
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 {
5208 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
5209 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
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
5236 status = ClassSendSrbSynchronous(DeviceObject,
5237 srb,
5238 modeData,
5239 modeLength,
5240 FALSE);
5241
5242 if (status != STATUS_VERIFY_REQUIRED) {
5243 if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
5244 status = STATUS_SUCCESS;
5245 }
5246 break;
5247 }
5248 retries--;
5249 }
5250
5251 if (NT_SUCCESS(status)) {
5252
5253 if (TEST_FLAG(modeData->DeviceSpecificParameter, MODE_DSP_WRITE_PROTECT)) {
5254 status = STATUS_MEDIA_WRITE_PROTECTED;
5255 }
5256 }
5257
5258 FREE_POOL(srb);
5259 FREE_POOL(modeData);
5260 return status;
5261 }
5262
5263 NTSTATUS
DiskIoctlSetVerify(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5264 DiskIoctlSetVerify(
5265 IN PDEVICE_OBJECT DeviceObject,
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 {
5291 NTSTATUS status = STATUS_NOT_SUPPORTED;
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
5305 SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
5306 status = STATUS_SUCCESS;
5307
5308 }
5309 return status;
5310 }
5311
5312 NTSTATUS
DiskIoctlClearVerify(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5313 DiskIoctlClearVerify(
5314 IN PDEVICE_OBJECT DeviceObject,
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 {
5340 NTSTATUS status = STATUS_NOT_SUPPORTED;
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
5354 CLEAR_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
5355 status = STATUS_SUCCESS;
5356
5357 }
5358 return status;
5359 }
5360
5361 NTSTATUS
DiskIoctlUpdateDriveSize(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5362 DiskIoctlUpdateDriveSize(
5363 IN PDEVICE_OBJECT DeviceObject,
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);
5395 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
5396 TARGET_DEVICE_CUSTOM_NOTIFICATION Notification = {0};
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
5418 status = DiskReadDriveCapacity(DeviceObject);
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);
5440 status = STATUS_SUCCESS;
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;
5448 Notification.Size = (USHORT)FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer);
5449 Notification.FileObject = NULL;
5450 Notification.NameBufferOffset = -1;
5451
5452 IoReportTargetDeviceChangeAsynchronous(fdoExtension->LowerPdo,
5453 &Notification,
5454 NULL,
5455 NULL);
5456 }
5457 return status;
5458 }
5459
5460 NTSTATUS
DiskIoctlGetVolumeDiskExtents(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5461 DiskIoctlGetVolumeDiskExtents(
5462 IN PDEVICE_OBJECT DeviceObject,
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);
5491 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
5492 NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
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, Irp));
5506
5507
5508 if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) {
5509
5510 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VOLUME_DISK_EXTENTS)) {
5511 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlGetVolumeDiskExtents: Output buffer too small.\n"));
5512 return STATUS_BUFFER_TOO_SMALL;
5513 }
5514
5515 status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
5516
5517 //
5518 // Note whether the drive is ready.
5519 //
5520
5521 diskData->ReadyStatus = status;
5522
5523 if (NT_SUCCESS(status)) {
5524
5525 PVOLUME_DISK_EXTENTS pVolExt = (PVOLUME_DISK_EXTENTS)Irp->AssociatedIrp.SystemBuffer;
5526
5527 pVolExt->NumberOfDiskExtents = 1;
5528 pVolExt->Extents[0].DiskNumber = commonExtension->PartitionZeroExtension->DeviceNumber;
5529 pVolExt->Extents[0].StartingOffset = commonExtension->StartingOffset;
5530 pVolExt->Extents[0].ExtentLength = commonExtension->PartitionLength;
5531
5532 Irp->IoStatus.Information = sizeof(VOLUME_DISK_EXTENTS);
5533 }
5534 }
5535
5536 return status;
5537 }
5538
5539 NTSTATUS
DiskIoctlSmartGetVersion(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5540 DiskIoctlSmartGetVersion(
5541 IN PDEVICE_OBJECT DeviceObject,
5542 IN OUT PIRP Irp
5543 )
5544
5545 /*++
5546
5547 Routine Description:
5548
5549 This routine services SMART_GET_VERSION. It returns the
5550 SMART version information.
5551
5552 This function must be called at IRQL < DISPATCH_LEVEL.
5553
5554 Arguments:
5555
5556 DeviceObject - Supplies the device object associated with this request.
5557
5558 Irp - The IRP to be processed
5559
5560 Return Value:
5561
5562 NTSTATUS code
5563
5564 --*/
5565
5566 {
5567 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5568 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5569 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5570 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
5571 NTSTATUS status;
5572
5573 PGETVERSIONINPARAMS versionParams;
5574 PSRB_IO_CONTROL srbControl;
5575 IO_STATUS_BLOCK ioStatus = { 0 };
5576 PUCHAR buffer;
5577
5578 //
5579 // This function must be called at less than dispatch level.
5580 // Fail if IRQL >= DISPATCH_LEVEL.
5581 //
5582 PAGED_CODE();
5583 CHECK_IRQL();
5584
5585 //
5586 // Validate the request.
5587 //
5588
5589 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5590
5591
5592 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GETVERSIONINPARAMS)) {
5593 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: Output buffer too small.\n"));
5594 return STATUS_BUFFER_TOO_SMALL;
5595 }
5596
5597 srbControl = ExAllocatePoolWithTag(NonPagedPoolNx,
5598 sizeof(SRB_IO_CONTROL) +
5599 sizeof(GETVERSIONINPARAMS),
5600 DISK_TAG_SMART);
5601
5602 if (srbControl == NULL) {
5603 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartGetVersion: Unable to allocate memory.\n"));
5604 return STATUS_INSUFFICIENT_RESOURCES;
5605 }
5606
5607 RtlZeroMemory(srbControl, sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
5608
5609 //
5610 // fill in srbControl fields
5611 //
5612
5613 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
5614 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
5615 srbControl->Timeout = fdoExtension->TimeOutValue;
5616 srbControl->Length = sizeof(GETVERSIONINPARAMS);
5617 srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
5618
5619 //
5620 // Point to the 'buffer' portion of the SRB_CONTROL
5621 //
5622
5623 buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
5624
5625 //
5626 // Ensure correct target is set in the cmd parameters.
5627 //
5628
5629 versionParams = (PGETVERSIONINPARAMS)buffer;
5630 versionParams->bIDEDeviceMap = diskData->ScsiAddress.TargetId;
5631
5632 ClassSendDeviceIoControlSynchronous(
5633 IOCTL_SCSI_MINIPORT,
5634 commonExtension->LowerDeviceObject,
5635 srbControl,
5636 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
5637 sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
5638 FALSE,
5639 &ioStatus);
5640
5641 status = ioStatus.Status;
5642
5643 //
5644 // If successful, copy the data received into the output buffer.
5645 // This should only fail in the event that the IDE driver is older
5646 // than this driver.
5647 //
5648
5649 if (NT_SUCCESS(status)) {
5650
5651 buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
5652
5653 RtlMoveMemory (Irp->AssociatedIrp.SystemBuffer, buffer, sizeof(GETVERSIONINPARAMS));
5654 Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
5655 }
5656
5657 FREE_POOL(srbControl);
5658
5659 return status;
5660 }
5661
5662 NTSTATUS
DiskIoctlSmartReceiveDriveData(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5663 DiskIoctlSmartReceiveDriveData(
5664 IN PDEVICE_OBJECT DeviceObject,
5665 IN OUT PIRP Irp
5666 )
5667
5668 /*++
5669
5670 Routine Description:
5671
5672 This routine services SMART_RCV_DRIVE_DATA. This function
5673 allows the caller to read SMART information from the device.
5674
5675 This function must be called at IRQL < DISPATCH_LEVEL.
5676
5677 Arguments:
5678
5679 DeviceObject - Supplies the device object associated with this request.
5680
5681 Irp - The IRP to be processed
5682
5683 Return Value:
5684
5685 NTSTATUS code
5686
5687 --*/
5688
5689 {
5690 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5691 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5692 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5693 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
5694 NTSTATUS status = STATUS_INVALID_PARAMETER;
5695
5696 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
5697 PSRB_IO_CONTROL srbControl;
5698 IO_STATUS_BLOCK ioStatus = { 0 };
5699 ULONG controlCode = 0;
5700 PUCHAR buffer;
5701 PIRP irp2;
5702 KEVENT event;
5703 ULONG length = 0;
5704
5705 //
5706 // This function must be called at less than dispatch level.
5707 // Fail if IRQL >= DISPATCH_LEVEL.
5708 //
5709 PAGED_CODE();
5710 CHECK_IRQL();
5711
5712 //
5713 // Validate the request.
5714 //
5715
5716 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5717
5718 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < (sizeof(SENDCMDINPARAMS) - 1)) {
5719 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Input buffer length invalid.\n"));
5720 return STATUS_INVALID_PARAMETER;
5721 }
5722
5723 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
5724 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Output buffer too small.\n"));
5725 return STATUS_BUFFER_TOO_SMALL;
5726 }
5727
5728 //
5729 // Create notification event object to be used to signal the
5730 // request completion.
5731 //
5732
5733 KeInitializeEvent(&event, NotificationEvent, FALSE);
5734
5735 //
5736 // use controlCode as a sort of 'STATUS_SUCCESS' to see if it's
5737 // a valid request type
5738 //
5739
5740 if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
5741
5742 length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
5743 controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
5744
5745 } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
5746
5747 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
5748
5749 case READ_ATTRIBUTES:
5750 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
5751 length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
5752 break;
5753
5754 case READ_THRESHOLDS:
5755 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
5756 length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
5757 break;
5758
5759 case SMART_READ_LOG: {
5760
5761 if (diskData->FailurePredictionCapability != FailurePredictionSmart) {
5762 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: SMART failure prediction not supported.\n"));
5763 return STATUS_INVALID_DEVICE_REQUEST;
5764 }
5765
5766 //
5767 // Calculate additional length based on number of sectors to be read.
5768 // Then verify the output buffer is large enough.
5769 //
5770
5771 length = cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE;
5772
5773 //
5774 // Ensure at least 1 sector is going to be read
5775 //
5776 if (length == 0) {
5777 return STATUS_INVALID_PARAMETER;
5778 }
5779
5780 length += max(sizeof(SENDCMDOUTPARAMS), sizeof(SENDCMDINPARAMS));
5781
5782 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < length - 1) {
5783 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Output buffer too small for SMART_READ_LOG.\n"));
5784 return STATUS_BUFFER_TOO_SMALL;
5785 }
5786
5787 controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_LOG;
5788 break;
5789 }
5790 }
5791 }
5792
5793 if (controlCode == 0) {
5794 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Invalid request.\n"));
5795 return STATUS_INVALID_PARAMETER;
5796 }
5797
5798 srbControl = ExAllocatePoolWithTag(NonPagedPoolNx,
5799 sizeof(SRB_IO_CONTROL) + length,
5800 DISK_TAG_SMART);
5801
5802 if (srbControl == NULL) {
5803 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Unable to allocate memory.\n"));
5804 return STATUS_INSUFFICIENT_RESOURCES;
5805 }
5806
5807 //
5808 // fill in srbControl fields
5809 //
5810
5811 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
5812 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
5813 srbControl->Timeout = fdoExtension->TimeOutValue;
5814 srbControl->Length = length;
5815 srbControl->ControlCode = controlCode;
5816
5817 //
5818 // Point to the 'buffer' portion of the SRB_CONTROL
5819 //
5820
5821 buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
5822
5823 //
5824 // Ensure correct target is set in the cmd parameters.
5825 //
5826
5827 cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
5828
5829 //
5830 // Copy the IOCTL parameters to the srb control buffer area.
5831 //
5832
5833 RtlMoveMemory(buffer,
5834 Irp->AssociatedIrp.SystemBuffer,
5835 sizeof(SENDCMDINPARAMS) - 1);
5836
5837 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
5838 commonExtension->LowerDeviceObject,
5839 srbControl,
5840 sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
5841 srbControl,
5842 sizeof(SRB_IO_CONTROL) + length,
5843 FALSE,
5844 &event,
5845 &ioStatus);
5846
5847 if (irp2 == NULL) {
5848 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartReceiveDriveData: Unable to allocate IRP.\n"));
5849 FREE_POOL(srbControl);
5850 return STATUS_INSUFFICIENT_RESOURCES;
5851 }
5852
5853 //
5854 // Call the port driver with the request and wait for it to complete.
5855 //
5856
5857 status = IoCallDriver(commonExtension->LowerDeviceObject, irp2);
5858
5859 if (status == STATUS_PENDING) {
5860 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
5861 status = ioStatus.Status;
5862 }
5863
5864 //
5865 // Copy the data received into the output buffer. Since the status buffer
5866 // contains error information also, always perform this copy. IO will
5867 // either pass this back to the app, or zero it, in case of error.
5868 //
5869
5870 buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
5871
5872 if (NT_SUCCESS(status)) {
5873
5874 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length - 1);
5875 Irp->IoStatus.Information = length - 1;
5876
5877 } else {
5878
5879 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
5880 Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
5881
5882 }
5883
5884 FREE_POOL(srbControl);
5885
5886 return status;
5887 }
5888
5889 NTSTATUS
DiskIoctlSmartSendDriveCommand(IN PDEVICE_OBJECT DeviceObject,IN OUT PIRP Irp)5890 DiskIoctlSmartSendDriveCommand(
5891 IN PDEVICE_OBJECT DeviceObject,
5892 IN OUT PIRP Irp
5893 )
5894
5895 /*++
5896
5897 Routine Description:
5898
5899 This routine services SMART_SEND_DRIVE_COMMAND. This function
5900 allows the caller to send SMART commands to the device.
5901
5902 This function must be called at IRQL < DISPATCH_LEVEL.
5903
5904 Arguments:
5905
5906 DeviceObject - Supplies the device object associated with this request.
5907
5908 Irp - The IRP to be processed
5909
5910 Return Value:
5911
5912 NTSTATUS code
5913
5914 --*/
5915
5916 {
5917 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5918 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
5919 PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
5920 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
5921 NTSTATUS status = STATUS_INVALID_PARAMETER;
5922
5923 PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
5924 PSRB_IO_CONTROL srbControl;
5925 IO_STATUS_BLOCK ioStatus = { 0 };
5926 ULONG controlCode = 0;
5927 PUCHAR buffer;
5928 PIRP irp2;
5929 KEVENT event;
5930 ULONG length = 0;
5931
5932 //
5933 // This function must be called at less than dispatch level.
5934 // Fail if IRQL >= DISPATCH_LEVEL.
5935 //
5936 PAGED_CODE();
5937 CHECK_IRQL();
5938
5939 //
5940 // Validate the request.
5941 //
5942
5943 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: DeviceObject %p Irp %p\n", DeviceObject, Irp));
5944
5945 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < (sizeof(SENDCMDINPARAMS) - 1)) {
5946 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Input buffer size invalid.\n"));
5947 return STATUS_INVALID_PARAMETER;
5948 }
5949
5950 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(SENDCMDOUTPARAMS) - 1)) {
5951 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Output buffer too small.\n"));
5952 return STATUS_BUFFER_TOO_SMALL;
5953 }
5954
5955 //
5956 // Create notification event object to be used to signal the
5957 // request completion.
5958 //
5959
5960 KeInitializeEvent(&event, NotificationEvent, FALSE);
5961
5962 if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
5963
5964 switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
5965
5966 case SMART_WRITE_LOG: {
5967
5968 if (diskData->FailurePredictionCapability != FailurePredictionSmart) {
5969
5970 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: SMART failure prediction not supported.\n"));
5971 return STATUS_INVALID_DEVICE_REQUEST;
5972 }
5973
5974 //
5975 // Calculate additional length based on number of sectors to be written.
5976 // Then verify the input buffer is large enough.
5977 //
5978
5979 length = cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE;
5980
5981 //
5982 // Ensure at least 1 sector is going to be written
5983 //
5984
5985 if (length == 0) {
5986 return STATUS_INVALID_PARAMETER;
5987 }
5988
5989 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
5990 (sizeof(SENDCMDINPARAMS) - 1) + length) {
5991
5992 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Input buffer too small for SMART_WRITE_LOG.\n"));
5993 return STATUS_BUFFER_TOO_SMALL;
5994 }
5995
5996 controlCode = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG;
5997 break;
5998 }
5999
6000 case ENABLE_SMART:
6001 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
6002 break;
6003
6004 case DISABLE_SMART:
6005 controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
6006 break;
6007
6008 case RETURN_SMART_STATUS:
6009
6010 //
6011 // Ensure bBuffer is at least 2 bytes (to hold the values of
6012 // cylinderLow and cylinderHigh).
6013 //
6014
6015 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
6016 (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
6017
6018 return STATUS_BUFFER_TOO_SMALL;
6019 break;
6020 }
6021
6022 controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
6023 length = sizeof(IDEREGS);
6024 break;
6025
6026 case ENABLE_DISABLE_AUTOSAVE:
6027 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
6028 break;
6029
6030 case SAVE_ATTRIBUTE_VALUES:
6031 controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
6032 break;
6033
6034 case EXECUTE_OFFLINE_DIAGS:
6035 //
6036 // Validate that this is an ok self test command
6037 //
6038 if (DiskIsValidSmartSelfTest(cmdInParameters->irDriveRegs.bSectorNumberReg)) {
6039
6040 controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
6041 }
6042 break;
6043
6044 case ENABLE_DISABLE_AUTO_OFFLINE:
6045 controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE;
6046 break;
6047 }
6048 }
6049
6050 if (controlCode == 0) {
6051 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Invalid request.\n"));
6052 return STATUS_INVALID_PARAMETER;
6053 }
6054
6055 length += max(sizeof(SENDCMDOUTPARAMS), sizeof(SENDCMDINPARAMS));
6056 srbControl = ExAllocatePoolWithTag(NonPagedPoolNx,
6057 sizeof(SRB_IO_CONTROL) + length,
6058 DISK_TAG_SMART);
6059
6060 if (srbControl == NULL) {
6061 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Unable to allocate memory.\n"));
6062 return STATUS_INSUFFICIENT_RESOURCES;
6063 }
6064
6065 //
6066 // fill in srbControl fields
6067 //
6068
6069 srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
6070 RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
6071 srbControl->Timeout = fdoExtension->TimeOutValue;
6072 srbControl->Length = length;
6073 srbControl->ControlCode = controlCode;
6074
6075 //
6076 // Point to the 'buffer' portion of the SRB_CONTROL
6077 //
6078
6079 buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
6080
6081 //
6082 // Ensure correct target is set in the cmd parameters.
6083 //
6084
6085 cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
6086
6087 //
6088 // Copy the IOCTL parameters to the srb control buffer area.
6089 //
6090
6091 if (cmdInParameters->irDriveRegs.bFeaturesReg == SMART_WRITE_LOG) {
6092 RtlMoveMemory(buffer,
6093 Irp->AssociatedIrp.SystemBuffer,
6094 sizeof(SENDCMDINPARAMS) - 1 +
6095 cmdInParameters->irDriveRegs.bSectorCountReg * SMART_LOG_SECTOR_SIZE);
6096 } else {
6097 RtlMoveMemory(buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
6098 }
6099
6100 irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
6101 commonExtension->LowerDeviceObject,
6102 srbControl,
6103 sizeof(SRB_IO_CONTROL) + length,
6104 srbControl,
6105 sizeof(SRB_IO_CONTROL) + length,
6106 FALSE,
6107 &event,
6108 &ioStatus);
6109
6110 if (irp2 == NULL) {
6111 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, "DiskIoctlSmartSendDriveCommand: Unable to allocate IRP.\n"));
6112 FREE_POOL(srbControl);
6113 return STATUS_INSUFFICIENT_RESOURCES;
6114 }
6115
6116 //
6117 // Call the port driver with the request and wait for it to complete.
6118 //
6119
6120 status = IoCallDriver(commonExtension->LowerDeviceObject, irp2);
6121
6122 if (status == STATUS_PENDING) {
6123 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
6124 status = ioStatus.Status;
6125 }
6126
6127 //
6128 // Copy the data received into the output buffer. Since the status buffer
6129 // contains error information also, always perform this copy. IO will
6130 // either pass this back to the app, or zero it, in case of error.
6131 //
6132
6133 buffer = (PUCHAR)srbControl + srbControl->HeaderLength;
6134
6135 //
6136 // Update the return buffer size based on the sub-command.
6137 //
6138
6139 if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
6140 length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
6141 } else {
6142 length = sizeof(SENDCMDOUTPARAMS) - 1;
6143 }
6144
6145 RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, buffer, length);
6146 Irp->IoStatus.Information = length;
6147
6148 FREE_POOL(srbControl);
6149
6150 return status;
6151 }
6152
6153
6154 VOID
DiskEtwEnableCallback(_In_ LPCGUID SourceId,_In_ ULONG IsEnabled,_In_ UCHAR Level,_In_ ULONGLONG MatchAnyKeyword,_In_ ULONGLONG MatchAllKeyword,_In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData,_In_opt_ PVOID CallbackContext)6155 DiskEtwEnableCallback (
6156 _In_ LPCGUID SourceId,
6157 _In_ ULONG IsEnabled,
6158 _In_ UCHAR Level,
6159 _In_ ULONGLONG MatchAnyKeyword,
6160 _In_ ULONGLONG MatchAllKeyword,
6161 _In_opt_ PEVENT_FILTER_DESCRIPTOR FilterData,
6162 _In_opt_ PVOID CallbackContext
6163 )
6164 /*+++
6165
6166 Routine Description:
6167
6168 This routine is the enable callback routine for ETW. It gets called when
6169 tracing is enabled or disabled for our provider.
6170
6171 Arguments:
6172
6173 As per the ETW callback.
6174
6175 Return Value:
6176
6177 None.
6178 --*/
6179
6180 {
6181 //
6182 // Initialize locals.
6183 //
6184 UNREFERENCED_PARAMETER(SourceId);
6185 UNREFERENCED_PARAMETER(Level);
6186 UNREFERENCED_PARAMETER(MatchAnyKeyword);
6187 UNREFERENCED_PARAMETER(MatchAllKeyword);
6188 UNREFERENCED_PARAMETER(FilterData);
6189 UNREFERENCED_PARAMETER(CallbackContext);
6190
6191 //
6192 // Set the ETW tracing enable state.
6193 //
6194 DiskETWEnabled = IsEnabled ? TRUE : FALSE;
6195
6196 return;
6197 }
6198
6199
6200