ReactOS  0.4.15-dev-1033-gd7d716a
class.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 2010
4 
5 Module Name:
6 
7  class.c
8 
9 Abstract:
10 
11  SCSI class driver routines
12 
13 Environment:
14 
15  kernel mode only
16 
17 Notes:
18 
19 
20 Revision 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 
84 IO_COMPLETION_ROUTINE ClassCheckVerifyComplete;
85 
86 
89 CONST LARGE_INTEGER Magic10000 = {{0xe219652c, 0xd1b71758}};
90 GUID 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 
156 DriverEntry()
157 
158 Routine Description:
159 
160  Temporary entry point needed to initialize the class system dll.
161  It doesn't do anything.
162 
163 Arguments:
164 
165  DriverObject - Pointer to the driver object created by the system.
166 
167 Return Value:
168 
169  STATUS_SUCCESS
170 
171 --*/
172 NTSTATUS
173 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
177  )
178 {
181 
182  return STATUS_SUCCESS;
183 }
184 
185 
186 
187 /*++////////////////////////////////////////////////////////////////////////////
188 
189 ClassInitialize()
190 
191 Routine Description:
192 
193  This routine is called by a class driver during its
194  DriverEntry routine to initialize the driver.
195 
196 Arguments:
197 
198  Argument1 - Driver Object.
199  Argument2 - Registry Path.
200  InitializationData - Device-specific driver's initialization data.
201 
202 Return Value:
203 
204  A valid return code for a DriverEntry routine.
205 
206 --*/
209 ULONG
210 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
211 ClassInitialize(
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"));
306  NT_ASSERT(FALSE);
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),
371  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) {
430  }
431 
432  if ((InitializationData->ClassUnload) && (ClassPnpAllowUnload == TRUE)) {
434  } else {
436  }
437 
439 #ifdef _MSC_VER
440 #pragma prefast(pop)
441 #endif
442 
443 
444  //
445  // Register for event tracing
446  //
447  if (driverExtension->EtwHandle == 0) {
448  status = EtwRegister(&StoragePredictFailureDPSGuid,
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 
473 ClassInitializeEx()
474 
475 Routine 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 
506 Arguments:
507 
508  DriverObject
509  Guid
510  Data
511 
512 Return Value:
513 
514  Status Code
515 
516 --*/
519 ULONG
520 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
521 ClassInitializeEx(
523  _In_ LPGUID Guid,
524  _In_ PVOID Data
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  {
540  NT_ASSERT(FALSE);
541  return (ULONG)STATUS_UNSUCCESSFUL;
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
619  NT_ASSERT(FALSE);
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
699  NT_ASSERT(FALSE);
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) {
731  NT_ASSERT(FALSE);
732  }
733  } else {
735  }
736  }
737  else
738  {
740  }
741 
742  return status;
743 
744 } // end ClassInitializeEx()
745 
746 /*++////////////////////////////////////////////////////////////////////////////
747 
748 ClassUnload()
749 
750 Routine Description:
751 
752  called when there are no more references to the driver. this allows
753  drivers to be updated without rebooting.
754 
755 Arguments:
756 
757  DriverObject - a pointer to the driver object that is being unloaded
758 
759 Status:
760 
761 --*/
762 VOID
763 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
766  )
767 {
768  PCLASS_DRIVER_EXTENSION driverExtension;
769 
770  PAGED_CODE();
771 
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  {
782  NT_ASSERT(FALSE);
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 
825 ClassAddDevice()
826 
827 Routine 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 
836 Arguments:
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 
841 Status: 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 --*/
846 NTSTATUS
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
850 NTAPI /* 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 
874 ClassDispatchPnp()
875 
876 Routine 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 
881 Arguments:
882 
883  DeviceObject - pointer to the device object
884 
885  Irp - pointer to the io request packet
886 
887 Return Value:
888 
889  status
890 
891 --*/
892 NTSTATUS
893 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
896  IN PIRP Irp
897  )
898 {
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
923  driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, CLASS_DRIVER_EXTENSION_KEY);
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",
938  DeviceObject, Irp,
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",
943  DeviceObject, Irp,
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 
982  if(type == TargetDeviceRelation) {
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",
1112  DeviceObject, Irp,
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) {
1137  status = devInfo->ClassStopDevice(DeviceObject,
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",
1165  DeviceObject, Irp, status));
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) {
1180  status = devInfo->ClassStopDevice(DeviceObject,
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  ) ||
1199  ((irpStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) &&
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",
1234  DeviceObject, Irp,
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 
1271  case IRP_MN_REMOVE_DEVICE:
1272  case IRP_MN_SURPRISE_REMOVAL: {
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 
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 
1365  DEVICE_USAGE_NOTIFICATION_TYPE type = irpStack->Parameters.UsageNotification.Type;
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){
1404  DeviceObject,
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 
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 
1502  DeviceObject,
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 
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 
1585  case DeviceUsageTypeDumpFile: {
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 
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) {
1654  PCLASS_PRIVATE_FDO_DATA fdoData;
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 
1697  DeviceObject,
1698  irpStack->Parameters.DeviceCapabilities.Capabilities
1699  );
1700 
1701  break;
1702 
1703  } else {
1704 
1705  PDEVICE_CAPABILITIES deviceCapabilities;
1706  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1707  PCLASS_PRIVATE_FDO_DATA fdoData;
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 
1801 ClassPnpStartDevice()
1802 
1803 Routine Description:
1804 
1805  Storage class driver routine for IRP_MN_START_DEVICE requests.
1806  This routine kicks off any device specific initialization
1807 
1808 Arguments:
1809 
1810  DeviceObject - a pointer to the device object
1811 
1812  Irp - a pointer to the io request packet
1813 
1814 Return Value:
1815 
1816  none
1817 
1818 --*/
1820 {
1821  PCLASS_DRIVER_EXTENSION driverExtension;
1822  PCLASS_INIT_DATA initData;
1823 
1824  PCLASS_DEV_INFO devInfo;
1825 
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)) {
1980  NT_ASSERT(FALSE);
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);
2084  if (t >= CLASS_PERF_RESTORE_MINIMUM) {
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));
2121  }
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)){
2163  status = devInfo->ClassInitDevice(DeviceObject);
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 
2339  status = devInfo->ClassStartDevice(DeviceObject);
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 
2403 ClassReadWrite()
2404 
2405 Routine 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 
2418 Arguments:
2419 
2420  DeviceObject - a pointer to the device object for this request
2421 
2422  Irp - IO request
2423 
2424 Return Value:
2425 
2426  NT Status
2427 
2428 --*/
2429 NTSTATUS
2430 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2432 {
2434  PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
2436  ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
2437  ULONG isRemoved;
2438  NTSTATUS status;
2439 
2440  /*
2441  * Grab the remove lock. If we can't acquire it, bail out.
2442  */
2443  isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
2444  if (isRemoved) {
2445  Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
2446  Irp->IoStatus.Information = 0;
2450  }
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  */
2477  currentIrpStack->MinorFunction = CLASSP_VOLUME_VERIFY_CHECKED;
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 
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 
2576  SnapDiskStartup();
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  //
2609  ClassAcquireRemoveLock(DeviceObject, (PVOID)&uniqueAddr);
2610 
2613  if (fdoData->IdlePrioritySupported == TRUE) {
2615  }
2616 
2617  ClassReleaseRemoveLock(DeviceObject, (PVOID)&uniqueAddr);
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 
2635 Exit:
2636  return status;
2637 }
2638 
2639 
2641 {
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  */
2701  fdoExt->CommonExtension.PartitionLength.QuadPart =
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 {
2711  fdoExt->DiskGeometry.MediaType = FixedMedia;
2712  }
2713 
2714 }
2715 
2716 /*++////////////////////////////////////////////////////////////////////////////
2717 
2718 ClassReadDriveCapacity()
2719 
2720 Routine 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 
2729 Arguments:
2730 
2731  DeviceObject - Supplies a pointer to the device object that represents
2732  the device whose capacity is to be read.
2733 
2734 Return Value:
2735 
2736  Status is returned.
2737 
2738 --*/
2740 NTSTATUS
2741 NTAPI /* 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;
2749  NTSTATUS status;
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 
2759 RetryRequest:
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 
2781  pkt = DequeueFreeTransferPacket(Fdo, TRUE);
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);
2811  SubmitTransferPacket(pkt);
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 
2828  pkt = DequeueFreeTransferPacket(Fdo, TRUE);
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);
2840  SubmitTransferPacket(pkt);
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;
2917  fdoData->IsCachedDriveCapDataValid = TRUE;
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;
2981  fdoExt->CommonExtension.PartitionLength.QuadPart = (LONGLONG) 0;
2982 
2983  //
2984  // Is this removable or fixed media
2985  //
2986 
2987  if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
2989  } else {
2990  fdoExt->DiskGeometry.MediaType = FixedMedia;
2991  }
2992  }
2993 
2994 SafeExit:
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)) {
3019  fdoData->IsCachedDriveCapDataValid = FALSE;
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 
3042 ClassSendStartUnit()
3043 
3044 Routine 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 
3060 Arguments:
3061 
3062  Fdo - The functional device object for the stopped device.
3063 
3064 Return Value:
3065 
3066  None.
3067 
3068 --*/
3069 VOID
3070 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3072  _In_ PDEVICE_OBJECT Fdo
3073  )
3074 {
3075  PIO_STACK_LOCATION irpStack;
3076  PIRP irp;
3077  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3078  PSCSI_REQUEST_BLOCK srb;
3080  PCDB cdb;
3081  NTSTATUS status;
3082  PSTORAGE_REQUEST_BLOCK srbEx;
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)) {
3119  FREE_POOL(context);
3120  NT_ASSERT(FALSE);
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 
3153  SrbAssignSrbFlags(srb,
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 
3190  ClassAcquireRemoveLock(Fdo, irp);
3191 
3194  context,
3195  TRUE,
3196  TRUE,
3197  TRUE);
3198 
3199  irpStack = IoGetNextIrpStackLocation(irp);
3200  irpStack->MajorFunction = IRP_MJ_SCSI;
3201  SrbSetOriginalRequest(srb, irp);
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 
3213  IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
3214 
3215  return;
3216 
3217 } // end StartUnit()
3218 
3219 /*++////////////////////////////////////////////////////////////////////////////
3220 
3221 ClassAsynchronousCompletion() ISSUE-2000/02/18-henrygab - why public?!
3222 
3223 Routine 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 
3230 Arguments:
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 
3239 Return Value:
3240 
3241  None.
3242 
3243 --*/
3244 NTSTATUS
3245 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3248  PIRP Irp,
3249  PVOID Context
3250  )
3251 {
3253  PSCSI_REQUEST_BLOCK srb;
3254  ULONG srbFunction;
3255  ULONG srbFlags;
3256 
3257  if (context == NULL) {
3258  return STATUS_INVALID_PARAMETER;
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 
3287  if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
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 
3300 
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 
3327  FREE_POOL(context);
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 
3340 NTSTATUS
3342  PDEVICE_OBJECT Fdo,
3343  PIRP Irp,
3344  BOOLEAN PostToDpc
3345  )
3346 
3347 /*++
3348 
3349 Routine 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 
3359 Arguments:
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 
3365 Return Value:
3366 
3367  STATUS_SUCCESS if successful, an error code otherwise
3368 
3369 --*/
3370 
3371 {
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  */
3507  pkt = DequeueFreeTransferPacket(Fdo, TRUE);
3508  if (pkt) {
3509  SimplePushSlist(&pktList, (PSINGLE_LIST_ENTRY)&pkt->SlistEntry);
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++){
3519  pkt = DequeueFreeTransferPacket(Fdo, TRUE);
3520  if (pkt){
3521  SimplePushSlist(&pktList, (PSINGLE_LIST_ENTRY)&pkt->SlistEntry);
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);
3645  EnqueueFreeTransferPacket(Fdo, pkt);
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 
3739 ClassIoComplete()
3740 
3741 Routine 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 
3752 Arguments:
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 
3761 Return Value:
3762 
3763  NT status
3764 
3765 --*/
3766 NTSTATUS
3767 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3769  IN PDEVICE_OBJECT Fdo,
3770  IN PIRP Irp,
3771  IN PVOID Context
3772  )
3773 {
3776  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3777  PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
3778  NTSTATUS status;
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 
3804  if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
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 
3813  if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
3814  ClassReleaseQueue(Fdo);
3815  }
3817  Fdo,
3818  Irp,
3819  srb,
3820  irpStack->MajorFunction,
3821  ((irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) ?
3822  irpStack->Parameters.DeviceIoControl.IoControlCode :
3823  0),
3824  MAXIMUM_RETRIES -
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 &&
3834  (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_PERSISTENT_RESERVE_IN ||
3835  irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_PERSISTENT_RESERVE_OUT) &&
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 
3929  if (fdoExtension->CommonExtension.IsSrbLookasideListInitialized){
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 
3993  if (fdoExtension->CommonExtension.DriverExtension->InitData.ClassStartIo) {
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 
4011 ClassSendSrbSynchronous()
4012 
4013 Routine 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 
4020 Arguments:
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 
4032 Return 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 --*/
4040 NTSTATUS
4041 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
4043  _In_ PDEVICE_OBJECT Fdo,
4045  _In_reads_bytes_opt_(BufferLength) PVOID BufferAddress,
4047  _In_ BOOLEAN WriteToDevice
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;
4060  NTSTATUS status;
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 
4077  if (Srb->Function != SRB_FUNCTION_STORAGE_REQUEST_BLOCK) {
4078  //
4079  // Write length to SRB.
4080  //
4081 
4082  Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
4083 
4084  //
4085  // Set SCSI bus address.
4086  //
4087 
4088  Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4089  }
4090 
4091  //
4092  // The Srb->Function should have been set corresponding to SrbType.
4093  //
4094 
4095  NT_ASSERT( ((fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_SCSI_REQUEST_BLOCK) && (Srb->Function == SRB_FUNCTION_EXECUTE_SCSI)) ||
4096  ((fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) && (Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK)) );
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 
4131  SrbSetDataBuffer(Srb, BufferAddress);
4132 
4133 
4134  //
4135  // Start retries here.
4136  //
4137 
4138 retry:
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 
4180  irp = IoAllocateIrp(
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,
4223  BufferLength,
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,
4244  (WriteToDevice ? IoReadAccess :
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 
4275  SrbSetScsiStatus(Srb, 0);
4276  Srb->SrbStatus = 0;
4278 
4279  //
4280  // Set up IRP Address.
4281  //
4282 
4283  SrbSetOriginalRequest(Srb, irp);
4284 
4285  //
4286  // Call the port driver with the request and wait for it to complete.
4287  //
4288 
4289  status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
4290 
4291  if (status == STATUS_PENDING) {
4293  status = ioStatus.Status;
4294  }
4295 
4296 // NT_ASSERT(SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_PENDING);
4298  NT_ASSERT(!(Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN));
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 
4311  if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
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,
4317  DBGGETSRBSTATUSSTR(Srb), (ULONG)Srb->SrbStatus, status,
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
4335  IRP_MJ_SCSI,
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 
4357  (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) {
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 
4419 ClassInterpretSenseInfo()
4420 
4421 Routine 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 
4427 Arguments:
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 
4444 Return Value:
4445 
4446  BOOLEAN TRUE: Drivers should retry this request.
4447  FALSE: Drivers should not retry this request.
4448 
4449 --*/
4450 BOOLEAN
4451 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
4453  _In_ PDEVICE_OBJECT Fdo,
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 
4530  if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR) {
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;
4567  ULONGLONG information = 0;
4568 
4569 
4570  validSense = ScsiGetSenseKeyAndCodes(senseBuffer,
4573  &senseKey,
4574  &addlSenseCode,
4575  &addlSenseCodeQual);
4576 
4577  if (!validSense && !IsSenseDataFormatValueValid(senseBuffer)) {
4578 
4579  NT_ASSERT(FALSE);
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;
4614  PVOID outBuffer = NULL;
4615  UCHAR outBufferLength = 0;
4616  BOOLEAN foundBlockCommandType = FALSE;
4617  BOOLEAN foundInformationType = FALSE;
4618  UCHAR descriptorLength = 0;
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  //
4663  NT_ASSERT(FALSE);
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  //
4688  NT_ASSERT(FALSE);
4689  }
4690 
4691  } else {
4692 
4693  //
4694  // ScsiGetNextDescriptorByType should only return a type that is specified by us.
4695  //
4696  NT_ASSERT(FALSE);
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) {
4757  case SCSI_ADSENSE_SEEK_ERROR: {
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
4796  SrbGetPathId(Srb),
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  //
4914  *Status = STATUS_RETRY;
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 
4966  ClassSendStartUnit(Fdo);
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 
5009  case SCSI_SENSE_MEDIUM_ERROR: {
5010  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
5011  "Medium Error (bad block)\n"));
5013 
5014  retry = FALSE;
5015  logError = TRUE;
5016  uniqueId = 256;
5017  logStatus = IO_ERR_BAD_BLOCK;
5018 
5019  //
5020  // Check if this error is due to unknown format
5021  //
5022  if (addlSenseCode == SCSI_ADSENSE_INVALID_MEDIA) {
5023 
5024  switch (addlSenseCodeQual) {
5025 
5027 
5029 
5030  //
5031  // Log error only if this is a paging request
5032  //
5034  logError = FALSE;
5035  }
5036  break;
5037  }
5038 
5040 
5042  logError = FALSE;
5043  break;
5044 
5045  }
5046  default: {
5047  break;
5048  }
5049  } // end switch addlSenseCodeQual
5050 
5051  } // end SCSI_ADSENSE_INVALID_MEDIA
5052 
5053  break;
5054 
5055  } // end SCSI_SENSE_MEDIUM_ERROR
5056 
5058  BOOLEAN logHardwareError = TRUE;
5059 
5060  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
5061  "Hardware error\n"));
5062 
5063  if (fdoData->LegacyErrorHandling == FALSE) {
5064  //
5065  // Hardware errors indicate something has seriously gone
5066  // wrong with the device and retries are very unlikely to
5067  // succeed so fail this request back immediately.
5068  //
5069  retry = FALSE;
5071  logError = FALSE;
5072 
5073  } else {
5074  //
5075  // Revert to legacy behavior. That is, retry everything by default.
5076  //
5077  retry = TRUE;
5079  logError = TRUE;
5080  uniqueId = 257;
5081  logStatus = IO_ERR_CONTROLLER_ERROR;
5082  logHardwareError = FALSE;
5083 
5084  //
5085  // This indicates the possibility of a dropped FC packet.
5086  //
5087  if ((addlSenseCode == SCSI_ADSENSE_LOGICAL_UNIT_ERROR && addlSenseCodeQual == SCSI_SENSEQ_TIMEOUT_ON_LOGICAL_UNIT) ||
5088  (addlSenseCode == SCSI_ADSENSE_DATA_TRANSFER_ERROR && addlSenseCodeQual == SCSI_SENSEQ_INITIATOR_RESPONSE_TIMEOUT)) {
5089  //
5090  // Fail requests that report this error back to the application.
5091  //
5092  retry = FALSE;
5093 
5094  //
5095  // Log a more descriptive error and avoid a second
5096  // error message (IO_ERR_CONTROLLER_ERROR) being logged.
5097  //
5098  logHardwareError = TRUE;
5099  logError = FALSE;
5100  }
5101  }
5102 
5103  //
5104  // If CRC error was returned, retry after a slight delay.
5105  //
5106  if (addlSenseCode == SCSI_ADSENSE_LUN_COMMUNICATION &&
5107  addlSenseCodeQual == SCSI_SESNEQ_COMM_CRC_ERROR) {
5108  retry = TRUE;
5109  retryInterval = 1;
5110  logHardwareError = FALSE;
5111  logError = FALSE;
5112  }
5113 
5114  //
5115  // Hardware errors warrant a more descriptive error.
5116  // Specifically, we need to ensure this disk is easily
5117  // identifiable.
5118  //
5119  if (logHardwareError) {
5120  UCHAR senseInfoBufferLength = SrbGetSenseInfoBufferLength(Srb);
5121  UCHAR senseBufferSize = 0;
5122 
5123  if (ScsiGetTotalSenseByteCountIndicated(senseBuffer,
5124  senseInfoBufferLength,
5125  &senseBufferSize)) {
5126 
5127  senseBufferSize = min(senseBufferSize, senseInfoBufferLength);
5128 
5129  } else {
5130  //
5131  // it's smaller than required to read the total number of
5132  // valid bytes, so just use the SenseInfoBufferLength field.
5133  //
5134  senseBufferSize = senseInfoBufferLength;
5135  }
5136 
5138  senseBufferSize,
5139  senseBuffer,
5140  SRB_STATUS(Srb->SrbStatus),
5143  cdbLength,
5144  cdb,
5145  NULL);
5146  }
5147 
5148  break;
5149  } // end SCSI_SENSE_HARDWARE_ERROR
5150 
5152 
5153  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
5154  "Illegal SCSI request\n"));
5156  retry = FALSE;
5157 
5158  switch (addlSenseCode) {
5159 
5160  case SCSI_ADSENSE_NO_SENSE: {
5161 
5162  switch (addlSenseCodeQual) {
5163 
5164  //
5165  // 1. Duplicate List Identifier
5166  //
5168 
5169  //
5170  // XCOPY, READ BUFFER and CHANGE ALIASES return this sense combination under
5171  // certain conditions. Since these commands aren't sent down natively by the
5172  // Windows OS, return the default error for them and only handle this sense
5173  // combination for offload data transfer commands.
5174  //
5176 
5177  TracePrint((TRACE_LEVEL_ERROR,
5178  TRACE_FLAG_IOCTL,
5179  "ClassInterpretSenseInfo (%p): Duplicate List Identifier (command %x, parameter field offset 0x%016llx)\n",
5180  Fdo,
5181  cdbOpcode,
5182  information));
5183 
5184  NT_ASSERTMSG("Duplicate list identifier specified", FALSE);
5185 
5186  //
5187  // The host should ensure that it uses unique list id for each TokenOperation request.
5188  //
5190  }
5191  break;
5192  }
5193  }
5194  break;
5195  }
5196 
5198 
5199  switch (addlSenseCodeQual) {
5200 
5201  //
5202  // 1. Source/Destination pairing can't communicate with each other or the copy manager.
5203  //
5205 
5206  TracePrint((TRACE_LEVEL_ERROR,
5207  TRACE_FLAG_IOCTL,
5208  "ClassInterpretSenseInfo (%p): Source-Destination LUNs can't communicate (command %x)\n",
5209  Fdo,
5210  cdbOpcode));
5211 
5213  break;
5214  }
5215  }
5216  break;
5217  }
5218 
5220 
5221  switch (addlSenseCodeQual) {
5222 
5223  //
5224  // 1. Sum of logical block fields in all block device range descriptors is greater than number
5225  // of logical blocks in the ROD minus block offset into ROD
5226  //
5228 
5229  TracePrint((TRACE_LEVEL_ERROR,
5230  TRACE_FLAG_IOCTL,
5231  "ClassInterpretSenseInfo (%p): Host specified a transfer length greater than what is represented by the token (considering the offset) [command %x]\n",
5232  Fdo,
5233  cdbOpcode));
5234 
5235  NT_ASSERTMSG("Host specified blocks to write beyond what is represented by the token", FALSE);
5236 
5238  break;
5239  }
5240  }
5241  break;
5242  }
5243 
5244  //
5245  // 1. Parameter data truncation (e.g. last descriptor was not fully specified)
5246  //
5248 
5249  TracePrint((TRACE_LEVEL_ERROR,
5250  TRACE_FLAG_IOCTL,
5251  "ClassInterpretSenseInfo (%p): Target truncated the block device range descriptors in the parameter list (command %x)\n",
5252  Fdo,
5253  cdbOpcode));
5254 
5255  NT_ASSERTMSG("Parameter data truncation", FALSE);
5256 
5258  break;
5259  }
5260 
5262  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
5263  "Illegal command\n"));
5264  break;
5265  }
5266 
5268 
5269  LARGE_INTEGER logicalBlockAddr;
5270  LARGE_INTEGER lastLBA;
5271  ULONG numTransferBlocks = 0;
5272 
5273  logicalBlockAddr.QuadPart = 0;
5274 
5275  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: Illegal block address\n"));
5276 
5278 
5279  if (Fdo->DeviceType == FILE_DEVICE_DISK) {
5280 
5281  if (IS_SCSIOP_READWRITE(cdbOpcode) && cdb) {
5282 
5283  if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_USE_16BYTE_CDB)) {
5284  REVERSE_BYTES_QUAD(&logicalBlockAddr, &cdb->CDB16.LogicalBlock);
5285  REVERSE_BYTES(&numTransferBlocks, &cdb->CDB16.TransferLength);
5286  } else {
5287  REVERSE_BYTES(&logicalBlockAddr.LowPart, &cdb->CDB10.LogicalBlockByte0);
5288  REVERSE_BYTES_SHORT((PUSHORT)&numTransferBlocks, &cdb->CDB10.TransferBlocksMsb);
5289  }
5290 
5292 
5293  if ((logicalBlockAddr.QuadPart > lastLBA.QuadPart) ||
5294  ((logicalBlockAddr.QuadPart + numTransferBlocks - 1) > lastLBA.QuadPart)) {
5295 
5296  TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
5297  "Request beyond boundary. Last LBA: 0x%I64X Read LBA: 0x%I64X Length: 0x%X\n",
5298  (__int64) lastLBA.QuadPart, (__int64) logicalBlockAddr.QuadPart, numTransferBlocks));
5299  } else {
5300  //
5301  // Should only retry these if the request was
5302  // truly within our expected size.
5303  //
5304  // Fujitsu IDE drives have been observed to
5305  // return this error transiently for a legal LBA;
5306  // manual retry in the debugger then works, so
5307  // there is a good chance that a programmed retry
5308  // will also work.
5309  //
5310 
5311  retry = TRUE;
5312  retryInterval = 5;
5313  }
5314  } else if (ClasspIsOffloadDataTransferCommand(cdb)) {
5315 
5316  //
5317  // 1. Number of logical blocks of block device range descriptor exceeds capacity of the medium
5318  //
5319  TracePrint((TRACE_LEVEL_ERROR,
5320  TRACE_FLAG_IOCTL,
5321  "ClassInterpretSenseInfo (%p): LBA out of range (command %x, parameter field offset 0x%016llx)\n",
5322  Fdo,
5323  cdbOpcode,
5324  information));
5325 
5326  NT_ASSERTMSG("Number of blocks specified exceeds LUN capacity", FALSE);
5327  }
5328  }
5329  break;
5330  }
5331 
5332  //
5333  // 1. Generic error - cause not reportable
5334  // 2. Insufficient resources to create ROD
5335  // 3. Insufficient resources to create Token
5336  // 4. Max number of tokens exceeded
5337  // 5. Remote Token creation not supported
5338  // 6. Token expired
5339  // 7. Token unknown
5340  // 8. Unsupported Token type
5341  // 9. Token corrupt
5342  // 10. Token revoked
5343  // 11. Token cancelled
5344  // 12. Remote Token usage not supported
5345  //
5347 
5348  TracePrint((TRACE_LEVEL_ERROR,
5349  TRACE_FLAG_IOCTL,
5350  "ClassInterpretSenseInfo (%p): Invalid/Expired/Modified token specified (command %x, parameter field offset 0x%016llx)\n",
5351  Fdo,
5352  cdbOpcode,
5353  information));
5354 
5356  break;
5357  }
5358 
5359  case SCSI_ADSENSE_INVALID_CDB: {
5361 
5362  //
5363  // 1. Mismatched I_T nexus and list identifier
5364  //
5365  TracePrint((TRACE_LEVEL_ERROR,
5366  TRACE_FLAG_IOCTL,
5367  "ClassInterpretSenseInfo (%p): Incorrect I_T nexus likely used (command %x)\n",
5368  Fdo,
5369  cdbOpcode));
5370 
5371  //
5372  // The host should ensure that it sends TokenOperation and ReceiveTokenInformation for the same
5373  // list Id using the same I_T nexus.
5374  //
5376 
5377  } else {
5378 
5379  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
5380  "Invalid CDB\n"));
5381 
5382  //
5383  // Note: the retry interval is not typically used.
5384  // it is set here only because a ClassErrorHandler
5385  // cannot set the retryInterval, and the error may
5386  // require a few commands to be sent to clear whatever
5387  // caused this condition (i.e. disk clears the write
5388  // cache, requiring at least two commands)
5389  //
5390  // hopefully, this shortcoming can be changed for
5391  // blackcomb.
5392  //
5393 
5394  retryInterval = 3;
5395  }
5396  break;
5397  }
5398 
5399  case SCSI_ADSENSE_INVALID_LUN: {
5400  TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "ClassInterpretSenseInfo: "
5401  "Invalid LUN\n"));
5403  break;
5404  }
5405 
5407 
5408  switch (addlSenseCodeQual) {
5409 
5410  //
5411  // 1. Alignment violation (e.g. copy manager is unable to copy because destination offset is NOT aligned to LUN's granularity/alignment)
5412  //
5414 
5415  TracePrint((TRACE_LEVEL_ERROR,
5416  TRACE_FLAG_IOCTL,
5417  "ClassInterpretSenseInfo (%p): Alignment violation for command %x.\n",
5418  Fdo,
5419  cdbOpcode));
5420 
5421  NT_ASSERTMSG("Specified offset is not aligned to LUN's granularity", FALSE);
5422 
5424  break;
5425  }
5426 
5427  //
5428  // 1. Number of block device range descriptors is greater than maximum range descriptors
5429  //
5431 
5432  TracePrint((TRACE_LEVEL_ERROR,
5433  TRACE_FLAG_IOCTL,
5434  "ClassInterpretSenseInfo (%p): Too many descriptors in parameter list for command %x (parameter field offset 0x%016llx)\n",
5435  Fdo,
5436  cdbOpcode,
5437  information));
5438 
5439  NT_ASSERTMSG("Too many descriptors specified", FALSE);
5440 
5442  break;
5443  }
5444 
5445  default: {
5446