ReactOS 0.4.15-dev-8632-gbc8c7d1
class.c
Go to the documentation of this file.
1/*++
2
3Copyright (C) Microsoft Corporation, 1991 - 2010
4
5Module Name:
6
7 class.c
8
9Abstract:
10
11 SCSI class driver routines
12
13Environment:
14
15 kernel mode only
16
17Notes:
18
19
20Revision History:
21
22--*/
23
24#define CLASS_INIT_GUID 1
25#define DEBUG_MAIN_SOURCE 1
26
27#include "classp.h"
28#include "debug.h"
29#include <process.h>
30#include <devpkey.h>
31#include <ntiologc.h>
32
33
34#ifdef DEBUG_USE_WPP
35#include "class.tmh"
36#endif
37
38#ifdef ALLOC_PRAGMA
39 #pragma alloc_text(INIT, DriverEntry)
40 #pragma alloc_text(PAGE, ClassAddDevice)
41 #pragma alloc_text(PAGE, ClassClaimDevice)
42 #pragma alloc_text(PAGE, ClassCreateDeviceObject)
43 #pragma alloc_text(PAGE, ClassDispatchPnp)
44 #pragma alloc_text(PAGE, ClassGetDescriptor)
45 #pragma alloc_text(PAGE, ClassGetPdoId)
46 #pragma alloc_text(PAGE, ClassInitialize)
47 #pragma alloc_text(PAGE, ClassInitializeEx)
48 #pragma alloc_text(PAGE, ClassInvalidateBusRelations)
49 #pragma alloc_text(PAGE, ClassMarkChildMissing)
50 #pragma alloc_text(PAGE, ClassMarkChildrenMissing)
51 #pragma alloc_text(PAGE, ClassModeSense)
52 #pragma alloc_text(PAGE, ClassPnpQueryFdoRelations)
53 #pragma alloc_text(PAGE, ClassPnpStartDevice)
54 #pragma alloc_text(PAGE, ClassQueryPnpCapabilities)
55 #pragma alloc_text(PAGE, ClassQueryTimeOutRegistryValue)
56 #pragma alloc_text(PAGE, ClassRemoveDevice)
57 #pragma alloc_text(PAGE, ClassRetrieveDeviceRelations)
58 #pragma alloc_text(PAGE, ClassUpdateInformationInRegistry)
59 #pragma alloc_text(PAGE, ClassSendDeviceIoControlSynchronous)
60 #pragma alloc_text(PAGE, ClassUnload)
61 #pragma alloc_text(PAGE, ClasspAllocateReleaseRequest)
62 #pragma alloc_text(PAGE, ClasspFreeReleaseRequest)
63 #pragma alloc_text(PAGE, ClasspInitializeHotplugInfo)
64 #pragma alloc_text(PAGE, ClasspRegisterMountedDeviceInterface)
65 #pragma alloc_text(PAGE, ClasspScanForClassHacks)
66 #pragma alloc_text(PAGE, ClasspScanForSpecialInRegistry)
67 #pragma alloc_text(PAGE, ClasspModeSense)
68 #pragma alloc_text(PAGE, ClasspIsPortable)
69 #pragma alloc_text(PAGE, ClassAcquireChildLock)
70 #pragma alloc_text(PAGE, ClassDetermineTokenOperationCommandSupport)
71 #pragma alloc_text(PAGE, ClassDeviceProcessOffloadRead)
72 #pragma alloc_text(PAGE, ClassDeviceProcessOffloadWrite)
73 #pragma alloc_text(PAGE, ClasspServicePopulateTokenTransferRequest)
74 #pragma alloc_text(PAGE, ClasspServiceWriteUsingTokenTransferRequest)
75#if (NTDDI_VERSION >= NTDDI_WINBLUE)
76 #pragma alloc_text(PAGE, ClassModeSenseEx)
77#endif
78#endif
79
80#ifdef _MSC_VER
81#pragma prefast(disable:28159, "There are certain cases when we have to bugcheck...")
82#endif
83
84IO_COMPLETION_ROUTINE ClassCheckVerifyComplete;
85
86
89CONST LARGE_INTEGER Magic10000 = {{0xe219652c, 0xd1b71758}};
90GUID StoragePredictFailureDPSGuid = WDI_STORAGE_PREDICT_FAILURE_DPS_GUID;
91
92#define FirstDriveLetter 'C'
93#define LastDriveLetter 'Z'
94
96
97//
98// Keep track of whether security cookie is initialized or not. This is
99// required by SDL.
100//
101
103
104//
105// List Identifier for offload data transfer operations
106//
109
110//
111// List of FDOs that have enabled idle power management.
112//
115
116//
117// Handle used to register for power setting notifications.
118//
120
121//
122// Handle used to register for screen state setting notifications.
123//
125
126//
127// Disk idle timeout in milliseconds.
128// We default this to 0xFFFFFFFF as this is what the power manager considers
129// "never" and ensures we do not set a disk idle timeout until the power
130// manager calls us back with a different value.
131//
133
134
136{
137 DbgPrintEx(DPFLTR_CLASSPNP_ID, DPFLTR_INFO_LEVEL, "classpnp.sys is now unloading\n");
138
140 PoUnregisterPowerSettingCallback(PowerSettingNotificationHandle);
142 }
143
145 PoUnregisterPowerSettingCallback(ScreenStateNotificationHandle);
147 }
148
149
150 return STATUS_SUCCESS;
151}
152
153
154/*++////////////////////////////////////////////////////////////////////////////
155
156DriverEntry()
157
158Routine Description:
159
160 Temporary entry point needed to initialize the class system dll.
161 It doesn't do anything.
162
163Arguments:
164
165 DriverObject - Pointer to the driver object created by the system.
166
167Return Value:
168
169 STATUS_SUCCESS
170
171--*/
173NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
177 )
178{
181
182 return STATUS_SUCCESS;
183}
184
185
186
187/*++////////////////////////////////////////////////////////////////////////////
188
189ClassInitialize()
190
191Routine Description:
192
193 This routine is called by a class driver during its
194 DriverEntry routine to initialize the driver.
195
196Arguments:
197
198 Argument1 - Driver Object.
199 Argument2 - Registry Path.
200 InitializationData - Device-specific driver's initialization data.
201
202Return Value:
203
204 A valid return code for a DriverEntry routine.
205
206--*/
209ULONG
210NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
211ClassInitialize(
215 )
216{
219
220 PCLASS_DRIVER_EXTENSION driverExtension;
221
223
224
225
226 PAGED_CODE();
227
228 //
229 // Initialize the security cookie if needed.
230 //
231#ifndef __REACTOS__
232 if (InitSecurityCookie == FALSE) {
235 }
236#endif
237
238
239 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "\n\nSCSI Class Driver\n"));
240
242
243 //
244 // Validate the length of this structure. This is effectively a
245 // version check.
246 //
247
248 if (InitializationData->InitializationDataSize != sizeof(CLASS_INIT_DATA)) {
249
250 //
251 // This DebugPrint is to help third-party driver writers
252 //
253
254 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassInitialize: Class driver wrong version\n"));
256 }
257
258 //
259 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
260 // are not required entry points.
261 //
262
263 if ((!InitializationData->FdoData.ClassDeviceControl) ||
264 (!((InitializationData->FdoData.ClassReadWriteVerification) ||
265 (InitializationData->ClassStartIo))) ||
266 (!InitializationData->ClassAddDevice) ||
267 (!InitializationData->FdoData.ClassStartDevice)) {
268
269 //
270 // This DebugPrint is to help third-party driver writers
271 //
272
273 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,
274 "ClassInitialize: Class device-specific driver missing required "
275 "FDO entry\n"));
276
278 }
279
280 if ((InitializationData->ClassEnumerateDevice) &&
281 ((!InitializationData->PdoData.ClassDeviceControl) ||
282 (!InitializationData->PdoData.ClassStartDevice) ||
283 (!((InitializationData->PdoData.ClassReadWriteVerification) ||
284 (InitializationData->ClassStartIo))))) {
285
286 //
287 // This DebugPrint is to help third-party driver writers
288 //
289
290 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassInitialize: Class device-specific missing "
291 "required PDO entry\n"));
292
294 }
295
296 if((InitializationData->FdoData.ClassStopDevice == NULL) ||
297 ((InitializationData->ClassEnumerateDevice != NULL) &&
298 (InitializationData->PdoData.ClassStopDevice == NULL))) {
299
300 //
301 // This DebugPrint is to help third-party driver writers
302 //
303
304 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassInitialize: Class device-specific missing "
305 "required PDO entry\n"));
308 }
309
310 //
311 // Setup the default power handlers if the class driver didn't provide
312 // any.
313 //
314
315 if(InitializationData->FdoData.ClassPowerDevice == NULL) {
316 InitializationData->FdoData.ClassPowerDevice = ClassMinimalPowerHandler;
317 }
318
319 if((InitializationData->ClassEnumerateDevice != NULL) &&
320 (InitializationData->PdoData.ClassPowerDevice == NULL)) {
321 InitializationData->PdoData.ClassPowerDevice = ClassMinimalPowerHandler;
322 }
323
324 //
325 // warn that unload is not supported
326 //
327 // ISSUE-2000/02/03-peterwie
328 // We should think about making this a fatal error.
329 //
330
331 if(InitializationData->ClassUnload == NULL) {
332
333 //
334 // This DebugPrint is to help third-party driver writers
335 //
336
337 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClassInitialize: driver does not support unload %wZ\n",
338 RegistryPath));
339 }
340
341 //
342 // Create an extension for the driver object
343 //
344#ifdef _MSC_VER
345#pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case
346#endif
348
349 if(NT_SUCCESS(status)) {
350
351 //
352 // Copy the registry path into the driver extension so we can use it later
353 //
354
355 driverExtension->RegistryPath.Length = RegistryPath->Length;
356 driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
357
358 driverExtension->RegistryPath.Buffer =
360 RegistryPath->MaximumLength,
361 '1CcS');
362
363 if(driverExtension->RegistryPath.Buffer == NULL) {
364
366 return status;
367 }
368
370 &(driverExtension->RegistryPath),
372
373 //
374 // Copy the initialization data into the driver extension so we can reuse
375 // it during our add device routine
376 //
377
379 &(driverExtension->InitData),
381 sizeof(CLASS_INIT_DATA));
382
383 driverExtension->DeviceCount = 0;
384
385 ClassInitializeDispatchTables(driverExtension);
386
387 } else if (status == STATUS_OBJECT_NAME_COLLISION) {
388
389 //
390 // The extension already exists - get a pointer to it
391 //
392#ifdef _MSC_VER
393#pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case
394#endif
396
397 NT_ASSERT(driverExtension != NULL);
398
399 } else {
400
401 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassInitialize: Class driver extension could not be "
402 "allocated %lx\n", status));
403 return status;
404 }
405
406
407 //
408 // Update driver object with entry points.
409 //
410
411#ifdef _MSC_VER
412#pragma prefast(push)
413#pragma prefast(disable:28175, "Accessing DRIVER_OBJECT fileds is OK here since this function " \
414 "is supposed to be invoked from DriverEntry only")
415#endif
427
428 if (InitializationData->ClassStartIo) {
429 DriverObject->DriverStartIo = ClasspStartIo;
430 }
431
432 if ((InitializationData->ClassUnload) && (ClassPnpAllowUnload == TRUE)) {
433 DriverObject->DriverUnload = ClassUnload;
434 } else {
435 DriverObject->DriverUnload = NULL;
436 }
437
438 DriverObject->DriverExtension->AddDevice = ClassAddDevice;
439#ifdef _MSC_VER
440#pragma prefast(pop)
441#endif
442
443
444 //
445 // Register for event tracing
446 //
447 if (driverExtension->EtwHandle == 0) {
449 NULL,
450 NULL,
451 &driverExtension->EtwHandle);
452 if (!NT_SUCCESS(status)) {
453 driverExtension->EtwHandle = 0;
454 }
456 }
457
458
459 //
460 // Ensure these are only initialized once.
461 //
462 if (IdlePowerFDOList.Flink == NULL) {
465 }
466
468 return status;
469} // end ClassInitialize()
470
471/*++////////////////////////////////////////////////////////////////////////////
472
473ClassInitializeEx()
474
475Routine Description:
476
477 This routine is allows the caller to do any extra initialization or
478 setup that is not done in ClassInitialize. The operation is
479 controlled by the GUID that is passed and the contents of the Data
480 parameter is dependent upon the GUID.
481
482 This is the list of supported operations:
483
484 GUID_CLASSPNP_QUERY_REGINFOEX == CLASS_QUERY_WMI_REGINFO_EX_LIST
485
486 Initialized classpnp to callback a PCLASS_QUERY_WMI_REGINFO_EX
487 callback instead of a PCLASS_QUERY_WMI_REGINFO callback. The
488 former callback allows the driver to specify the name of the
489 mof resource.
490
491 GUID_CLASSPNP_SENSEINFO2 == CLASS_INTERPRET_SENSE_INFO2
492
493 Initialize classpnp to callback into class drive for interpretation
494 of all sense info, and to indicate the count of "history" to keep
495 for each packet.
496
497 GUID_CLASSPNP_WORKING_SET == CLASS_WORKING_SET
498
499 Allow class driver to override the min and max working set transfer
500 packet value used in classpnp.
501
502 GUID_CLASSPNP_SRB_SUPPORT == ULONG
503
504 Allow class driver to provide supported SRB types.
505
506Arguments:
507
508 DriverObject
509 Guid
510 Data
511
512Return Value:
513
514 Status Code
515
516--*/
519ULONG
520NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
521ClassInitializeEx(
525 )
526{
527 PCLASS_DRIVER_EXTENSION driverExtension;
528
530
531 PAGED_CODE();
532
533#ifdef _MSC_VER
534#pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case
535#endif
537
538 if (driverExtension == NULL)
539 {
542 }
543
545 {
547
548 //
549 // Indicate the device supports PCLASS_QUERY_REGINFO_EX
550 // callback instead of PCLASS_QUERY_REGINFO callback.
551 //
553
554 if (List->Size == sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST))
555 {
556 driverExtension->ClassFdoQueryWmiRegInfoEx = List->ClassFdoQueryWmiRegInfoEx;
557 driverExtension->ClassPdoQueryWmiRegInfoEx = List->ClassPdoQueryWmiRegInfoEx;
559 } else {
561 }
562 }
564 {
567
568 // only try to allocate memory for cached copy if size is correct
569 if (infoOriginal->Size != sizeof(CLASS_WORKING_SET))
570 {
571 // incorrect size -- client programming error
573 }
574 else
575 {
576 info = ExAllocatePoolWithTag(NonPagedPoolNx,
577 sizeof(CLASS_WORKING_SET),
579 );
580 if (info == NULL)
581 {
583 }
584 else
585 {
586 // cache the structure internally
587 RtlCopyMemory(info, infoOriginal, sizeof(CLASS_WORKING_SET));
589 }
590 }
591 // if we successfully cached a copy, validate all the data within
592 if (NT_SUCCESS(status))
593 {
594 if (info->Size != sizeof(CLASS_WORKING_SET))
595 {
596 // incorrect size -- client programming error
598 }
599 else if (info->XferPacketsWorkingSetMaximum > CLASS_WORKING_SET_MAXIMUM)
600 {
601 // too many requested in the working set
603 }
604 else if (info->XferPacketsWorkingSetMinimum > CLASS_WORKING_SET_MAXIMUM)
605 {
606 // too many requested in the working set
608 }
609 else if (driverExtension->InitData.FdoData.DeviceType != FILE_DEVICE_CD_ROM)
610 {
611 // classpnp developer wants to restrict this code path
612 // for now to CDROM devices only.
614 }
615 else if (driverExtension->WorkingSet != NULL)
616 {
617 // not allowed to change it once it is set for a driver
620 }
621 }
622 // save results or cleanup
623 if (NT_SUCCESS(status))
624 {
625 driverExtension->WorkingSet = info; info = NULL;
626 }
627 else
628 {
629 FREE_POOL( info );
630 }
631 }
633 {
636
637 // only try to allocate memory for cached copy if size is correct
638 if (infoOriginal->Size != sizeof(CLASS_INTERPRET_SENSE_INFO2))
639 {
640 // incorrect size -- client programming error
642 }
643 else
644 {
645 info = ExAllocatePoolWithTag(NonPagedPoolNx,
648 );
649 if (info == NULL)
650 {
652 }
653 else
654 {
655 // cache the structure internally
656 RtlCopyMemory(info, infoOriginal, sizeof(CLASS_INTERPRET_SENSE_INFO2));
658 }
659 }
660
661 // if we successfully cached a copy, validate all the data within
662 if (NT_SUCCESS(status))
663 {
664 if (info->Size != sizeof(CLASS_INTERPRET_SENSE_INFO2))
665 {
666 // incorrect size -- client programming error
668 }
670 {
671 // incorrect count -- client programming error
673 }
674 else if (info->Compress == NULL)
675 {
676 // Compression of the history is required to be supported
678 }
679 else if (info->HistoryCount == 0)
680 {
681 // History count cannot be zero
683 }
684 else if (info->Interpret == NULL)
685 {
686 // Updated interpret sense info function is required
688 }
689 else if (driverExtension->InitData.FdoData.DeviceType != FILE_DEVICE_CD_ROM)
690 {
691 // classpnp developer wants to restrict this code path
692 // for now to CDROM devices only.
694 }
695 else if (driverExtension->InterpretSenseInfo != NULL)
696 {
697 // not allowed to change it once it is set for a driver
700 }
701 }
702
703 // save results or cleanup
704 if (NT_SUCCESS(status))
705 {
706 driverExtension->InterpretSenseInfo = info; info = NULL;
707 }
708 else
709 {
710 FREE_POOL( info );
711 }
712 }
714 {
715 ULONG srbSupport = *((PULONG)Data);
716
717 //
718 // Validate that at least one of the supported bit flags is set. Assume
719 // all class drivers support SCSI_REQUEST_BLOCK as a class driver that
720 // supports only extended SRB is not feasible.
721 //
722 if ((srbSupport &
724 driverExtension->SrbSupport = srbSupport;
726
727 //
728 // Catch cases of a class driver reporting only extended SRB support
729 //
730 if ((driverExtension->SrbSupport & CLASS_SRB_SCSI_REQUEST_BLOCK) == 0) {
732 }
733 } else {
735 }
736 }
737 else
738 {
740 }
741
742 return status;
743
744} // end ClassInitializeEx()
745
746/*++////////////////////////////////////////////////////////////////////////////
747
748ClassUnload()
749
750Routine Description:
751
752 called when there are no more references to the driver. this allows
753 drivers to be updated without rebooting.
754
755Arguments:
756
757 DriverObject - a pointer to the driver object that is being unloaded
758
759Status:
760
761--*/
762VOID
763NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
766 )
767{
768 PCLASS_DRIVER_EXTENSION driverExtension;
769
770 PAGED_CODE();
771
772 NT_ASSERT( DriverObject->DeviceObject == NULL );
773
774#ifdef _MSC_VER
775#pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case
776#endif
778
779
780 if (driverExtension == NULL)
781 {
783 return;
784 }
785
786 NT_ASSERT(driverExtension->RegistryPath.Buffer != NULL);
787 NT_ASSERT(driverExtension->InitData.ClassUnload != NULL);
788
789 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "ClassUnload: driver unloading %wZ\n",
790 &driverExtension->RegistryPath));
791
792 //
793 // attempt to process the driver's unload routine first.
794 //
795
796 driverExtension->InitData.ClassUnload(DriverObject);
797
798 //
799 // free own allocated resources and return
800 //
801
802 FREE_POOL( driverExtension->WorkingSet );
803 FREE_POOL( driverExtension->InterpretSenseInfo );
804 FREE_POOL( driverExtension->RegistryPath.Buffer );
805 driverExtension->RegistryPath.Length = 0;
806 driverExtension->RegistryPath.MaximumLength = 0;
807
808
809 //
810 // Unregister ETW
811 //
812 if (driverExtension->EtwHandle != 0) {
813 EtwUnregister(driverExtension->EtwHandle);
814 driverExtension->EtwHandle = 0;
815
817 }
818
819
820 return;
821} // end ClassUnload()
822
823/*++////////////////////////////////////////////////////////////////////////////
824
825ClassAddDevice()
826
827Routine Description:
828
829 SCSI class driver add device routine. This is called by pnp when a new
830 physical device come into being.
831
832 This routine will call out to the class driver to verify that it should
833 own this device then will create and attach a device object and then hand
834 it to the driver to initialize and create symbolic links
835
836Arguments:
837
838 DriverObject - a pointer to the driver object that this is being created for
839 PhysicalDeviceObject - a pointer to the physical device object
840
841Status: STATUS_NO_SUCH_DEVICE if the class driver did not want this device
842 STATUS_SUCCESS if the creation and attachment was successful
843 status of device creation and initialization
844
845--*/
847#ifdef _MSC_VER
848#pragma prefast(suppress:28152, "We expect the class driver to clear the DO_DEVICE_INITIALIZING flag in its AddDevice routine.")
849#endif
850NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
854 )
855{
856#ifdef _MSC_VER
857#pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case
858#endif
860
862
863 PAGED_CODE();
864
865
866 status = driverExtension->InitData.ClassAddDevice(DriverObject,
868
869 return status;
870} // end ClassAddDevice()
871
872/*++////////////////////////////////////////////////////////////////////////////
873
874ClassDispatchPnp()
875
876Routine Description:
877
878 Storage class driver pnp routine. This is called by the io system when
879 a PNP request is sent to the device.
880
881Arguments:
882
883 DeviceObject - pointer to the device object
884
885 Irp - pointer to the io request packet
886
887Return Value:
888
889 status
890
891--*/
893NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
896 IN PIRP Irp
897 )
898{
899 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
900 BOOLEAN isFdo = commonExtension->IsFdo;
901
902 PCLASS_DRIVER_EXTENSION driverExtension;
903 PCLASS_INIT_DATA initData;
904 PCLASS_DEV_INFO devInfo;
905
907
908 NTSTATUS status = Irp->IoStatus.Status;
909 BOOLEAN completeRequest = TRUE;
910 BOOLEAN lockReleased = FALSE;
911
912
913 PAGED_CODE();
914
915 //
916 // Extract all the useful information out of the driver object
917 // extension
918 //
919
920#ifdef _MSC_VER
921#pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case
922#endif
924
925 if (driverExtension){
926
927 initData = &(driverExtension->InitData);
928
929 if(isFdo) {
930 devInfo = &(initData->FdoData);
931 } else {
932 devInfo = &(initData->PdoData);
933 }
934
936
937 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): minor code %#x for %s %p\n",
939 irpStack->MinorFunction,
940 isFdo ? "fdo" : "pdo",
941 DeviceObject));
942 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): previous %#x, current %#x\n",
944 commonExtension->PreviousState,
945 commonExtension->CurrentState));
946
947
948 switch(irpStack->MinorFunction) {
949
950 case IRP_MN_START_DEVICE: {
951
952 //
953 // if this is sent to the FDO we should forward it down the
954 // attachment chain before we start the FDO.
955 //
956
957 if (isFdo) {
958 status = ClassForwardIrpSynchronous(commonExtension, Irp);
959 }
960 else {
962 }
963
964 if (NT_SUCCESS(status)){
965 status = Irp->IoStatus.Status = ClassPnpStartDevice(DeviceObject);
966 }
967
968 break;
969 }
970
971
973
975 irpStack->Parameters.QueryDeviceRelations.Type;
976
977 PDEVICE_RELATIONS deviceRelations = NULL;
978
979
980 if(!isFdo) {
981
983
984 //
985 // Device relations has one entry built in to it's size.
986 //
987
989
990 deviceRelations = ExAllocatePoolWithTag(PagedPool,
991 sizeof(DEVICE_RELATIONS),
992 '2CcS');
993
994 if(deviceRelations != NULL) {
995
996 RtlZeroMemory(deviceRelations,
997 sizeof(DEVICE_RELATIONS));
998
999 Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
1000
1001 deviceRelations->Count = 1;
1002 deviceRelations->Objects[0] = DeviceObject;
1003 ObReferenceObject(deviceRelations->Objects[0]);
1004
1006 }
1007
1008 } else {
1009 //
1010 // PDO's just complete enumeration requests without altering
1011 // the status.
1012 //
1013
1014 status = Irp->IoStatus.Status;
1015 }
1016
1017 break;
1018
1019 } else if (type == BusRelations) {
1020
1021 NT_ASSERT(commonExtension->IsInitialized);
1022
1023 //
1024 // Make sure we support enumeration
1025 //
1026
1027 if(initData->ClassEnumerateDevice == NULL) {
1028
1029 //
1030 // Just send the request down to the lower driver. Perhaps
1031 // It can enumerate children.
1032 //
1033
1034 } else {
1035
1036 //
1037 // Re-enumerate the device
1038 //
1039
1041
1042 if(!NT_SUCCESS(status)) {
1043 completeRequest = TRUE;
1044 break;
1045 }
1046 }
1047 }
1048
1049
1052 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1053 completeRequest = FALSE;
1054
1055 break;
1056 }
1057
1058 case IRP_MN_QUERY_ID: {
1059
1060 BUS_QUERY_ID_TYPE idType = irpStack->Parameters.QueryId.IdType;
1061 UNICODE_STRING unicodeString;
1062
1063
1064 if(isFdo) {
1065
1066
1067 //
1068 // FDO's should just forward the query down to the lower
1069 // device objects
1070 //
1071
1074
1075 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1076 completeRequest = FALSE;
1077 break;
1078 }
1079
1080 //
1081 // PDO's need to give an answer - this is easy for now
1082 //
1083
1084 RtlInitUnicodeString(&unicodeString, NULL);
1085
1087 idType,
1088 &unicodeString);
1089
1091 //
1092 // The driver doesn't implement this ID (whatever it is).
1093 // Use the status out of the IRP so that we don't mangle a
1094 // response from someone else.
1095 //
1096
1097 status = Irp->IoStatus.Status;
1098 } else if(NT_SUCCESS(status)) {
1099 Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer;
1100 } else {
1101 Irp->IoStatus.Information = (ULONG_PTR) NULL;
1102 }
1103
1104 break;
1105 }
1106
1109
1110
1111 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Processing QUERY_%s irp\n",
1113 ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
1114 "STOP" : "REMOVE")));
1115
1116 //
1117 // If this device is in use for some reason (paging, etc...)
1118 // then we need to fail the request.
1119 //
1120
1121 if(commonExtension->PagingPathCount != 0) {
1122
1123 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): device is in paging "
1124 "path and cannot be removed\n",
1125 DeviceObject, Irp));
1127 break;
1128 }
1129
1130
1131 //
1132 // Check with the class driver to see if the query operation
1133 // can succeed.
1134 //
1135
1136 if(irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) {
1138 irpStack->MinorFunction);
1139 } else {
1141 irpStack->MinorFunction);
1142 }
1143
1144 if(NT_SUCCESS(status)) {
1145
1146 //
1147 // ASSERT that we never get two queries in a row, as
1148 // this will severly mess up the state machine
1149 //
1150 NT_ASSERT(commonExtension->CurrentState != irpStack->MinorFunction);
1151 commonExtension->PreviousState = commonExtension->CurrentState;
1152 commonExtension->CurrentState = irpStack->MinorFunction;
1153
1154 if(isFdo) {
1155 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Forwarding QUERY_"
1156 "%s irp\n", DeviceObject, Irp,
1157 ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
1158 "STOP" : "REMOVE")));
1159 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1160 }
1161 }
1162
1163
1164 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Final status == %x\n",
1166
1167 break;
1168 }
1169
1172
1173
1174 //
1175 // Check with the class driver to see if the query or cancel
1176 // operation can succeed.
1177 //
1178
1179 if(irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) {
1181 irpStack->MinorFunction);
1182 NT_ASSERTMSG("ClassDispatchPnp !! CANCEL_STOP_DEVICE should never be failed\n", NT_SUCCESS(status));
1183 } else {
1185 irpStack->MinorFunction);
1186 NT_ASSERTMSG("ClassDispatchPnp !! CANCEL_REMOVE_DEVICE should never be failed\n", NT_SUCCESS(status));
1187 }
1188
1189 Irp->IoStatus.Status = status;
1190
1191 //
1192 // We got a CANCEL - roll back to the previous state only
1193 // if the current state is the respective QUERY state.
1194 //
1195
1196 if(((irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) &&
1197 (commonExtension->CurrentState == IRP_MN_QUERY_STOP_DEVICE)
1198 ) ||
1200 (commonExtension->CurrentState == IRP_MN_QUERY_REMOVE_DEVICE)
1201 )
1202 ) {
1203
1204 commonExtension->CurrentState =
1205 commonExtension->PreviousState;
1206 commonExtension->PreviousState = 0xff;
1207
1208 }
1209
1210
1211 if(isFdo) {
1212
1213
1216 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1217 completeRequest = FALSE;
1218 } else {
1220 }
1221
1222 break;
1223 }
1224
1225 case IRP_MN_STOP_DEVICE: {
1226
1227
1228 //
1229 // These all mean nothing to the class driver currently. The
1230 // port driver will handle all queueing when necessary.
1231 //
1232
1233 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): got stop request for %s\n",
1235 (isFdo ? "fdo" : "pdo")
1236 ));
1237
1238 NT_ASSERT(commonExtension->PagingPathCount == 0);
1239
1240 //
1241 // ISSUE-2000/02/03-peterwie
1242 // if we stop the timer here then it means no class driver can
1243 // do i/o in its ClassStopDevice routine. This is because the
1244 // retry (among other things) is tied into the tick handler
1245 // and disabling retries could cause the class driver to deadlock.
1246 // Currently no class driver we're aware of issues i/o in its
1247 // Stop routine but this is a case we may want to defend ourself
1248 // against.
1249 //
1250
1252
1253
1255
1256 NT_ASSERTMSG("ClassDispatchPnp !! STOP_DEVICE should never be failed\n", NT_SUCCESS(status));
1257
1258 if(isFdo) {
1259 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1260 }
1261
1262 if(NT_SUCCESS(status)) {
1263 commonExtension->CurrentState = irpStack->MinorFunction;
1264 commonExtension->PreviousState = 0xff;
1265 }
1266
1267
1268 break;
1269 }
1270
1273 UCHAR removeType = irpStack->MinorFunction;
1274
1275 //
1276 // Log a sytem event when non-removable disks are surprise-removed.
1277 //
1278 if (isFdo &&
1279 (removeType == IRP_MN_SURPRISE_REMOVAL)) {
1280
1281 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1282 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
1283 BOOLEAN logSurpriseRemove = TRUE;
1284 STORAGE_BUS_TYPE busType = fdoExtension->DeviceDescriptor->BusType;
1285
1286 //
1287 // Don't log an event for VHDs
1288 //
1289 if (busType == BusTypeFileBackedVirtual) {
1290 logSurpriseRemove = FALSE;
1291
1292 } else if (fdoData->HotplugInfo.MediaRemovable) {
1293 logSurpriseRemove = FALSE;
1294
1295 } else if (fdoData->HotplugInfo.DeviceHotplug && ( busType == BusTypeUsb || busType == BusType1394)) {
1296
1297 /*
1298 This device is reported as DeviceHotplug but since the busType is Usb or 1394, don't log an event
1299 Note that some storage arrays may report DeviceHotplug and we would like to log an event in those cases
1300 */
1301
1302 logSurpriseRemove = FALSE;
1303 }
1304
1305 if (logSurpriseRemove) {
1306
1308 }
1309
1310 }
1311
1312 if (commonExtension->PagingPathCount != 0) {
1313 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): paging device is getting removed!", DeviceObject, Irp));
1314 }
1315
1316 //
1317 // Release the lock for this IRP before calling in.
1318 //
1320 lockReleased = TRUE;
1321
1322 /*
1323 * Set IsRemoved before propagating the REMOVE down the stack.
1324 * This keeps class-initiated I/O (e.g. the MCN irp) from getting sent
1325 * after we propagate the remove.
1326 */
1327 commonExtension->IsRemoved = REMOVE_PENDING;
1328
1329 /*
1330 * If a timer was started on the device, stop it.
1331 */
1333
1334 /*
1335 * "Fire-and-forget" the remove irp to the lower stack.
1336 * Don't touch the irp (or the irp stack!) after this.
1337 */
1338 if (isFdo) {
1339
1340
1342 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1344 completeRequest = FALSE;
1345 }
1346 else {
1348 }
1349
1350 /*
1351 * Do our own cleanup and call the class driver's remove
1352 * cleanup routine.
1353 * For IRP_MN_REMOVE_DEVICE, this also deletes our device object,
1354 * so don't touch the extension after this.
1355 */
1356 commonExtension->PreviousState = commonExtension->CurrentState;
1357 commonExtension->CurrentState = removeType;
1358 ClassRemoveDevice(DeviceObject, removeType);
1359
1360 break;
1361 }
1362
1364
1366 BOOLEAN setPagable;
1367
1368
1369 switch(type) {
1370
1371 case DeviceUsageTypePaging: {
1372
1373 if ((irpStack->Parameters.UsageNotification.InPath) &&
1374 (commonExtension->CurrentState != IRP_MN_START_DEVICE)) {
1375
1376 //
1377 // Device isn't started. Don't allow adding a
1378 // paging file, but allow a removal of one.
1379 //
1380
1382 break;
1383 }
1384
1385 NT_ASSERT(commonExtension->IsInitialized);
1386
1387 /*
1388 * Ensure that this user thread is not suspended while we are holding the PathCountEvent.
1389 */
1391
1392 (VOID)KeWaitForSingleObject(&commonExtension->PathCountEvent,
1394 FALSE, NULL);
1396
1397 //
1398 // If the volume is removable we should try to lock it in
1399 // place or unlock it once per paging path count
1400 //
1401
1402 if (commonExtension->IsFdo){
1405 Irp,
1407 (BOOLEAN)irpStack->Parameters.UsageNotification.InPath);
1408 }
1409
1410 if (!NT_SUCCESS(status)){
1411 KeSetEvent(&commonExtension->PathCountEvent, IO_NO_INCREMENT, FALSE);
1413 break;
1414 }
1415
1416 //
1417 // if removing last paging device, need to set DO_POWER_PAGABLE
1418 // bit here, and possible re-set it below on failure.
1419 //
1420
1421 setPagable = FALSE;
1422
1423 if ((!irpStack->Parameters.UsageNotification.InPath) &&
1424 (commonExtension->PagingPathCount == 1)) {
1425
1426 //
1427 // removing last paging file
1428 // must have DO_POWER_PAGABLE bits set, but only
1429 // if none set the DO_POWER_INRUSH bit and no other special files
1430 //
1431
1432 if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) {
1433 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last "
1434 "paging file removed, but "
1435 "DO_POWER_INRUSH was set, so NOT "
1436 "setting DO_POWER_PAGABLE\n",
1437 DeviceObject, Irp));
1438 } else if ((commonExtension->HibernationPathCount == 0) &&
1439 (commonExtension->DumpPathCount == 0)) {
1440 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last "
1441 "paging file removed, "
1442 "setting DO_POWER_PAGABLE\n",
1443 DeviceObject, Irp));
1445 setPagable = TRUE;
1446 }
1447
1448 }
1449
1450 //
1451 // forward the irp before finishing handling the
1452 // special cases
1453 //
1454
1455 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1456
1457 //
1458 // now deal with the failure and success cases.
1459 // note that we are not allowed to fail the irp
1460 // once it is sent to the lower drivers.
1461 //
1462
1463 if (NT_SUCCESS(status)) {
1464
1466 (volatile LONG *)&commonExtension->PagingPathCount,
1467 irpStack->Parameters.UsageNotification.InPath);
1468
1469 if (irpStack->Parameters.UsageNotification.InPath) {
1470 if (commonExtension->PagingPathCount == 1) {
1471 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): "
1472 "Clearing PAGABLE bit\n",
1473 DeviceObject, Irp));
1475
1476
1477 }
1478
1479 }
1480
1481 } else {
1482
1483 //
1484 // cleanup the changes done above
1485 //
1486
1487 if (setPagable == TRUE) {
1488 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Unsetting "
1489 "PAGABLE bit due to irp failure\n",
1490 DeviceObject, Irp));
1492 setPagable = FALSE;
1493 }
1494
1495 //
1496 // relock or unlock the media if needed.
1497 //
1498
1499 if (commonExtension->IsFdo) {
1500
1503 Irp,
1505 (BOOLEAN)!irpStack->Parameters.UsageNotification.InPath);
1506 }
1507 }
1508
1509 //
1510 // set the event so the next one can occur.
1511 //
1512
1513 KeSetEvent(&commonExtension->PathCountEvent,
1516 break;
1517 }
1518
1520
1521 //
1522 // if removing last hiber device, need to set DO_POWER_PAGABLE
1523 // bit here, and possible re-set it below on failure.
1524 //
1525
1526 setPagable = FALSE;
1527
1528 if ((!irpStack->Parameters.UsageNotification.InPath) &&
1529 (commonExtension->HibernationPathCount == 1)) {
1530
1531 //
1532 // removing last hiber file
1533 // must have DO_POWER_PAGABLE bits set, but only
1534 // if none set the DO_POWER_INRUSH bit and no other special files
1535 //
1536
1537 if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) {
1538 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last "
1539 "hiber file removed, but "
1540 "DO_POWER_INRUSH was set, so NOT "
1541 "setting DO_POWER_PAGABLE\n",
1542 DeviceObject, Irp));
1543 } else if ((commonExtension->PagingPathCount == 0) &&
1544 (commonExtension->DumpPathCount == 0)) {
1545 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last "
1546 "hiber file removed, "
1547 "setting DO_POWER_PAGABLE\n",
1548 DeviceObject, Irp));
1550 setPagable = TRUE;
1551 }
1552
1553 }
1554
1555 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1556 if (!NT_SUCCESS(status)) {
1557
1558 if (setPagable == TRUE) {
1559 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Unsetting "
1560 "PAGABLE bit due to irp failure\n",
1561 DeviceObject, Irp));
1563 setPagable = FALSE;
1564 }
1565
1566 } else {
1567
1569 (volatile LONG *)&commonExtension->HibernationPathCount,
1570 irpStack->Parameters.UsageNotification.InPath
1571 );
1572
1573 if ((irpStack->Parameters.UsageNotification.InPath) &&
1574 (commonExtension->HibernationPathCount == 1)) {
1575 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): "
1576 "Clearing PAGABLE bit\n",
1577 DeviceObject, Irp));
1579 }
1580 }
1581
1582 break;
1583 }
1584
1586
1587 //
1588 // if removing last dump device, need to set DO_POWER_PAGABLE
1589 // bit here, and possible re-set it below on failure.
1590 //
1591
1592 setPagable = FALSE;
1593
1594 if ((!irpStack->Parameters.UsageNotification.InPath) &&
1595 (commonExtension->DumpPathCount == 1)) {
1596
1597 //
1598 // removing last dump file
1599 // must have DO_POWER_PAGABLE bits set, but only
1600 // if none set the DO_POWER_INRUSH bit and no other special files
1601 //
1602
1603 if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) {
1604 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last "
1605 "dump file removed, but "
1606 "DO_POWER_INRUSH was set, so NOT "
1607 "setting DO_POWER_PAGABLE\n",
1608 DeviceObject, Irp));
1609 } else if ((commonExtension->PagingPathCount == 0) &&
1610 (commonExtension->HibernationPathCount == 0)) {
1611 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Last "
1612 "dump file removed, "
1613 "setting DO_POWER_PAGABLE\n",
1614 DeviceObject, Irp));
1616 setPagable = TRUE;
1617 }
1618
1619 }
1620
1621 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1622 if (!NT_SUCCESS(status)) {
1623
1624 if (setPagable == TRUE) {
1625 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): Unsetting "
1626 "PAGABLE bit due to irp failure\n",
1627 DeviceObject, Irp));
1629 setPagable = FALSE;
1630 }
1631
1632 } else {
1633
1635 (volatile LONG *)&commonExtension->DumpPathCount,
1636 irpStack->Parameters.UsageNotification.InPath
1637 );
1638
1639 if ((irpStack->Parameters.UsageNotification.InPath) &&
1640 (commonExtension->DumpPathCount == 1)) {
1641 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): "
1642 "Clearing PAGABLE bit\n",
1643 DeviceObject, Irp));
1645 }
1646 }
1647
1648 break;
1649 }
1650
1651 case DeviceUsageTypeBoot: {
1652
1653 if (isFdo) {
1655
1656 fdoData = ((PFUNCTIONAL_DEVICE_EXTENSION)(DeviceObject->DeviceExtension))->PrivateFdoData;
1657
1658
1659 //
1660 // If boot disk has removal policy as RemovalPolicyExpectSurpriseRemoval (e.g. disk is hotplug-able),
1661 // change the removal policy to RemovalPolicyExpectOrderlyRemoval.
1662 // This will cause the write cache of disk to be enabled on subsequent start Fdo (next boot).
1663 //
1664 if ((fdoData != NULL) &&
1665 fdoData->HotplugInfo.DeviceHotplug) {
1666
1667 fdoData->HotplugInfo.DeviceHotplug = FALSE;
1668 fdoData->HotplugInfo.MediaRemovable = FALSE;
1669
1670 ClassSetDeviceParameter((PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension,
1674 }
1675 }
1676
1677 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1678 break;
1679 }
1680
1681 default: {
1683 break;
1684 }
1685 }
1686 break;
1687 }
1688
1690
1691 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): QueryCapabilities\n",
1692 DeviceObject, Irp));
1693
1694 if(!isFdo) {
1695
1698 irpStack->Parameters.DeviceCapabilities.Capabilities
1699 );
1700
1701 break;
1702
1703 } else {
1704
1705 PDEVICE_CAPABILITIES deviceCapabilities;
1706 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1708
1709 fdoExtension = DeviceObject->DeviceExtension;
1710 fdoData = fdoExtension->PrivateFdoData;
1711 deviceCapabilities =
1712 irpStack->Parameters.DeviceCapabilities.Capabilities;
1713
1714 //
1715 // forward the irp before handling the special cases
1716 //
1717
1718 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1719 if (!NT_SUCCESS(status)) {
1720 break;
1721 }
1722
1723 //
1724 // we generally want to remove the device from the hotplug
1725 // applet, which requires the SR-OK bit to be set.
1726 // only when the user specifies that they are capable of
1727 // safely removing things do we want to clear this bit
1728 // (saved in WriteCacheEnableOverride)
1729 //
1730 // setting of this bit is done either above, or by the
1731 // lower driver.
1732 //
1733 // note: may not be started, so check we have FDO data first.
1734 //
1735
1736 if (fdoData &&
1738 if (deviceCapabilities->SurpriseRemovalOK) {
1739 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "Classpnp: Clearing SR-OK bit in "
1740 "device capabilities due to hotplug "
1741 "device or media\n"));
1742 }
1743 deviceCapabilities->SurpriseRemovalOK = FALSE;
1744 }
1745 break;
1746
1747 } // end QUERY_CAPABILITIES for FDOs
1748
1749 break;
1750
1751
1752 } // end QUERY_CAPABILITIES
1753
1754 default: {
1755
1756 if (isFdo){
1757
1758
1760
1762 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1763
1764 completeRequest = FALSE;
1765 }
1766
1767 break;
1768 }
1769 }
1770 }
1771 else {
1772 NT_ASSERT(driverExtension);
1774 }
1775
1776 if (completeRequest){
1777 Irp->IoStatus.Status = status;
1778
1779 if (!lockReleased){
1781 }
1782
1784
1785 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): leaving with previous %#x, current %#x.", DeviceObject, Irp, commonExtension->PreviousState, commonExtension->CurrentState));
1786 }
1787 else {
1788 /*
1789 * The irp is already completed so don't touch it.
1790 * This may be a remove so don't touch the device extension.
1791 */
1792 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "ClassDispatchPnp (%p,%p): leaving.", DeviceObject, Irp));
1793 }
1794
1795 return status;
1796} // end ClassDispatchPnp()
1797
1798
1799/*++////////////////////////////////////////////////////////////////////////////
1800
1801ClassPnpStartDevice()
1802
1803Routine Description:
1804
1805 Storage class driver routine for IRP_MN_START_DEVICE requests.
1806 This routine kicks off any device specific initialization
1807
1808Arguments:
1809
1810 DeviceObject - a pointer to the device object
1811
1812 Irp - a pointer to the io request packet
1813
1814Return Value:
1815
1816 none
1817
1818--*/
1820{
1821 PCLASS_DRIVER_EXTENSION driverExtension;
1822 PCLASS_INIT_DATA initData;
1823
1824 PCLASS_DEV_INFO devInfo;
1825
1826 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1827 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1828 BOOLEAN isFdo = commonExtension->IsFdo;
1829
1830 BOOLEAN isMountedDevice = TRUE;
1831 BOOLEAN isPortable = FALSE;
1832
1834 PDEVICE_POWER_DESCRIPTOR powerDescriptor = NULL;
1835
1836
1837 PAGED_CODE();
1838
1839#ifdef _MSC_VER
1840#pragma warning(suppress:4054) // okay to type cast function pointer as data pointer for this use case
1841#endif
1842 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, CLASS_DRIVER_EXTENSION_KEY);
1843
1844 initData = &(driverExtension->InitData);
1845 if(isFdo) {
1846 devInfo = &(initData->FdoData);
1847 } else {
1848 devInfo = &(initData->PdoData);
1849 }
1850
1851 NT_ASSERT(devInfo->ClassInitDevice != NULL);
1852 NT_ASSERT(devInfo->ClassStartDevice != NULL);
1853
1854 if (!commonExtension->IsInitialized){
1855
1856 //
1857 // perform FDO/PDO specific initialization
1858 //
1859
1860 if (isFdo){
1861 STORAGE_PROPERTY_ID propertyId;
1862
1863 //
1864 // allocate a private extension for class data
1865 //
1866
1867 if (fdoExtension->PrivateFdoData == NULL) {
1868 fdoExtension->PrivateFdoData = ExAllocatePoolWithTag(NonPagedPoolNx,
1869 sizeof(CLASS_PRIVATE_FDO_DATA),
1871 );
1872 }
1873
1874 if (fdoExtension->PrivateFdoData == NULL) {
1875 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate for private fdo data\n"));
1877 }
1878
1879 RtlZeroMemory(fdoExtension->PrivateFdoData, sizeof(CLASS_PRIVATE_FDO_DATA));
1880
1881
1882#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
1883 //
1884 // Allocate a structure to hold more data than what we can put in FUNCTIONAL_DEVICE_EXTENSION.
1885 // This structure's memory is managed by classpnp, so it is more extensible.
1886 //
1887 if (fdoExtension->AdditionalFdoData == NULL) {
1888 fdoExtension->AdditionalFdoData = ExAllocatePoolWithTag(NonPagedPoolNx,
1889 sizeof(ADDITIONAL_FDO_DATA),
1891 );
1892 }
1893
1894 if (fdoExtension->AdditionalFdoData == NULL) {
1895 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate memory for the additional data structure.\n"));
1897 }
1898
1899 RtlZeroMemory(fdoExtension->AdditionalFdoData, sizeof(ADDITIONAL_FDO_DATA));
1900#endif
1901
1902 status = ClasspInitializeTimer(fdoExtension);
1903 if (NT_SUCCESS(status) == FALSE) {
1904 FREE_POOL(fdoExtension->PrivateFdoData);
1905#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
1906 FREE_POOL(fdoExtension->AdditionalFdoData);
1907#endif
1908 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Failed to initialize tick timer\n"));
1910 }
1911
1912 //
1913 // allocate LowerLayerSupport for class data
1914 //
1915
1916 if (fdoExtension->FunctionSupportInfo == NULL) {
1917 fdoExtension->FunctionSupportInfo = (PCLASS_FUNCTION_SUPPORT_INFO)ExAllocatePoolWithTag(NonPagedPoolNx,
1919 '3BcS'
1920 );
1921 }
1922
1923 if (fdoExtension->FunctionSupportInfo == NULL) {
1924 ClasspDeleteTimer(fdoExtension);
1925 FREE_POOL(fdoExtension->PrivateFdoData);
1926#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
1927 FREE_POOL(fdoExtension->AdditionalFdoData);
1928#endif
1929 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate for FunctionSupportInfo\n"));
1931 }
1932
1933 //
1934 // initialize the struct's various fields.
1935 //
1936 RtlZeroMemory(fdoExtension->FunctionSupportInfo, sizeof(CLASS_FUNCTION_SUPPORT_INFO));
1937 KeInitializeSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock);
1938
1939 //
1940 // intialize the CommandStatus to -1 indicates that no effort made yet to retrieve the info.
1941 // Possible values of CommandStatus (data type: NTSTATUS):
1942 // -1: It's not attempted yet to retrieve the information.
1943 // success: Command sent and succeeded, information cached in FdoExtension.
1944 // failed/warning: Command is either not supported or failed by device or lower level driver.
1945 // The command should not be attempted again.
1946 //
1947 fdoExtension->FunctionSupportInfo->BlockLimitsData.CommandStatus = -1;
1948 fdoExtension->FunctionSupportInfo->DeviceCharacteristicsData.CommandStatus = -1;
1949 fdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus = -1;
1950 fdoExtension->FunctionSupportInfo->ReadCapacity16Data.CommandStatus = -1;
1951 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus = -1;
1952
1953
1954 KeInitializeTimer(&fdoExtension->PrivateFdoData->Retry.Timer);
1955 KeInitializeDpc(&fdoExtension->PrivateFdoData->Retry.Dpc,
1957 DeviceObject);
1958 KeInitializeSpinLock(&fdoExtension->PrivateFdoData->Retry.Lock);
1959 fdoExtension->PrivateFdoData->Retry.Granularity = KeQueryTimeIncrement();
1960 commonExtension->Reserved4 = (ULONG_PTR)(' GPH'); // debug aid
1961 InitializeListHead(&fdoExtension->PrivateFdoData->DeferredClientIrpList);
1962
1963 KeInitializeSpinLock(&fdoExtension->PrivateFdoData->SpinLock);
1964
1965 //
1966 // keep a pointer to the senseinfo2 stuff locally also (used in every read/write).
1967 //
1968 fdoExtension->PrivateFdoData->InterpretSenseInfo = driverExtension->InterpretSenseInfo;
1969
1970 fdoExtension->PrivateFdoData->MaxNumberOfIoRetries = NUM_IO_RETRIES;
1971
1972 //
1973 // Initialize release queue extended SRB
1974 //
1975 status = InitializeStorageRequestBlock(&(fdoExtension->PrivateFdoData->ReleaseQueueSrb.SrbEx),
1977 sizeof(fdoExtension->PrivateFdoData->ReleaseQueueSrb.ReleaseQueueSrbBuffer),
1978 0);
1979 if (!NT_SUCCESS(status)) {
1981 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP,
1982 "ClassPnpStartDevice: fail to initialize release queue extended SRB 0x%x\n", status));
1983 return status;
1984 }
1985
1986
1987 /*
1988 * Anchor the FDO in our static list.
1989 * Pnp is synchronized, so we shouldn't need any synchronization here.
1990 */
1991 InsertTailList(&AllFdosList, &fdoExtension->PrivateFdoData->AllFdosListEntry);
1992
1993 //
1994 // NOTE: the old interface allowed the class driver to allocate
1995 // this. this was unsafe for low-memory conditions. allocate one
1996 // unconditionally now, and modify our internal functions to use
1997 // our own exclusively as it is the only safe way to do this.
1998 //
1999
2000 status = ClasspAllocateReleaseQueueIrp(fdoExtension);
2001 if (!NT_SUCCESS(status)) {
2002 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate the private release queue irp\n"));
2003 return status;
2004 }
2005
2006 status = ClasspAllocatePowerProcessIrp(fdoExtension);
2007 if (!NT_SUCCESS(status)) {
2008 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: Cannot allocate the power process irp\n"));
2009 return status;
2010 }
2011
2012 //
2013 // Call port driver to get miniport properties for disk devices
2014 // It's ok for this call to fail
2015 //
2016
2017 if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) &&
2018 (!TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE))) {
2019
2020 propertyId = StorageMiniportProperty;
2021
2022 status = ClassGetDescriptor(fdoExtension->CommonExtension.LowerDeviceObject,
2023 &propertyId,
2024 (PVOID *)&fdoExtension->MiniportDescriptor);
2025
2026 //
2027 // function ClassGetDescriptor returns succeed with buffer "fdoExtension->MiniportDescriptor" allocated.
2028 //
2029 if ( NT_SUCCESS(status) &&
2030 (fdoExtension->MiniportDescriptor->Portdriver != StoragePortCodeSetStorport &&
2031 fdoExtension->MiniportDescriptor->Portdriver != StoragePortCodeSetUSBport) ) {
2032 //
2033 // field "IoTimeoutValue" supported for either Storport or USBStor
2034 //
2035 fdoExtension->MiniportDescriptor->IoTimeoutValue = 0;
2036 }
2037
2038
2039
2040 }
2041
2042 //
2043 // Call port driver to get adapter capabilities.
2044 //
2045
2046 propertyId = StorageAdapterProperty;
2047
2048 status = ClassGetDescriptor(
2049 commonExtension->LowerDeviceObject,
2050 &propertyId,
2051 (PVOID *)&fdoExtension->AdapterDescriptor);
2052 if (!NT_SUCCESS(status)) {
2053 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: ClassGetDescriptor [ADAPTER] failed %lx\n", status));
2054 return status;
2055 }
2056
2057 //
2058 // Call port driver to get device descriptor.
2059 //
2060
2061 propertyId = StorageDeviceProperty;
2062
2063 status = ClassGetDescriptor(
2064 commonExtension->LowerDeviceObject,
2065 &propertyId,
2066 (PVOID *)&fdoExtension->DeviceDescriptor);
2067 if (NT_SUCCESS(status)){
2068
2069 ClasspScanForSpecialInRegistry(fdoExtension);
2070 ClassScanForSpecial(fdoExtension, ClassBadItems, ClasspScanForClassHacks);
2071
2072 //
2073 // allow perf to be re-enabled after a given number of failed IOs
2074 // require this number to be at least CLASS_PERF_RESTORE_MINIMUM
2075 //
2076
2077 {
2079
2080 ClassGetDeviceParameter(fdoExtension,
2083 &t);
2085 fdoExtension->PrivateFdoData->Perf.ReEnableThreshhold = t;
2086 }
2087 }
2088
2089 //
2090 // compatibility comes first. writable cd media will not
2091 // get a SYNCH_CACHE on power down.
2092 //
2093 if (fdoExtension->DeviceObject->DeviceType != FILE_DEVICE_DISK) {
2094 SET_FLAG(fdoExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_SYNC_CACHE);
2095 }
2096
2097
2098 //
2099 // Test if the device is portable and updated the characteristics if so
2100 //
2101 status = ClasspIsPortable(fdoExtension,
2102 &isPortable);
2103
2104 if (NT_SUCCESS(status) && (isPortable == TRUE)) {
2105 DeviceObject->Characteristics |= FILE_PORTABLE_DEVICE;
2106 }
2107
2108 //
2109 // initialize the hotplug information only after the ScanForSpecial
2110 // routines, as it relies upon the hack flags.
2111 //
2112 status = ClasspInitializeHotplugInfo(fdoExtension);
2113 if (NT_SUCCESS(status)){
2114 /*
2115 * Allocate/initialize TRANSFER_PACKETs and related resources.
2116 */
2118 }
2119 else {
2120 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_PNP, "ClassPnpStartDevice: Could not initialize hotplug information %lx\n", status));
2122 }
2123 else {
2124 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: ClassGetDescriptor [DEVICE] failed %lx\n", status));
2125 return status;
2126 }
2127
2128
2129 if (NT_SUCCESS(status)) {
2130
2131 //
2132 // Retrieve info on whether async notification is supported by port drivers
2133 //
2134 propertyId = StorageDevicePowerProperty;
2135
2136 status = ClassGetDescriptor(fdoExtension->CommonExtension.LowerDeviceObject,
2137 &propertyId,
2138 (PVOID *)&powerDescriptor);
2139 if (NT_SUCCESS(status) && (powerDescriptor != NULL)) {
2140 fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported = powerDescriptor->AsynchronousNotificationSupported;
2141 fdoExtension->FunctionSupportInfo->IdlePower.D3ColdSupported = powerDescriptor->D3ColdSupported;
2142 fdoExtension->FunctionSupportInfo->IdlePower.NoVerifyDuringIdlePower = powerDescriptor->NoVerifyDuringIdlePower;
2143 FREE_POOL(powerDescriptor);
2144 } else {
2145 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "ClassPnpStartDevice: ClassGetDescriptor [DevicePower] failed %lx\n", status));
2146
2147 //
2148 // Ignore error as device power property is optional
2149 //
2151 }
2152 }
2153 }
2154
2155 //
2156 // ISSUE - drivers need to disable write caching on the media
2157 // if hotplug and !useroverride. perhaps we should
2158 // allow registration of a callback to enable/disable
2159 // write cache instead.
2160 //
2161
2162 if (NT_SUCCESS(status)){
2164 }
2165
2166 if (commonExtension->IsFdo) {
2167 fdoExtension->PrivateFdoData->Perf.OriginalSrbFlags = fdoExtension->SrbFlags;
2168
2169 //
2170 // initialization for disk device
2171 //
2172 if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) &&
2173 (!TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE))) {
2174
2175 ULONG accessAlignmentNotSupported = 0;
2176 ULONG qerrOverrideMode = QERR_SET_ZERO_ODX_OR_TP_ONLY;
2177 ULONG legacyErrorHandling = FALSE;
2178
2179 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP,
2180 "ClassPnpStartDevice: Enabling idle timer for %p\n", DeviceObject));
2181 // Initialize idle timer for disk devices
2182 ClasspInitializeIdleTimer(fdoExtension);
2183
2184 if (ClasspIsObsoletePortDriver(fdoExtension) == FALSE) {
2185 // get INQUIRY VPD support information. It's safe to send command as everything is ready in ClassInitDevice().
2186 ClasspGetInquiryVpdSupportInfo(fdoExtension);
2187
2188 // Query and cache away Logical Block Provisioning info in the FDO extension.
2189 // The cached information will be used in responding to some IOCTLs
2190 ClasspGetLBProvisioningInfo(fdoExtension);
2191
2192 //
2193 // Query and cache away Block Device ROD Limits info in the FDO extension.
2194 //
2195 if (fdoExtension->FunctionSupportInfo->ValidInquiryPages.BlockDeviceRODLimits) {
2196 ClassDetermineTokenOperationCommandSupport(DeviceObject);
2197 }
2198
2199 //
2200 // See if the user has specified a particular QERR override
2201 // mode. "Override" meaning setting QERR = 0 via Mode Select.
2202 // 0 = Only when ODX or Thin Provisioning are supported (default)
2203 // 1 = Always
2204 // 2 = Never (or any value >= 2)
2205 //
2206 ClassGetDeviceParameter(fdoExtension,
2209 &qerrOverrideMode);
2210
2211 //
2212 // If this device is thinly provisioned or supports ODX, we
2213 // may need to force QERR to zero. The user may have also
2214 // specified that we should always or never do this.
2215 //
2216 if (qerrOverrideMode == QERR_SET_ZERO_ALWAYS ||
2217 (qerrOverrideMode == QERR_SET_ZERO_ODX_OR_TP_ONLY &&
2218 (ClasspIsThinProvisioned(fdoExtension->FunctionSupportInfo) ||
2219 NT_SUCCESS(ClasspValidateOffloadSupported(DeviceObject, NULL))))) {
2220
2222 }
2223
2224 } else {
2225
2226 //
2227 // Since this device has been exposed by a legacy miniport (e.g. SCSIPort miniport)
2228 // set its LB Provisioning command status to an error status that will be surfaced
2229 // up to the caller of a TRIM/Unmap command.
2230 //
2231 fdoExtension->FunctionSupportInfo->LBProvisioningData.CommandStatus = STATUS_UNSUCCESSFUL;
2232 fdoExtension->FunctionSupportInfo->BlockLimitsData.CommandStatus = STATUS_UNSUCCESSFUL;
2233 fdoExtension->FunctionSupportInfo->BlockDeviceRODLimitsData.CommandStatus = STATUS_UNSUCCESSFUL;
2234 }
2235
2236 // Get registry setting of failing the IOCTL for AccessAlignment Property.
2237 ClassGetDeviceParameter(fdoExtension,
2240 &accessAlignmentNotSupported);
2241
2242 if (accessAlignmentNotSupported > 0) {
2243 fdoExtension->FunctionSupportInfo->RegAccessAlignmentQueryNotSupported = TRUE;
2244 }
2245
2246#if (NTDDI_VERSION >= NTDDI_WINBLUE)
2247
2248
2249 //
2250 // See if the user has specified legacy error handling.
2251 //
2252 ClassGetDeviceParameter(fdoExtension,
2255 &legacyErrorHandling);
2256
2257 if (legacyErrorHandling) {
2258 //
2259 // Legacy error handling means that the maximum number of
2260 // retries allowd for an IO request is 8 instead of 4.
2261 //
2262 fdoExtension->PrivateFdoData->MaxNumberOfIoRetries = LEGACY_NUM_IO_RETRIES;
2263 fdoExtension->PrivateFdoData->LegacyErrorHandling = TRUE;
2264 }
2265#else
2266 UNREFERENCED_PARAMETER(legacyErrorHandling);
2267#endif
2268
2269
2270 //
2271 // Get the copy offload max target duration value.
2272 // This function will set the default value if one hasn't been
2273 // specified in the registry.
2274 //
2275 ClasspGetCopyOffloadMaxDuration(DeviceObject,
2277 &(fdoExtension->PrivateFdoData->CopyOffloadMaxTargetDuration));
2278
2279 }
2280
2281 }
2282 }
2283
2284 if (!NT_SUCCESS(status)){
2285
2286 //
2287 // Just bail out - the remove that comes down will clean up the
2288 // initialized scraps.
2289 //
2290
2291 return status;
2292 } else {
2293 commonExtension->IsInitialized = TRUE;
2294 }
2295
2296 //
2297 // If device requests autorun functionality or a once a second callback
2298 // then enable the once per second timer. Exception is if media change
2299 // detection is desired but device supports async notification.
2300 //
2301 // NOTE: This assumes that ClassInitializeMediaChangeDetection is always
2302 // called in the context of the ClassInitDevice callback. If called
2303 // after then this check will have already been made and the
2304 // once a second timer will not have been enabled.
2305 //
2306 if ((isFdo) &&
2307 ((initData->ClassTick != NULL) ||
2308 ((fdoExtension->MediaChangeDetectionInfo != NULL) &&
2309 (fdoExtension->FunctionSupportInfo != NULL) &&
2310 (fdoExtension->FunctionSupportInfo->AsynchronousNotificationSupported == FALSE)) ||
2311 ((fdoExtension->FailurePredictionInfo != NULL) &&
2312 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone))))
2313 {
2314 ClasspEnableTimer(fdoExtension);
2315
2316 //
2317 // In addition, we may change our polling behavior when the screen is
2318 // off so register for screen state notification if we haven't already
2319 // done so.
2320 //
2323 &GUID_CONSOLE_DISPLAY_STATE,
2325 NULL,
2327 }
2328 }
2329
2330 //
2331 // NOTE: the timer looks at commonExtension->CurrentState now
2332 // to prevent Media Change Notification code from running
2333 // until the device is started, but allows the device
2334 // specific tick handler to run. therefore it is imperative
2335 // that commonExtension->CurrentState not be updated until
2336 // the device specific startdevice handler has finished.
2337 //
2338
2340
2341 if (NT_SUCCESS(status)){
2342 commonExtension->CurrentState = IRP_MN_START_DEVICE;
2343
2344 if((isFdo) && (initData->ClassEnumerateDevice != NULL)) {
2345 isMountedDevice = FALSE;
2346 }
2347
2348 if (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM) {
2349
2350 isMountedDevice = FALSE;
2351 }
2352
2353 //
2354 // Register for mounted device interface if this is a
2355 // sfloppy device.
2356 //
2357 if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) &&
2358 (TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE))) {
2359
2360 isMountedDevice = TRUE;
2361 }
2362
2363 if(isMountedDevice) {
2365 }
2366
2367 if(commonExtension->IsFdo) {
2369
2370 //
2371 // Tell Storport (Usbstor or SD) to enable idle power management for this
2372 // device, assuming the user hasn't turned it off in the registry.
2373 //
2374 if (fdoExtension->FunctionSupportInfo != NULL &&
2375 fdoExtension->FunctionSupportInfo->IdlePower.IdlePowerEnabled == FALSE &&
2376 fdoExtension->MiniportDescriptor != NULL &&
2377 (fdoExtension->MiniportDescriptor->Portdriver == StoragePortCodeSetStorport ||
2378 fdoExtension->MiniportDescriptor->Portdriver == StoragePortCodeSetSDport ||
2379 fdoExtension->MiniportDescriptor->Portdriver == StoragePortCodeSetUSBport)) {
2380 ULONG disableIdlePower= 0;
2381 ClassGetDeviceParameter(fdoExtension,
2384 &disableIdlePower);
2385
2386 if (!disableIdlePower) {
2388 }
2389 }
2390 }
2391 }
2392 else {
2393 ClasspDisableTimer(fdoExtension);
2394 }
2395
2396
2397 return status;
2398}
2399
2400
2401/*++////////////////////////////////////////////////////////////////////////////
2402
2403ClassReadWrite()
2404
2405Routine Description:
2406
2407 This is the system entry point for read and write requests. The
2408 device-specific handler is invoked to perform any validation necessary.
2409
2410 If the device object is a PDO (partition object) then the request will
2411 simply be adjusted for Partition0 and issued to the lower device driver.
2412
2413 IF the device object is an FDO (paritition 0 object), the number of bytes
2414 in the request are checked against the maximum byte counts that the adapter
2415 supports and requests are broken up into
2416 smaller sizes if necessary.
2417
2418Arguments:
2419
2420 DeviceObject - a pointer to the device object for this request
2421
2422 Irp - IO request
2423
2424Return Value:
2425
2426 NT Status
2427
2428--*/
2430NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2432{
2433 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
2434 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
2436 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
2437 ULONG isRemoved;
2439
2440 /*
2441 * Grab the remove lock. If we can't acquire it, bail out.
2442 */
2444 if (isRemoved) {
2445 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
2446 Irp->IoStatus.Information = 0;
2450 }
2451 else if (TEST_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME) &&
2452 (currentIrpStack->MinorFunction != CLASSP_VOLUME_VERIFY_CHECKED) &&
2453 !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)){
2454
2455 /*
2456 * DO_VERIFY_VOLUME is set for the device object,
2457 * but this request is not itself a verify request.
2458 * So fail this request.
2459 */
2460 if (Irp->Tail.Overlay.Thread != NULL) {
2462 }
2463 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
2464 Irp->IoStatus.Information = 0;
2468 }
2469 else {
2470
2471 /*
2472 * Since we've bypassed the verify-required tests we don't need to repeat
2473 * them with this IRP - in particular we don't want to worry about
2474 * hitting them at the partition 0 level if the request has come through
2475 * a non-zero partition.
2476 */
2478
2479 /*
2480 * Call the miniport driver's pre-pass filter to check if we
2481 * should continue with this transfer.
2482 */
2483 NT_ASSERT(commonExtension->DevInfo->ClassReadWriteVerification);
2485 // Code Analysis cannot analyze the code paths specific to clients.
2487 if (!NT_SUCCESS(status)){
2488 NT_ASSERT(Irp->IoStatus.Status == status);
2489 Irp->IoStatus.Information = 0;
2492 }
2493 else if (status == STATUS_PENDING){
2494 /*
2495 * ClassReadWriteVerification queued this request.
2496 * So don't touch the irp anymore.
2497 */
2498 }
2499 else {
2500
2501 if (transferByteCount == 0) {
2502 /*
2503 * Several parts of the code turn 0 into 0xffffffff,
2504 * so don't process a zero-length request any further.
2505 */
2506 Irp->IoStatus.Status = STATUS_SUCCESS;
2507 Irp->IoStatus.Information = 0;
2511 }
2512 else {
2513 /*
2514 * If the driver has its own StartIo routine, call it.
2515 */
2516 if (commonExtension->DriverExtension->InitData.ClassStartIo) {
2520 }
2521 else {
2522 /*
2523 * The driver does not have its own StartIo routine.
2524 * So process this request ourselves.
2525 */
2526
2527 /*
2528 * Add partition byte offset to make starting byte relative to
2529 * beginning of disk.
2530 */
2531 currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
2532 commonExtension->StartingOffset.QuadPart;
2533
2534 if (commonExtension->IsFdo){
2535
2536 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
2537 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
2538
2539 /*
2540 * Add in any skew for the disk manager software.
2541 */
2542 currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
2543 commonExtension->PartitionZeroExtension->DMByteSkew;
2544
2545 //
2546 // In case DEV_USE_16BYTE_CDB flag is not set, R/W request will be translated into READ/WRITE 10 SCSI command.
2547 // These SCSI commands have 4 bytes in "Starting LBA" field.
2548 // Requests cannot be represented in these SCSI commands should be failed.
2549 //
2550 if (!TEST_FLAG(fdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
2551 LARGE_INTEGER startingLba;
2552
2553 startingLba.QuadPart = currentIrpStack->Parameters.Read.ByteOffset.QuadPart >> fdoExtension->SectorShift;
2554
2555 if (startingLba.QuadPart > MAXULONG) {
2556 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
2557 Irp->IoStatus.Information = 0;
2561 goto Exit;
2562 }
2563 }
2564
2565#if DBG
2566 //
2567 // Record the caller if:
2568 // 1. the disk is currently off
2569 // 2. the operation is a read, (likely resulting in disk spinnage)
2570 // 3. the operation is marked WT (likely resulting in disk spinnage)
2571 //
2572 if((fdoExtension->DevicePowerState == PowerDeviceD3) && // disk is off
2573 ((currentIrpStack->MajorFunction == IRP_MJ_READ) || // It's a read.
2574 (TEST_FLAG(currentIrpStack->Flags, SL_WRITE_THROUGH))) ) { // they *really* want it to go to disk.
2575
2577 }
2578#endif
2579
2580 /*
2581 * Perform the actual transfer(s) on the hardware
2582 * to service this request.
2583 */
2584 if (ClasspIsIdleRequestSupported(fdoData, Irp)) {
2587 } else {
2588 UCHAR uniqueAddr = 0;
2589
2590 //
2591 // Since we're touching fdoData after servicing the transfer packet, this opens us up to
2592 // a potential window, where the device may be removed between the time that
2593 // ServiceTransferPacket completes and we've had a chance to access fdoData. In order
2594 // to guard against this, we acquire the removelock an additional time here. This
2595 // acquire is guaranteed to succeed otherwise we wouldn't be here (because of the
2596 // outer acquire).
2597 // The sequence of events we're guarding against with this remLock acquire is:
2598 // 1. This UL IRP acquired the lock.
2599 // 2. Device gets surprised removed, then gets IRP_MN_REMOVE_DEVICE; ClassRemoveDevice
2600 // waits for the above RemoveLock.
2601 // 3. ServiceTransferRequest breaks the UL IRP into DL IRPs.
2602 // 4. DL IRPs complete with STATUS_NO_SUCH_DEVICE and TransferPktComplete completes the UL
2603 // IRP with STATUS_NO_SUCH_DEVICE; releases the RemoveLock.
2604 // 5. ClassRemoveDevice is now unblocked, continues running and frees resources (including
2605 // fdoData).
2606 // 6. Finally ClassReadWrite gets to run again and accesses a freed fdoData when trying to
2607 // check/update idle-related fields.
2608 //
2610
2613 if (fdoData->IdlePrioritySupported == TRUE) {
2615 }
2616
2618 }
2619 }
2620 else {
2621 /*
2622 * This is a child PDO enumerated for our FDO by e.g. disk.sys
2623 * and owned by e.g. partmgr. Send it down to the next device
2624 * and the same irp will come back to us for the FDO.
2625 */
2628 status = IoCallDriver(lowerDeviceObject, Irp);
2629 }
2630 }
2631 }
2632 }
2633 }
2634
2635Exit:
2636 return status;
2637}
2638
2639
2641{
2642 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
2643 ULONG cylinderSize;
2644 ULONG bytesPerSector;
2645 LARGE_INTEGER lastSector;
2646 LARGE_INTEGER largeInt;
2647
2648 bytesPerSector = ClasspCalculateLogicalSectorSize(Fdo, ReadCapacityData->BytesPerBlock);
2649
2650 fdoExt->DiskGeometry.BytesPerSector = bytesPerSector;
2652
2653 /*
2654 * LogicalBlockAddress is the last sector of the logical drive, in big-endian.
2655 * It tells us the size of the drive (#sectors is lastSector+1).
2656 */
2657
2658 largeInt = ReadCapacityData->LogicalBlockAddress;
2659 REVERSE_BYTES_QUAD(&lastSector, &largeInt);
2660
2661 if (fdoExt->DMActive){
2662 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClassReadDriveCapacity: reducing number of sectors by %d\n", fdoExt->DMSkew));
2663 lastSector.QuadPart -= fdoExt->DMSkew;
2664 }
2665
2666 /*
2667 * Check to see if we have a geometry we should be using already.
2668 * If not, we set part of the disk geometry to garbage values that will be filled in by the caller (e.g. disk.sys).
2669 *
2670 * So the first call to ClassReadDriveCapacity always sets a meaningless geometry.
2671 * TracksPerCylinder and SectorsPerTrack are kind of meaningless anyway wrt I/O,
2672 * because I/O is always targeted to a logical sector number.
2673 * All that really matters is BytesPerSector and the number of sectors.
2674 */
2675 cylinderSize = fdoExt->DiskGeometry.TracksPerCylinder * fdoExt->DiskGeometry.SectorsPerTrack;
2676 if (cylinderSize == 0){
2677 fdoExt->DiskGeometry.TracksPerCylinder = 0xff;
2678 fdoExt->DiskGeometry.SectorsPerTrack = 0x3f;
2679 cylinderSize = fdoExt->DiskGeometry.TracksPerCylinder * fdoExt->DiskGeometry.SectorsPerTrack;
2680 }
2681
2682 /*
2683 * Calculate number of cylinders.
2684 * If there are zero cylinders, then the device lied AND it's
2685 * smaller than 0xff*0x3f (about 16k sectors, usually 8 meg)
2686 * this can fit into a single LONGLONG, so create another usable
2687 * geometry, even if it's unusual looking.
2688 * This allows small, non-standard devices, such as Sony's Memory Stick, to show up as having a partition.
2689 */
2690 fdoExt->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector.QuadPart + 1)/cylinderSize);
2691 if (fdoExt->DiskGeometry.Cylinders.QuadPart == (LONGLONG)0) {
2692 fdoExt->DiskGeometry.SectorsPerTrack = 1;
2693 fdoExt->DiskGeometry.TracksPerCylinder = 1;
2694 fdoExt->DiskGeometry.Cylinders.QuadPart = lastSector.QuadPart + 1;
2695 }
2696
2697 /*
2698 * Calculate media capacity in bytes.
2699 * For this purpose we treat the entire LUN as is if it is one partition. Disk will deal with actual partitioning.
2700 */
2702 ((LONGLONG)(lastSector.QuadPart + 1)) << fdoExt->SectorShift;
2703
2704 /*
2705 * Is this removable or fixed media
2706 */
2707 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
2709 }
2710 else {
2712 }
2713
2714}
2715
2716/*++////////////////////////////////////////////////////////////////////////////
2717
2718ClassReadDriveCapacity()
2719
2720Routine Description:
2721
2722 This routine sends a READ CAPACITY to the requested device, updates
2723 the geometry information in the device object and returns
2724 when it is complete. This routine is synchronous.
2725
2726 This routine must be called with the remove lock held or some other
2727 assurance that the Fdo will not be removed while processing.
2728
2729Arguments:
2730
2731 DeviceObject - Supplies a pointer to the device object that represents
2732 the device whose capacity is to be read.
2733
2734Return Value:
2735
2736 Status is returned.
2737
2738--*/
2741NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2743{
2744 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
2745 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
2746 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
2747 READ_CAPACITY_DATA_EX PTRALIGN readCapacityData = {0};
2748 PTRANSFER_PACKET pkt;
2750 PMDL driveCapMdl = NULL;
2751 KEVENT event;
2752 IRP pseudoIrp = {0};
2753 ULONG readCapacityDataSize;
2754 BOOLEAN use16ByteCdb;
2755 BOOLEAN match = TRUE;
2756
2757 use16ByteCdb = TEST_FLAG(fdoExt->DeviceFlags, DEV_USE_16BYTE_CDB);
2758
2760
2761 if (use16ByteCdb) {
2762 readCapacityDataSize = sizeof(READ_CAPACITY_DATA_EX);
2763 } else {
2764 readCapacityDataSize = sizeof(READ_CAPACITY_DATA);
2765 }
2766
2767 if (driveCapMdl != NULL) {
2768 FreeDeviceInputMdl(driveCapMdl);
2769 driveCapMdl = NULL;
2770 }
2771
2772 //
2773 // Allocate the MDL based on the Read Capacity command.
2774 //
2775 driveCapMdl = BuildDeviceInputMdl(&readCapacityData, readCapacityDataSize);
2776 if (driveCapMdl == NULL) {
2778 goto SafeExit;
2779 }
2780
2782 if (pkt == NULL) {
2784 goto SafeExit;
2785 }
2786
2787 //
2788 // Our engine needs an "original irp" to write the status back to
2789 // and to count down packets (one in this case).
2790 // Just use a pretend irp for this.
2791 //
2792
2793 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
2794 pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
2795 pseudoIrp.IoStatus.Information = 0;
2796 pseudoIrp.MdlAddress = driveCapMdl;
2797
2798 //
2799 // Set this up as a SYNCHRONOUS transfer, submit it,
2800 // and wait for the packet to complete. The result
2801 // status will be written to the original irp.
2802 //
2803
2806 &readCapacityData,
2807 readCapacityDataSize,
2808 &event,
2809 &pseudoIrp,
2810 use16ByteCdb);
2813
2814 status = pseudoIrp.IoStatus.Status;
2815
2816 //
2817 // If we got an UNDERRUN, retry exactly once.
2818 // (The transfer_packet engine didn't retry because the result
2819 // status was success).
2820 //
2821
2822 if (NT_SUCCESS(status) &&
2823 (pseudoIrp.IoStatus.Information < readCapacityDataSize)) {
2824
2825 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, "ClassReadDriveCapacity: read len (%xh) < %xh, retrying ...",
2826 (ULONG)pseudoIrp.IoStatus.Information, readCapacityDataSize));
2827
2829 if (pkt) {
2830 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
2831 pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
2832 pseudoIrp.IoStatus.Information = 0;
2835 &readCapacityData,
2836 readCapacityDataSize,
2837 &event,
2838 &pseudoIrp,
2839 use16ByteCdb);
2842 status = pseudoIrp.IoStatus.Status;
2843 if (pseudoIrp.IoStatus.Information < readCapacityDataSize){
2845 }
2846 } else {
2848 }
2849 }
2850
2851 if (NT_SUCCESS(status)) {
2852 //
2853 // The request succeeded. Check for 8 byte LBA support.
2854 //
2855
2856 if (use16ByteCdb == FALSE) {
2857
2858 PREAD_CAPACITY_DATA readCapacity;
2859
2860 //
2861 // Check whether the device supports 8 byte LBA. If the device supports
2862 // it then retry the request using 16 byte CDB.
2863 //
2864
2865 readCapacity = (PREAD_CAPACITY_DATA) &readCapacityData;
2866
2867 if (readCapacity->LogicalBlockAddress == 0xFFFFFFFF) {
2868 //
2869 // Device returned max size for last LBA. Need to send
2870 // 16 byte request to get the size.
2871 //
2872 use16ByteCdb = TRUE;
2873 goto RetryRequest;
2874
2875 } else {
2876 //
2877 // Convert the 4 byte LBA (READ_CAPACITY_DATA) to 8 byte LBA (READ_CAPACITY_DATA_EX)
2878 // format for ease of use. This is the only format stored in the device extension.
2879 //
2880
2881 RtlMoveMemory((PUCHAR)(&readCapacityData) + sizeof(ULONG), readCapacity, sizeof(READ_CAPACITY_DATA));
2882 RtlZeroMemory((PUCHAR)(&readCapacityData), sizeof(ULONG));
2883
2884 }
2885 } else {
2886 //
2887 // Device completed 16 byte command successfully, it supports 8-byte LBA.
2888 //
2889
2891 }
2892
2893 //
2894 // Read out and store the drive information.
2895 //
2896
2897 InterpretCapacityData(Fdo, &readCapacityData);
2898
2899 //
2900 // Before caching the new drive capacity, compare it with the
2901 // cached capacity for any change.
2902 //
2903
2904 if (fdoData->IsCachedDriveCapDataValid == TRUE) {
2905
2907 &readCapacityData, sizeof(READ_CAPACITY_DATA_EX));
2908 }
2909
2910 //
2911 // Store the readCapacityData in private FDO data.
2912 // This is so that runtime memory failures don't cause disk.sys to put
2913 // the paging disk in an error state. Also this is used in
2914 // IOCTL_STORAGE_READ_CAPACITY.
2915 //
2916 fdoData->LastKnownDriveCapacityData = readCapacityData;
2918
2919 if (match == FALSE) {
2920 if (commonExtension->CurrentState != IRP_MN_START_DEVICE)
2921 {
2922 //
2923 // This can happen if a disk reports Parameters Changed / Capacity Data Changed sense data.
2924 // NT_ASSERT(!"Drive capacity has changed while the device wasn't started!");
2925 //
2926 } else {
2927 //
2928 // state of (commonExtension->CurrentState == IRP_MN_START_DEVICE) indicates that the device has been started.
2929 // UpdateDiskPropertiesWorkItemActive is used as a flag to ensure we only have one work item updating the disk
2930 // properties at a time.
2931 //
2932 if (InterlockedCompareExchange((volatile LONG *)&fdoData->UpdateDiskPropertiesWorkItemActive, 1, 0) == 0)
2933 {
2934 PIO_WORKITEM workItem;
2935
2936 workItem = IoAllocateWorkItem(Fdo);
2937
2938 if (workItem) {
2939 //
2940 // The disk capacity has changed, send notification to the disk driver.
2941 // Start a work item to notify the disk class driver asynchronously.
2942 //
2944 } else {
2946 }
2947 }
2948 }
2949 }
2950
2951 } else {
2952 //
2953 // The request failed.
2954 //
2955
2956 //
2957 // ISSUE - 2000/02/04 - henrygab - non-512-byte sector sizes and failed geometry update
2958 // what happens when the disk's sector size is bigger than
2959 // 512 bytes and we hit this code path? this is untested.
2960 //
2961 // If the read capacity fails, set the geometry to reasonable parameter
2962 // so things don't fail at unexpected places. Zero the geometry
2963 // except for the bytes per sector and sector shift.
2964 //
2965
2966 //
2967 // This request can sometimes fail legitimately
2968 // (e.g. when a SCSI device is attached but turned off)
2969 // so this is not necessarily a device/driver bug.
2970 //
2971
2972 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClassReadDriveCapacity on Fdo %p failed with status %ul.", Fdo, status));
2973
2974 //
2975 // Write in a default disk geometry which we HOPE is right (??).
2976 //
2977
2978 RtlZeroMemory(&fdoExt->DiskGeometry, sizeof(DISK_GEOMETRY));
2979 fdoExt->DiskGeometry.BytesPerSector = 512;
2980 fdoExt->SectorShift = 9;
2982
2983 //
2984 // Is this removable or fixed media
2985 //
2986
2987 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
2989 } else {
2991 }
2992 }
2993
2994SafeExit:
2995
2996
2997 //
2998 // In case DEV_USE_16BYTE_CDB flag is not set, classpnp translates R/W request into READ/WRITE 10 SCSI command.
2999 // These SCSI commands have 2 bytes in "Transfer Blocks" field.
3000 // Make sure this max length (0xFFFF * sector size) is respected during request split.
3001 //
3002 if (!TEST_FLAG(fdoExt->DeviceFlags, DEV_USE_16BYTE_CDB)) {
3003 ULONG cdb10MaxBlocks = ((ULONG)USHORT_MAX) << fdoExt->SectorShift;
3004
3005 fdoData->HwMaxXferLen = min(cdb10MaxBlocks, fdoData->HwMaxXferLen);
3006 }
3007
3008 if (driveCapMdl != NULL) {
3009 FreeDeviceInputMdl(driveCapMdl);
3010 }
3011
3012 //
3013 // If the request failed for some reason then invalidate the cached
3014 // capacity data for removable devices. So that we won't return
3015 // wrong capacity in IOCTL_STORAGE_READ_CAPACITY
3016 //
3017
3018 if (!NT_SUCCESS(status) && (fdoExt->DiskGeometry.MediaType == RemovableMedia)) {
3020 }
3021
3022 //
3023 // Don't let memory failures (either here or in the port driver) in the ReadDriveCapacity call
3024 // put the paging disk in an error state such that paging fails.
3025 // Return the last known drive capacity (which may possibly be slightly out of date, even on
3026 // fixed media, e.g. for storage cabinets that can grow a logical disk).
3027 //
3029 (fdoData->IsCachedDriveCapDataValid) &&
3030 (fdoExt->DiskGeometry.MediaType == FixedMedia)) {
3031 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, "ClassReadDriveCapacity: defaulting to cached DriveCapacity data"));
3034 }
3035
3036 return status;
3037}
3038
3039
3040/*++////////////////////////////////////////////////////////////////////////////
3041
3042ClassSendStartUnit()
3043
3044Routine Description:
3045
3046 Send command to SCSI unit to start or power up.
3047 Because this command is issued asynchronounsly, that is, without
3048 waiting on it to complete, the IMMEDIATE flag is not set. This
3049 means that the CDB will not return until the drive has powered up.
3050 This should keep subsequent requests from being submitted to the
3051 device before it has completely spun up.
3052
3053 This routine is called from the InterpretSense routine, when a
3054 request sense returns data indicating that a drive must be
3055 powered up.
3056
3057 This routine may also be called from a class driver's error handler,
3058 or anytime a non-critical start device should be sent to the device.
3059
3060Arguments:
3061
3062 Fdo - The functional device object for the stopped device.
3063
3064Return Value:
3065
3066 None.
3067
3068--*/
3069VOID
3070NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3073 )
3074{
3075 PIO_STACK_LOCATION irpStack;
3076 PIRP irp;
3077 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3080 PCDB cdb;
3083
3084 //
3085 // Allocate Srb from nonpaged pool.
3086 //
3087
3088 context = ExAllocatePoolWithTag(NonPagedPoolNx,
3089 sizeof(COMPLETION_CONTEXT),
3090 '6CcS');
3091
3092 if (context == NULL) {
3093
3094 //
3095 // ISSUE-2000/02/03-peterwie
3096 // This code path was inheritted from the NT 4.0 class2.sys driver.
3097 // It needs to be changed to survive low-memory conditions.
3098 //
3099
3100 KeBugCheck(SCSI_DISK_DRIVER_INTERNAL);
3101 }
3102
3103 //
3104 // Save the device object in the context for use by the completion
3105 // routine.
3106 //
3107
3108 context->DeviceObject = Fdo;
3109
3110 srb = &context->Srb.Srb;
3111 if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
3112 srbEx = &context->Srb.SrbEx;
3115 sizeof(context->Srb.SrbExBuffer),
3116 1,
3118 if (!NT_SUCCESS(status)) {
3121 return;
3122 }
3123
3124 srbEx->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
3125
3126 } else {
3127
3128 //
3129 // Zero out srb.
3130 //
3131
3132 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
3133
3134 //
3135 // Write length to SRB.
3136 //
3137
3138 srb->Length = sizeof(SCSI_REQUEST_BLOCK);
3139
3141 }
3142
3143 //
3144 // Set timeout value large enough for drive to spin up.
3145 //
3146
3148
3149 //
3150 // Set the transfer length.
3151 //
3152
3157
3158 //
3159 // Build the start unit CDB.
3160 //
3161
3162 SrbSetCdbLength(srb, 6);
3163 cdb = SrbGetCdb(srb);
3164
3165 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
3166 cdb->START_STOP.Start = 1;
3167 cdb->START_STOP.Immediate = 0;
3168 cdb->START_STOP.LogicalUnitNumber = srb->Lun;
3169
3170 //
3171 // Build the asynchronous request to be sent to the port driver.
3172 // Since this routine is called from a DPC the IRP should always be
3173 // available.
3174 //
3175
3176 irp = IoAllocateIrp(Fdo->StackSize, FALSE);
3177
3178 if (irp == NULL) {
3179
3180 //
3181 // ISSUE-2000/02/03-peterwie
3182 // This code path was inheritted from the NT 4.0 class2.sys driver.
3183 // It needs to be changed to survive low-memory conditions.
3184 //
3185
3186 KeBugCheck(SCSI_DISK_DRIVER_INTERNAL);
3187
3188 }
3189
3191
3194 context,
3195 TRUE,
3196 TRUE,
3197 TRUE);
3198
3199 irpStack = IoGetNextIrpStackLocation(irp);
3200 irpStack->MajorFunction = IRP_MJ_SCSI;
3202
3203 //
3204 // Store the SRB address in next stack for port driver.
3205 //
3206
3207 irpStack->Parameters.Scsi.Srb = srb;
3208
3209 //
3210 // Call the port driver with the IRP.
3211 //
3212
3214
3215 return;
3216
3217} // end StartUnit()
3218
3219/*++////////////////////////////////////////////////////////////////////////////
3220
3221ClassAsynchronousCompletion() ISSUE-2000/02/18-henrygab - why public?!
3222
3223Routine Description:
3224
3225 This routine is called when an asynchronous I/O request
3226 which was issused by the class driver completes. Examples of such requests
3227 are release queue or START UNIT. This routine releases the queue if
3228 necessary. It then frees the context and the IRP.
3229
3230Arguments:
3231
3232 DeviceObject - The device object for the logical unit; however since this
3233 is the top stack location the value is NULL.
3234
3235 Irp - Supplies a pointer to the Irp to be processed.
3236
3237 Context - Supplies the context to be used to process this request.
3238
3239Return Value:
3240
3241 None.
3242
3243--*/
3245NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3248 PIRP Irp,
3250 )
3251{
3254 ULONG srbFunction;
3255 ULONG srbFlags;
3256
3257 if (context == NULL) {
3259 }
3260
3261 if (DeviceObject == NULL) {
3262
3263 DeviceObject = context->DeviceObject;
3264 }
3265
3266 srb = &context->Srb.Srb;
3267
3269 srbFunction = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction;
3270 srbFlags = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFlags;
3271 } else {
3272 srbFunction = srb->Function;
3273 srbFlags = srb->SrbFlags;
3274 }
3275
3276 //
3277 // If this is an execute srb, then check the return status and make sure.
3278 // the queue is not frozen.
3279 //
3280
3281 if (srbFunction == SRB_FUNCTION_EXECUTE_SCSI) {
3282
3283 //
3284 // Check for a frozen queue.
3285 //
3286
3288
3289 //
3290 // Unfreeze the queue getting the device object from the context.
3291 //
3292
3293 ClassReleaseQueue(context->DeviceObject);
3294 }
3295 }
3296
3297 { // free port-allocated sense buffer if we can detect
3298
3299 if (((PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension))->IsFdo) {
3300
3301 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
3302 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
3303 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
3304 }
3305
3306 } else {
3307
3309
3310 }
3311 }
3312
3313
3314 //
3315 // Free the context and the Irp.
3316 //
3317
3318 if (Irp->MdlAddress != NULL) {
3319 MmUnlockPages(Irp->MdlAddress);
3320 IoFreeMdl(Irp->MdlAddress);
3321
3322 Irp->MdlAddress = NULL;
3323 }
3324
3326
3328
3329 IoFreeIrp(Irp);
3330
3331 //
3332 // Indicate the I/O system should stop processing the Irp completion.
3333 //
3334
3336
3337} // end ClassAsynchronousCompletion()
3338
3339
3343 PIRP Irp,
3344 BOOLEAN PostToDpc
3345 )
3346
3347/*++
3348
3349Routine description:
3350
3351 This routine processes Io requests, splitting them if they
3352 are larger than what the hardware can handle at a time. If
3353 there isn't enough memory available, the request is placed
3354 in a queue, to be processed at a later time
3355
3356 If this is a high priority paging request, all regular Io
3357 are throttled to provide Mm with better thoroughput
3358
3359Arguments:
3360
3361 Fdo - The functional device object processing the request
3362 Irp - The Io request to be processed
3363 PostToDpc - Flag that indicates that this IRP must be posted to a DPC
3364
3365Return Value:
3366
3367 STATUS_SUCCESS if successful, an error code otherwise
3368
3369--*/
3370
3371{
3372 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
3373 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
3374 PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExtension->PartitionZeroExtension->AdapterDescriptor;
3375 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
3377 BOOLEAN deferClientIrp = FALSE;
3378 BOOLEAN driverUsesStartIO = (commonExtension->DriverExtension->InitData.ClassStartIo != NULL);
3379 KIRQL oldIrql;
3382
3383 /*
3384 * Initialize IRP status for the master IRP to
3385 * - STATUS_FT_READ_FROM_COPY if it's a copy-specific read
3386 * - STATUS_SUCCESS otherwise.
3387 *
3388 * This is required. When Classpnp determines the status for the master IRP
3389 * when completing child IRPs, the call to IoSetMasterIrpStatus
3390 * will be functioning properly (See TransferPktComplete function)
3391 *
3392 * Note:
3393 * If the IRP is a copy-specific read, File System already initialized the IRP status
3394 * to be STATUS_FT_READ_FROM_COPY. However, this can be changed when the IRP arrives
3395 * at Classpnp. It's possible that other drivers in the stack may initialize the
3396 * IRP status field to other values before forwarding the IRP down the stack.
3397 * To be defensive, we initialize the IRP status to either STATUS_FT_READ_FROM_COPY
3398 * if it's a copy-specific read, or STATUS_SUCCESS otherwise.
3399 */
3400 if (currentIrpStack->MajorFunction == IRP_MJ_READ &&
3401 TEST_FLAG(currentIrpStack->Flags, SL_KEY_SPECIFIED) &&
3402 IsKeyReadCopyNumber(currentIrpStack->Parameters.Read.Key)) {
3403 Irp->IoStatus.Status = STATUS_FT_READ_FROM_COPY;
3404 } else {
3405 Irp->IoStatus.Status = STATUS_SUCCESS;
3406 }
3407
3408 //
3409 // If this is a high priority request, hold off all other Io requests
3410 //
3411
3413 {
3414 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
3415
3416 if (fdoData->NumHighPriorityPagingIo == 0)
3417 {
3418 //
3419 // Entering throttle mode
3420 //
3421
3423 }
3424
3425 fdoData->NumHighPriorityPagingIo++;
3427
3428 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
3429 }
3430 else
3431 {
3432 if (fdoData->NumHighPriorityPagingIo != 0)
3433 {
3434 //
3435 // This request wasn't flagged as critical and atleast one critical request
3436 // is currently outstanding. Queue this request until all of those are done
3437 // but only if the interleave threshold has been reached
3438 //
3439
3440 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
3441
3442 if (fdoData->NumHighPriorityPagingIo != 0)
3443 {
3444 if (fdoData->MaxInterleavedNormalIo == 0)
3445 {
3446 deferClientIrp = TRUE;
3447 }
3448 else
3449 {
3450 fdoData->MaxInterleavedNormalIo--;
3451 }
3452 }
3453
3454 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
3455 }
3456 }
3457
3458 if (!deferClientIrp)
3459 {
3461 ULONG entireXferLen = currentSp->Parameters.Read.Length;
3462 PUCHAR bufPtr = MmGetMdlVirtualAddress(Irp->MdlAddress);
3463 LARGE_INTEGER targetLocation = currentSp->Parameters.Read.ByteOffset;
3464 PTRANSFER_PACKET pkt;
3465 SINGLE_LIST_ENTRY pktList;
3466 PSINGLE_LIST_ENTRY slistEntry;
3467 ULONG hwMaxXferLen;
3468 ULONG numPackets;
3469 ULONG i;
3470
3471
3472 /*
3473 * We precomputed fdoData->HwMaxXferLen using (MaximumPhysicalPages-1).
3474 * If the buffer is page-aligned, that's one less page crossing so we can add the page back in.
3475 * Note: adapters that return MaximumPhysicalPages=0x10 depend on this to
3476 * transfer aligned 64K requests in one piece.
3477 * Also note: make sure adding PAGE_SIZE back in doesn't wrap to zero.
3478 */
3479 if (((ULONG_PTR)bufPtr & (PAGE_SIZE-1)) || (fdoData->HwMaxXferLen > 0xffffffff-PAGE_SIZE)){
3480 hwMaxXferLen = fdoData->HwMaxXferLen;
3481 }
3482 else {
3484 hwMaxXferLen = min(fdoData->HwMaxXferLen+PAGE_SIZE, adapterDesc->MaximumTransferLength);
3485 }
3486
3487 /*
3488 * Compute the number of hw xfers we'll have to do.
3489 * Calculate this without allowing for an overflow condition.
3490 */
3491 NT_ASSERT(hwMaxXferLen >= PAGE_SIZE);
3492 numPackets = entireXferLen/hwMaxXferLen;
3493 if (entireXferLen % hwMaxXferLen){
3494 numPackets++;
3495 }
3496
3497 /*
3498 * Use our 'simple' slist functions since we don't need interlocked.
3499 */
3500 SimpleInitSlistHdr(&pktList);
3501
3502 if (driverUsesStartIO) {
3503 /*
3504 * special case: StartIO-based writing must stay serialized, so just
3505 * re-use one packet.
3506 */
3508 if (pkt) {
3510 i = 1;
3511 } else {
3512 i = 0;
3513 }
3514 } else {
3515 /*
3516 * First get all the TRANSFER_PACKETs that we'll need at once.
3517 */
3518 for (i = 0; i < numPackets; i++){
3520 if (pkt){
3522 }
3523 else {
3524 break;
3525 }
3526 }
3527 }
3528
3529
3530 if ((i == numPackets) &&
3531 (!driverUsesStartIO)) {
3532 NTSTATUS pktStat;
3533
3534 /*
3535 * The IoStatus.Information field will be incremented to the
3536 * transfer length as the pieces complete.
3537 */
3538 Irp->IoStatus.Information = 0;
3539
3540 /*
3541 * Store the number of transfer pieces inside the original IRP.
3542 * It will be used to count down the pieces as they complete.
3543 */
3544 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(numPackets);
3545
3546 /*
3547 * For the common 1-packet case, we want to allow for an optimization by BlkCache
3548 * (and also potentially synchronous storage drivers) which may complete the
3549 * downward request synchronously.
3550 * In that synchronous completion case, we want to _not_ mark the original irp pending
3551 * and thereby save on the top-level APC.
3552 * It's critical to coordinate this with the completion routine so that we mark the original irp
3553 * pending if-and-only-if we return STATUS_PENDING for it.
3554 */
3555 if (numPackets > 1){
3558 }
3559 else {
3561 }
3562
3563 /*
3564 * Transmit the pieces of the transfer.
3565 */
3566 while (entireXferLen > 0){
3567 ULONG thisPieceLen = MIN(hwMaxXferLen, entireXferLen);
3568
3569 /*
3570 * Set up a TRANSFER_PACKET for this piece and send it.
3571 */
3572 slistEntry = SimplePopSlist(&pktList);
3573 NT_ASSERT(slistEntry);
3574 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
3576 bufPtr,
3577 thisPieceLen,
3578 targetLocation,
3579 Irp);
3580
3581 //
3582 // If the IRP needs to be split, then we need to use a partial MDL.
3583 // This prevents problems if the same MDL is mapped multiple times.
3584 //
3585 if (numPackets > 1) {
3586 pkt->UsePartialMdl = TRUE;
3587 }
3588
3589 /*
3590 * When an IRP is completed, the completion routine checks to see if there
3591 * is a deferred IRP ready to sent down (assuming that there are no non-idle
3592 * requests waiting to be serviced). If such a deferred IRP is available, it
3593 * is sent down using this routine. However, if the lower driver completes
3594 * the request inline, there is a potential for multiple deferred IRPs being
3595 * sent down in the context of the same completion thread, thus exhausting
3596 * the call stack.
3597 * In order to prevent this from happening, we need to ensure that deferred
3598 * IRPs that are dequeued in the context of a request's completion routine
3599 * get posted to a DPC.
3600 */
3601 if (PostToDpc) {
3602
3603 pkt->RetryIn100nsUnits = 0;
3606
3607 } else {
3608
3609 pktStat = SubmitTransferPacket(pkt);
3610
3611 /*
3612 * If any of the packets completes with pending, we MUST return pending.
3613 * Also, if a packet completes with an error, return pending; this is because
3614 * in the completion routine we mark the original irp pending if the packet failed
3615 * (since we may retry, thereby switching threads).
3616 */
3617 if (pktStat != STATUS_SUCCESS){
3619 }
3620 }
3621
3622 entireXferLen -= thisPieceLen;
3623 bufPtr += thisPieceLen;
3624 targetLocation.QuadPart += thisPieceLen;
3625 }
3626 NT_ASSERT(SimpleIsSlistEmpty(&pktList));
3627 }
3628 else if (i >= 1){
3629 /*
3630 * We were unable to get all the TRANSFER_PACKETs we need,
3631 * but we did get at least one.
3632 * That means that we are in extreme low-memory stress.
3633 * We'll try doing this transfer using a single packet.
3634 * The port driver is certainly also in stress, so use one-page
3635 * transfers.
3636 */
3637
3638 /*
3639 * Free all but one of the TRANSFER_PACKETs.
3640 */
3641 while (i-- > 1){
3642 slistEntry = SimplePopSlist(&pktList);
3643 NT_ASSERT(slistEntry);
3644 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
3646 }
3647
3648 /*
3649 * Get the single TRANSFER_PACKET that we'll be using.
3650 */
3651 slistEntry = SimplePopSlist(&pktList);
3652 NT_ASSERT(slistEntry);
3653 NT_ASSERT(SimpleIsSlistEmpty(&pktList));
3654 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
3655
3656 if (!driverUsesStartIO) {
3657 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Insufficient packets available in ServiceTransferRequest - entering lowMemRetry with pkt=%p.", pkt));
3658 }
3659
3660 /*
3661 * Set the number of transfer packets (one)
3662 * inside the original irp.
3663 */
3664 Irp->IoStatus.Information = 0;
3665 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1);
3667
3668 /*
3669 * Set up the TRANSFER_PACKET for a lowMem transfer and launch.
3670 */
3672 bufPtr,
3673 entireXferLen,
3674 targetLocation,
3675 Irp);
3676
3677 InitLowMemRetry(pkt, bufPtr, entireXferLen, targetLocation);
3678 StepLowMemRetry(pkt);
3680 }
3681 else {
3682 /*
3683 * We were unable to get ANY TRANSFER_PACKETs.
3684 * Defer this client irp until some TRANSFER_PACKETs free up.
3685 */
3686 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "No packets available in ServiceTransferRequest - deferring transfer (Irp=%p)...", Irp));
3687
3689 {
3690 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
3691
3693 {
3694 fdoData->MaxInterleavedNormalIo = 0;
3695 }
3696 else
3697 {
3699 }
3700
3701 fdoData->NumHighPriorityPagingIo--;
3702
3703 if (fdoData->NumHighPriorityPagingIo == 0)
3704 {
3705 LARGE_INTEGER period;
3706
3707 //
3708 // Exiting throttle mode
3709 //
3710
3712
3713 period.QuadPart = fdoData->ThrottleStopTime.QuadPart - fdoData->ThrottleStartTime.QuadPart;
3715 }
3716
3717 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
3718 }
3719
3720 deferClientIrp = TRUE;
3721 }
3722 }
3723 _Analysis_assume_(deferClientIrp);
3724 if (deferClientIrp)
3725 {
3729 }
3730
3732
3733 return status;
3734}
3735
3736
3737/*++////////////////////////////////////////////////////////////////////////////
3738
3739ClassIoComplete()
3740
3741Routine Description:
3742
3743 This routine executes when the port driver has completed a request.
3744 It looks at the SRB status in the completing SRB and if not success
3745 it checks for valid request sense buffer information. If valid, the
3746 info is used to update status with more precise message of type of
3747 error. This routine deallocates the SRB.
3748
3749 This routine should only be placed on the stack location for a class
3750 driver FDO.
3751
3752Arguments:
3753
3754 Fdo - Supplies the device object which represents the logical
3755 unit.
3756
3757 Irp - Supplies the Irp which has completed.
3758
3759 Context - Supplies a pointer to the SRB.
3760
3761Return Value:
3762
3763 NT status
3764
3765--*/
3767NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3770 IN PIRP Irp,
3772 )
3773{
3776 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3777 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
3779 BOOLEAN retry;
3780 BOOLEAN callStartNextPacket;
3781 ULONG srbFlags;
3782 ULONG srbFunction;
3783
3784 NT_ASSERT(fdoExtension->CommonExtension.IsFdo);
3785
3787 srbFlags = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFlags;
3788 srbFunction = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction;
3789 } else {
3790 srbFlags = srb->SrbFlags;
3791 srbFunction = srb->Function;
3792 }
3793
3794 #if DBG
3795 if (srbFunction == SRB_FUNCTION_FLUSH) {
3796 DBGLOGFLUSHINFO(fdoData, FALSE, FALSE, TRUE);
3797 }
3798 #endif
3799
3800 //
3801 // Check SRB status for success of completing request.
3802 //
3803
3805 LONGLONG retryInterval;
3806
3807 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoComplete: IRP %p, SRB %p\n", Irp, srb));
3808
3809 //
3810 // Release the queue if it is frozen.
3811 //
3812
3815 }
3817 Fdo,
3818 Irp,
3819 srb,
3820 irpStack->MajorFunction,
3821 ((irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ?
3822 irpStack->Parameters.DeviceIoControl.IoControlCode :
3823 0),
3825 ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
3826 &status,
3827 &retryInterval);
3828
3829 //
3830 // For Persistent Reserve requests, make sure user gets back partial data.
3831 //
3832
3833 if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
3837
3839 retry = FALSE;
3840 }
3841
3842 //
3843 // If the status is verified required and the this request
3844 // should bypass verify required then retry the request.
3845 //
3846
3847 if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
3849
3851 retry = TRUE;
3852 }
3853
3854#ifndef __REACTOS__
3855#pragma warning(suppress:4213) // okay to cast Arg4 as a ulong for this use case
3856 if (retry && ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4)--) {
3857#else
3858 if (retry && (*(ULONG *)&irpStack->Parameters.Others.Argument4)--) {
3859#endif
3860
3861
3862 //
3863 // Retry request.
3864 //
3865
3866 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "Retry request %p\n", Irp));
3867
3868 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
3869 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
3870 }
3871
3872 RetryRequest(Fdo, Irp, srb, FALSE, retryInterval);
3874 }
3875
3876 } else {
3877
3878 //
3879 // Set status for successful request
3880 //
3882 ClasspPerfIncrementSuccessfulIo(fdoExtension);
3884 } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)
3885
3886
3887 //
3888 // ensure we have returned some info, and it matches what the
3889 // original request wanted for PAGING operations only
3890 //
3891
3892 if ((NT_SUCCESS(status)) && TEST_FLAG(Irp->Flags, IRP_PAGING_IO)) {
3893 NT_ASSERT(Irp->IoStatus.Information != 0);
3894 NT_ASSERT(irpStack->Parameters.Read.Length == Irp->IoStatus.Information);
3895 }
3896
3897 //
3898 // remember if the caller wanted to skip calling IoStartNextPacket.
3899 // for legacy reasons, we cannot call IoStartNextPacket for IoDeviceControl
3900 // calls. this setting only affects device objects with StartIo routines.
3901 //
3902
3903 callStartNextPacket = !TEST_FLAG(srbFlags, SRB_FLAGS_DONT_START_NEXT_PACKET);
3904 if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
3905 callStartNextPacket = FALSE;
3906 }
3907
3908 //
3909 // Free MDL if allocated.
3910 //
3911
3912 if (TEST_FLAG(srbFlags, SRB_CLASS_FLAGS_FREE_MDL)) {
3914 IoFreeMdl(Irp->MdlAddress);
3915 Irp->MdlAddress = NULL;
3916 }
3917
3918
3919 //
3920 // Free the srb
3921 //
3922
3923 if (!TEST_FLAG(srbFlags, SRB_CLASS_FLAGS_PERSISTANT)) {
3924
3925 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
3926 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
3927 }
3928
3930 ClassFreeOrReuseSrb(fdoExtension, srb);
3931 }
3932 else {
3933 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoComplete is freeing an SRB (possibly) on behalf of another driver."));
3934 FREE_POOL(srb);
3935 }
3936
3937 } else {
3938
3939 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoComplete: Not Freeing srb @ %p because "
3940 "SRB_CLASS_FLAGS_PERSISTANT set\n", srb));
3941 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
3942 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassIoComplete: Not Freeing sensebuffer @ %p "
3943 " because SRB_CLASS_FLAGS_PERSISTANT set\n",
3944 srb->SenseInfoBuffer));
3945 }
3946
3947 }
3948
3949 //
3950 // Set status in completing IRP.
3951 //
3952
3953 Irp->IoStatus.Status = status;
3954
3955 //
3956 // Set the hard error if necessary.
3957 //
3958
3959 if (!NT_SUCCESS(status) &&
3961 (Irp->Tail.Overlay.Thread != NULL)
3962 ) {
3963
3964 //
3965 // Store DeviceObject for filesystem, and clear
3966 // in IoStatus.Information field.
3967 //
3968
3970 Irp->IoStatus.Information = 0;
3971 }
3972
3973 //
3974 // If disk firmware update succeeded, log a system event.
3975 //
3976
3977 if (NT_SUCCESS(status) &&
3978 (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) &&
3979 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_FIRMWARE_ACTIVATE)) {
3980
3982 }
3983
3984 //
3985 // If pending has be returned for this irp then mark the current stack as
3986 // pending.
3987 //
3988
3989 if (Irp->PendingReturned) {
3991 }
3992
3994 if (callStartNextPacket) {
3995 KIRQL oldIrql;
3996 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
3997 IoStartNextPacket(Fdo, TRUE); // Yes, some IO must now be cancellable.
3998 KeLowerIrql(oldIrql);
3999 }
4000 }
4001
4003
4004 return status;
4005
4006} // end ClassIoComplete()
4007
4008
4009/*++////////////////////////////////////////////////////////////////////////////
4010
4011ClassSendSrbSynchronous()
4012
4013Routine Description:
4014
4015 This routine is called by SCSI device controls to complete an
4016 SRB and send it to the port driver synchronously (ie wait for
4017 completion). The CDB is already completed along with the SRB CDB
4018 size and request timeout value.
4019
4020Arguments:
4021
4022 Fdo - Supplies the functional device object which represents the target.
4023
4024 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
4025
4026 BufferAddress - Supplies the address of the buffer.
4027
4028 BufferLength - Supplies the length in bytes of the buffer.
4029
4030 WriteToDevice - Indicates the data should be transfer to the device.
4031
4032Return Value:
4033
4034 NTSTATUS indicating the final results of the operation.
4035
4036 If NT_SUCCESS(), then the amount of usable data is contained in the field
4037 Srb->DataTransferLength
4038
4039--*/
4041NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
4048 )
4049{
4050
4051 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
4052 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
4053 IO_STATUS_BLOCK ioStatus = {0};
4054 PIRP irp;
4055 PIO_STACK_LOCATION irpStack;
4056 KEVENT event;
4058 ULONG senseInfoBufferLength = SENSE_BUFFER_SIZE_EX;
4059 ULONG retryCount = MAXIMUM_RETRIES;
4061 BOOLEAN retry;
4063
4064 //
4065 // NOTE: This code is only pagable because we are not freezing
4066 // the queue. Allowing the queue to be frozen from a pagable
4067 // routine could leave the queue frozen as we try to page in
4068 // the code to unfreeze the queue. The result would be a nice
4069 // case of deadlock. Therefore, since we are unfreezing the
4070 // queue regardless of the result, just set the NO_FREEZE_QUEUE
4071 // flag in the SRB.
4072 //
4073
4075 NT_ASSERT(fdoExtension->CommonExtension.IsFdo);
4076
4078 //
4079 // Write length to SRB.
4080 //
4081
4082 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
4083
4084 //
4085 // Set SCSI bus address.
4086 //
4087
4089 }
4090
4091 //
4092 // The Srb->Function should have been set corresponding to SrbType.
4093 //
4094
4097
4098
4099 //
4100 // Sense buffer is in aligned nonpaged pool.
4101 //
4102
4103#if defined(_ARM_) || defined(_ARM64_)
4104
4105 //
4106 // ARM has specific alignment requirements, although this will not have a functional impact on x86 or amd64
4107 // based platforms. We are taking the conservative approach here.
4108 //
4109 senseInfoBufferLength = ALIGN_UP_BY(senseInfoBufferLength,KeGetRecommendedSharedDataAlignment());
4110
4111#endif
4112
4113 senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
4114 senseInfoBufferLength,
4115 '7CcS');
4116
4117 if (senseInfoBuffer == NULL) {
4118
4119 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendSrbSynchronous: Can't allocate request sense "
4120 "buffer\n"));
4122 }
4123
4124
4125 //
4126 // Enable auto request sense.
4127 //
4130
4132
4133
4134 //
4135 // Start retries here.
4136 //
4137
4138retry:
4139
4140 //
4141 // use fdoextension's flags by default.
4142 // do not move out of loop, as the flag may change due to errors
4143 // sending this command.
4144 //
4145
4146 SrbAssignSrbFlags(Srb, fdoExtension->SrbFlags);
4147
4148 if (BufferAddress != NULL) {
4149 if (WriteToDevice) {
4151 } else {
4153 }
4154 }
4155
4156
4157 //
4158 // Initialize the QueueAction field.
4159 //
4160
4162
4163 //
4164 // Disable synchronous transfer for these requests.
4165 //
4167
4168 //
4169 // Set the event object to the unsignaled state.
4170 // It will be used to signal request completion.
4171 //
4172
4174
4175 //
4176 // Build device I/O control request with METHOD_NEITHER data transfer.
4177 // We'll queue a completion routine to cleanup the MDL's and such ourself.
4178 //
4179
4181 (CCHAR) (fdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1),
4182 FALSE);
4183
4184 if (irp == NULL) {
4188 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendSrbSynchronous: Can't allocate Irp\n"));
4190 }
4191
4192 //
4193 // Get next stack location.
4194 //
4195
4196 irpStack = IoGetNextIrpStackLocation(irp);
4197
4198 //
4199 // Set up SRB for execute scsi request. Save SRB address in next stack
4200 // for the port driver.
4201 //
4202
4203 irpStack->MajorFunction = IRP_MJ_SCSI;
4204 irpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)Srb;
4205
4208 Srb,
4209 TRUE,
4210 TRUE,
4211 TRUE);
4212
4213 irp->UserIosb = &ioStatus;
4214 irp->UserEvent = &event;
4215
4216 if (BufferAddress) {
4217 //
4218 // Build an MDL for the data buffer and stick it into the irp. The
4219 // completion routine will unlock the pages and free the MDL.
4220 //
4221
4222 irp->MdlAddress = IoAllocateMdl( BufferAddress,
4224 FALSE,
4225 FALSE,
4226 irp );
4227 if (irp->MdlAddress == NULL) {
4231 IoFreeIrp( irp );
4232 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendSrbSynchronous: Can't allocate MDL\n"));
4234 }
4235
4236 _SEH2_TRY {
4237
4238 //
4239 // the io manager unlocks these pages upon completion
4240 //
4241
4242 MmProbeAndLockPages( irp->MdlAddress,
4243 KernelMode,
4245 IoWriteAccess));
4246
4247#ifdef _MSC_VER
4248 #pragma warning(suppress: 6320) // We want to handle any exception that MmProbeAndLockPages might throw
4249#endif
4252
4256 IoFreeMdl(irp->MdlAddress);
4257 IoFreeIrp(irp);
4258
4259 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendSrbSynchronous: Exception %lx "
4260 "locking buffer\n", status));
4261 _SEH2_YIELD(return status);
4262 } _SEH2_END;
4263 }
4264
4265 //
4266 // Set the transfer length.
4267 //
4268
4270
4271 //
4272 // Zero out status.
4273 //
4274
4276 Srb->SrbStatus = 0;
4278
4279 //
4280 // Set up IRP Address.
4281 //
4282
4284
4285 //
4286 // Call the port driver with the request and wait for it to complete.
4287 //
4288
4290
4291 if (status == STATUS_PENDING) {
4293 status = ioStatus.Status;
4294 }
4295
4296// NT_ASSERT(SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_PENDING);
4299
4300 //
4301 // Clear the IRP address in SRB as IRP has been freed at this time
4302 // and don't want to leave any references that may be accessed.
4303 //
4304
4306
4307 //
4308 // Check that request completed without error.
4309 //
4310
4312
4313 LONGLONG retryInterval;
4314
4315 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassSendSrbSynchronous - srb %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s)", Srb,
4321
4322 //
4323 // assert that the queue is not frozen
4324 //
4325
4327
4328 //
4329 // Update status and determine if request should be retried.
4330 //
4331
4333 NULL, // no valid irp exists
4336 0,
4337 MAXIMUM_RETRIES - retryCount,
4338 &status,
4339 &retryInterval);
4340
4341 if (retry) {
4342
4345
4347
4348 validSense = ScsiGetSenseKeyAndCodes(senseInfoBuffer,
4351 NULL,
4353 NULL);
4354 }
4355
4358
4359 LARGE_INTEGER delay;
4360
4361 //
4362 // Delay for at least 2 seconds.
4363 //
4364
4365 if (retryInterval < 2*1000*1000*10) {
4366 retryInterval = 2*1000*1000*10;
4367 }
4368
4369 delay.QuadPart = -retryInterval;
4370
4371 //
4372 // Stall for a while to let the device become ready
4373 //
4374
4376
4377 }
4378
4379
4380 //
4381 // If retries are not exhausted then retry this operation.
4382 //
4383
4384 if (retryCount--) {
4385
4386 if (PORT_ALLOCATED_SENSE_EX(fdoExtension, Srb)) {
4388 }
4389
4390 goto retry;
4391 }
4392 }
4393
4394
4395 } else {
4398 }
4399
4400 //
4401 // required even though we allocated our own, since the port driver may
4402 // have allocated one also
4403 //
4404
4405 if (PORT_ALLOCATED_SENSE_EX(fdoExtension, Srb)) {
4407 }
4408
4412
4413 return status;
4414}
4415
4416
4417/*++////////////////////////////////////////////////////////////////////////////
4418
4419ClassInterpretSenseInfo()
4420
4421Routine Description:
4422
4423 This routine interprets the data returned from the SCSI
4424 request sense. It determines the status to return in the
4425 IRP and whether this request can be retried.
4426
4427Arguments:
4428
4429 Fdo - Supplies the device object associated with this request.
4430
4431 Srb - Supplies the scsi request block which failed.
4432
4433 MajorFunctionCode - Supplies the function code to be used for logging.
4434
4435 IoDeviceCode - Supplies the device code to be used for logging.
4436
4437 RetryCount - Number of times that the request has been retried.
4438
4439 Status - Returns the status for the request.
4440
4441 RetryInterval - Number of seconds before the request should be retried.
4442 Zero indicates the request should be immediately retried.
4443
4444Return Value:
4445
4446 BOOLEAN TRUE: Drivers should retry this request.
4447 FALSE: Drivers should not retry this request.
4448
4449--*/
4450BOOLEAN
4451NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
4457 _In_ ULONG RetryCount,
4459 _Out_opt_ _Deref_out_range_(0,100) ULONG *RetryInterval
4460 )
4461{
4462 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
4463 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
4465 PVOID senseBuffer = SrbGetSenseInfoBuffer(Srb);
4466 BOOLEAN retry = TRUE;
4467 BOOLEAN logError = FALSE;
4468 BOOLEAN unhandledError = FALSE;
4469 BOOLEAN incrementErrorCount = FALSE;
4470
4471 //
4472 // NOTE: This flag must be used only for read/write requests that
4473 // fail with a unexpected retryable error.
4474 //
4475 BOOLEAN logRetryableError = TRUE;
4476
4477 //
4478 // Indicates if we should log this error in our internal log.
4479 //
4480 BOOLEAN logErrorInternal = TRUE;
4481
4482 ULONGLONG badSector = 0;
4483 ULONG uniqueId = 0;
4484
4485 NTSTATUS logStatus;
4486
4487 ULONGLONG readSector;
4488 ULONG index;
4489
4490 ULONG retryInterval = 0;
4491 KIRQL oldIrql;
4492 PCDB cdb = SrbGetCdb(Srb);
4493 UCHAR cdbOpcode = 0;
4494 ULONG cdbLength = SrbGetCdbLength(Srb);
4495
4496#if DBG
4497 BOOLEAN isReservationConflict = FALSE;
4498#endif
4499
4500 if (cdb) {
4501 cdbOpcode = cdb->CDB6GENERIC.OperationCode;
4502 }
4503
4505 logStatus = -1;
4506
4508
4509 //
4510 // Log anything remotely incorrect about paging i/o
4511 //
4512
4513 logError = TRUE;
4514 uniqueId = 301;
4515 logStatus = IO_WARNING_PAGING_FAILURE;
4516 }
4517
4518 //
4519 // Check that request sense buffer is valid.
4520 //
4521
4522 NT_ASSERT(fdoExtension->CommonExtension.IsFdo);
4523
4524
4525 //
4526 // must handle the SRB_STATUS_INTERNAL_ERROR case first,
4527 // as it has all the flags set.
4528 //
4529
4531
4532 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
4533 "ClassInterpretSenseInfo: Internal Error code is %x\n",
4535
4536 retry = FALSE;
4538
4540
4541 //
4542 // Need to reserve STATUS_DEVICE_BUSY to convey reservation conflict
4543 // for read/write requests as there are upper level components that
4544 // have built-in assumptions that STATUS_DEVICE_BUSY implies reservation
4545 // conflict.
4546 //
4548 retry = FALSE;
4549 logError = FALSE;
4550#if DBG
4551 isReservationConflict = TRUE;
4552#endif
4553
4554 } else {
4555
4557
4558 if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && senseBuffer) {
4559
4560 UCHAR errorCode = 0;
4561 UCHAR senseKey = 0;
4562 UCHAR addlSenseCode = 0;
4563 UCHAR addlSenseCodeQual = 0;
4564 BOOLEAN isIncorrectLengthValid = FALSE;
4565 BOOLEAN incorrectLength = FALSE;
4566 BOOLEAN isInformationValid = FALSE;
4568
4569
4570 validSense = ScsiGetSenseKeyAndCodes(senseBuffer,
4573 &senseKey,
4574 &addlSenseCode,
4575 &addlSenseCodeQual);
4576
4577 if (!validSense && !IsSenseDataFormatValueValid(senseBuffer)) {
4578
4580
4581 validSense = ScsiGetFixedSenseKeyAndCodes(senseBuffer,
4583 &senseKey,
4584 &addlSenseCode,
4585 &addlSenseCodeQual);
4586 }
4587
4588 if (!validSense) {
4589 goto __ClassInterpretSenseInfo_ProcessingInvalidSenseBuffer;
4590 }
4591
4592 errorCode = ScsiGetSenseErrorCode(senseBuffer);
4593
4594 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: Error code is %x\n", errorCode));
4595 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: Sense key is %x\n", senseKey));
4596 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: Additional sense code is %x\n", addlSenseCode));
4597 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: Additional sense code qualifier is %x\n", addlSenseCodeQual));
4598
4599 if (IsDescriptorSenseDataFormat(senseBuffer)) {
4600
4601 //
4602 // Sense data in Descriptor format
4603 //
4604
4605 PVOID startBuffer = NULL;
4606 UCHAR startBufferLength = 0;
4607
4608
4609 if (ScsiGetSenseDescriptor(senseBuffer,
4611 &startBuffer,
4612 &startBufferLength)) {
4613 UCHAR outType;
4615 UCHAR outBufferLength = 0;
4616 BOOLEAN foundBlockCommandType = FALSE;
4617 BOOLEAN foundInformationType = FALSE;
4619
4622
4623 while ((!foundBlockCommandType || !foundInformationType) &&
4624 ScsiGetNextSenseDescriptorByType(startBuffer,
4625 startBufferLength,
4626 typeList,
4627 ARRAYSIZE(typeList),
4628 &outType,
4629 &outBuffer,
4630 &outBufferLength)) {
4631
4633
4634 if (outBufferLength < descriptorLength) {
4635
4636 // Descriptor data is truncated.
4637 // Complete searching descriptors. Exit the loop now.
4638 break;
4639 }
4640
4642
4643 //
4644 // Block Command type
4645 //
4646
4647 if (!foundBlockCommandType) {
4648
4649 foundBlockCommandType = TRUE;
4650
4651 if (ScsiValidateBlockCommandSenseDescriptor(outBuffer, outBufferLength)) {
4652 incorrectLength = ((PSCSI_SENSE_DESCRIPTOR_BLOCK_COMMAND)outBuffer)->IncorrectLength;
4653 isIncorrectLengthValid = TRUE;
4654 }
4655 } else {
4656
4657 //
4658 // A Block Command descriptor is already found earlier.
4659 //
4660 // T10 SPC specification only allows one descriptor for Block Command Descriptor type.
4661 // Assert here to catch devices that violate this rule. Ignore this descriptor.
4662 //
4664 }
4665
4666 } else if (outType == SCSI_SENSE_DESCRIPTOR_TYPE_INFORMATION) {
4667
4668 //
4669 // Information type
4670 //
4671
4672 if (!foundInformationType) {
4673
4674 foundInformationType = TRUE;
4675
4676 if (ScsiValidateInformationSenseDescriptor(outBuffer, outBufferLength)) {
4678 isInformationValid = TRUE;
4679 }
4680 } else {
4681
4682 //
4683 // A Information descriptor is already found earlier.
4684 //
4685 // T10 SPC specification only allows one descriptor for Information Descriptor type.
4686 // Assert here to catch devices that violate this rule. Ignore this descriptor.
4687 //
4689 }
4690
4691 } else {
4692
4693 //
4694 // ScsiGetNextDescriptorByType should only return a type that is specified by us.
4695 //
4697 break;
4698 }
4699
4700 //
4701 // Advance to start address of next descriptor
4702 //
4703 startBuffer = (PUCHAR)outBuffer + descriptorLength;
4704 startBufferLength = outBufferLength - descriptorLength;
4705 }
4706 }
4707 } else {
4708
4709 //
4710 // Sense data in Fixed format
4711 //
4712
4713 incorrectLength = ((PFIXED_SENSE_DATA)(senseBuffer))->IncorrectLength;
4715 isInformationValid = TRUE;
4716 isIncorrectLengthValid = TRUE;
4717 }
4718
4719
4720 switch (senseKey) {
4721
4722 case SCSI_SENSE_NO_SENSE: {
4723
4724 //
4725 // Check other indicators.
4726 //
4727
4728 if (isIncorrectLengthValid && incorrectLength) {
4729
4730 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4731 "Incorrect length detected.\n"));
4733 retry = FALSE;
4734
4735 } else {
4736
4737 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4738 "No specific sense key\n"));
4740 retry = TRUE;
4741 }
4742
4743 break;
4744 } // end SCSI_SENSE_NO_SENSE
4745
4747
4748 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4749 "Recovered error\n"));
4751 retry = FALSE;
4752 logError = TRUE;
4753 uniqueId = 258;
4754
4755 switch(addlSenseCode) {
4758 logStatus = IO_ERR_SEEK_ERROR;
4759 break;
4760 }
4761
4764 logStatus = IO_RECOVERED_VIA_ECC;
4765 break;
4766 }
4767
4769
4770 UCHAR wmiEventData[sizeof(ULONG)+sizeof(UCHAR)] = {0};
4771
4772 *((PULONG)wmiEventData) = sizeof(UCHAR);
4773 wmiEventData[sizeof(ULONG)] = addlSenseCodeQual;
4774
4775 //
4776 // Don't log another eventlog if we have already logged once
4777 // NOTE: this should have been interlocked, but the structure
4778 // was publicly defined to use a BOOLEAN (char). Since
4779 // media only reports these errors once per X minutes,
4780 // the potential race condition is nearly non-existant.
4781 // the worst case is duplicate log entries, so ignore.
4782 //
4783
4784 logError = FALSE;
4785 if (fdoExtension->FailurePredicted == 0) {
4786 logError = TRUE;
4787 }
4788 fdoExtension->FailureReason = addlSenseCodeQual;
4789 logStatus = IO_WRN_FAILURE_PREDICTED;
4790
4791 ClassNotifyFailurePredicted(fdoExtension,
4792 (PUCHAR)wmiEventData,
4793 sizeof(wmiEventData),
4794 FALSE, // do not log error
4795 4, // unique error value
4798 SrbGetLun(Srb));
4799
4800 fdoExtension->FailurePredicted = TRUE;
4801 break;
4802 }
4803
4804 default: {
4805 logStatus = IO_ERR_CONTROLLER_ERROR;
4806 break;
4807 }
4808
4809 } // end switch(addlSenseCode)
4810
4811 if (isIncorrectLengthValid && incorrectLength) {
4812
4813 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4814 "Incorrect length detected.\n"));
4816 }
4817
4818
4819 break;
4820 } // end SCSI_SENSE_RECOVERED_ERROR
4821
4822 case SCSI_SENSE_NOT_READY: {
4823
4824 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4825 "Device not ready\n"));
4827
4828 switch (addlSenseCode) {
4829
4831
4832 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4833 "Lun not ready\n"));
4834
4835 retryInterval = NOT_READY_RETRY_INTERVAL;
4836
4837 switch (addlSenseCodeQual) {
4838
4840 DEVICE_EVENT_BECOMING_READY notReady = {0};
4841
4842 logRetryableError = FALSE;
4843 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4844 "In process of becoming ready\n"));
4845
4846 notReady.Version = 1;
4847 notReady.Reason = 1;
4848 notReady.Estimated100msToReady = retryInterval * 10;
4849 ClassSendNotification(fdoExtension,
4850 &GUID_IO_DEVICE_BECOMING_READY,
4852 &notReady);
4853 break;
4854 }
4855
4857 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4858 "Manual intervention required\n"));
4860 retry = FALSE;
4861 break;
4862 }
4863
4865 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4866 "Format in progress\n"));
4867 retry = FALSE;
4868 break;
4869 }
4870
4872 DEVICE_EVENT_BECOMING_READY notReady = {0};
4873
4874 logRetryableError = FALSE;
4875 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4876 "Operation In Progress\n"));
4877
4878 notReady.Version = 1;
4879 notReady.Reason = 2;
4880 notReady.Estimated100msToReady = retryInterval * 10;
4881 ClassSendNotification(fdoExtension,
4882 &GUID_IO_DEVICE_BECOMING_READY,
4884 &notReady);
4885
4886 break;
4887 }
4888
4890 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4891 "Long write in progress\n"));
4892 //
4893 // This has been seen as a transcient failure on some cdrom
4894 // drives. The cdrom class driver is going to override this
4895 // setting but has no way of dropping the retry interval
4896 //
4897 retry = FALSE;
4898 retryInterval = 1;
4899 break;
4900 }
4901
4903 logRetryableError = FALSE;
4904 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4905 "The device (%p) is busy allocating space.\n",
4906 Fdo));
4907
4908 //
4909 // This indicates that a thinly-provisioned device has hit
4910 // a temporary resource exhaustion and is busy allocating
4911 // more space. We need to retry the request as the device
4912 // will eventually be able to service it.
4913 //
4915 retry = TRUE;
4916
4917 break;
4918 }
4919
4921
4922 if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
4924
4925 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
4926 "ClassInterpretSenseInfo: "
4927 "not ready, cause unknown\n"));
4928 /*
4929 Many non-WHQL certified drives (mostly CD-RW) return
4930 this when they have no media instead of the obvious
4931 choice of:
4932
4933 SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
4934
4935 These drives should not pass WHQL certification due
4936 to this discrepency.
4937
4938 */
4939 retry = FALSE;
4940 break;
4941
4942 } else {
4943
4944 //
4945 // Treat this as init command required and fall through.
4946 //
4947 }
4948 }
4949
4951 default: {
4952 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4953 "Initializing command required\n"));
4954 retryInterval = 0; // go back to default
4955 logRetryableError = FALSE;
4956
4957 //
4958 // This sense code/additional sense code
4959 // combination may indicate that the device
4960 // needs to be started. Send an start unit if this
4961 // is a disk device.
4962 //
4963 if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT) &&
4965
4967 }
4968 break;
4969 }
4970
4971 } // end switch (addlSenseCodeQual)
4972 break;
4973 }
4974
4976 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4977 "No Media in device.\n"));
4979 retry = FALSE;
4980
4981 //
4982 // signal MCN that there isn't any media in the device
4983 //
4984 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
4985 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
4986 "No Media in a non-removable device %p\n",
4987 Fdo));
4988 }
4989
4990 if (addlSenseCodeQual == 0xCC){
4991 /*
4992 * The IMAPI filter returns this ASCQ value when it is burning CD-R media.
4993 * We want to indicate that the media is not present to most applications;
4994 * but RSM has to know that the media is still in the drive (i.e. the drive is not free).
4995 */
4996 ClassSetMediaChangeState(fdoExtension, MediaUnavailable, FALSE);
4997 }
4998 else {
4999 ClassSetMediaChangeState(fdoExtension, MediaNotPresent, FALSE);
5000 }
5001
5002 break;
5003 }
5004 } // end switch (addlSenseCode)
5005
5006 break;
5007 } // end SCSI_SENSE_NOT_READY
5008
5010 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
5011 "Medium Error (bad block)\n"));
5013
5014 retry