ReactOS  0.4.12-dev-708-g95ed44e
class.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 1999
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 #include "classp.h"
25 
26 #include <stddef.h>
27 
28 #include <initguid.h>
29 #include <mountdev.h>
30 
31 #ifdef ALLOC_PRAGMA
32  #pragma alloc_text(INIT, DriverEntry)
33  #pragma alloc_text(PAGE, ClassAddDevice)
34  #pragma alloc_text(PAGE, ClassClaimDevice)
35  #pragma alloc_text(PAGE, ClassCreateDeviceObject)
36  #pragma alloc_text(PAGE, ClassDispatchPnp)
37  #pragma alloc_text(PAGE, ClassGetDescriptor)
38  #pragma alloc_text(PAGE, ClassGetPdoId)
39  #pragma alloc_text(PAGE, ClassInitialize)
40  #pragma alloc_text(PAGE, ClassInitializeEx)
41  #pragma alloc_text(PAGE, ClassInvalidateBusRelations)
42  #pragma alloc_text(PAGE, ClassMarkChildMissing)
43  #pragma alloc_text(PAGE, ClassMarkChildrenMissing)
44  #pragma alloc_text(PAGE, ClassModeSense)
45  #pragma alloc_text(PAGE, ClassPnpQueryFdoRelations)
46  #pragma alloc_text(PAGE, ClassPnpStartDevice)
47  #pragma alloc_text(PAGE, ClassQueryPnpCapabilities)
48  #pragma alloc_text(PAGE, ClassQueryTimeOutRegistryValue)
49  #pragma alloc_text(PAGE, ClassRemoveDevice)
50  #pragma alloc_text(PAGE, ClassRetrieveDeviceRelations)
51  #pragma alloc_text(PAGE, ClassUpdateInformationInRegistry)
52  #pragma alloc_text(PAGE, ClassSendDeviceIoControlSynchronous)
53  #pragma alloc_text(PAGE, ClassUnload)
54  #pragma alloc_text(PAGE, ClasspAllocateReleaseRequest)
55  #pragma alloc_text(PAGE, ClasspFreeReleaseRequest)
56  #pragma alloc_text(PAGE, ClasspInitializeHotplugInfo)
57  #pragma alloc_text(PAGE, ClasspRegisterMountedDeviceInterface)
58  #pragma alloc_text(PAGE, ClasspScanForClassHacks)
59  #pragma alloc_text(PAGE, ClasspScanForSpecialInRegistry)
60 #endif
61 
63 
64 
65 #define FirstDriveLetter 'C'
66 #define LastDriveLetter 'Z'
67 
68 
69 
70 /*++////////////////////////////////////////////////////////////////////////////
71 
72 DriverEntry()
73 
74 Routine Description:
75 
76  Temporary entry point needed to initialize the class system dll.
77  It doesn't do anything.
78 
79 Arguments:
80 
81  DriverObject - Pointer to the driver object created by the system.
82 
83 Return Value:
84 
85  STATUS_SUCCESS
86 
87 --*/
89 NTAPI
93  )
94 {
95  return STATUS_SUCCESS;
96 }
97 
98 /*++////////////////////////////////////////////////////////////////////////////
99 
100 ClassInitialize()
101 
102 Routine Description:
103 
104  This routine is called by a class driver during its
105  DriverEntry routine to initialize the driver.
106 
107 Arguments:
108 
109  Argument1 - Driver Object.
110  Argument2 - Registry Path.
111  InitializationData - Device-specific driver's initialization data.
112 
113 Return Value:
114 
115  A valid return code for a DriverEntry routine.
116 
117 --*/
118 ULONG
119 NTAPI
124  )
125 {
128 
129  PCLASS_DRIVER_EXTENSION driverExtension;
130 
132 
133  PAGED_CODE();
134 
135  DebugPrint((3,"\n\nSCSI Class Driver\n"));
136 
138 
139  //
140  // Validate the length of this structure. This is effectively a
141  // version check.
142  //
143 
144  if (InitializationData->InitializationDataSize != sizeof(CLASS_INIT_DATA)) {
145 
146  //
147  // This DebugPrint is to help third-party driver writers
148  //
149 
150  DebugPrint((0,"ClassInitialize: Class driver wrong version\n"));
152  }
153 
154  //
155  // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
156  // are not required entry points.
157  //
158 
159  if ((!InitializationData->FdoData.ClassDeviceControl) ||
160  (!((InitializationData->FdoData.ClassReadWriteVerification) ||
161  (InitializationData->ClassStartIo))) ||
162  (!InitializationData->ClassAddDevice) ||
163  (!InitializationData->FdoData.ClassStartDevice)) {
164 
165  //
166  // This DebugPrint is to help third-party driver writers
167  //
168 
169  DebugPrint((0,
170  "ClassInitialize: Class device-specific driver missing required "
171  "FDO entry\n"));
172 
174  }
175 
176  if ((InitializationData->ClassEnumerateDevice) &&
177  ((!InitializationData->PdoData.ClassDeviceControl) ||
178  (!InitializationData->PdoData.ClassStartDevice) ||
179  (!((InitializationData->PdoData.ClassReadWriteVerification) ||
180  (InitializationData->ClassStartIo))))) {
181 
182  //
183  // This DebugPrint is to help third-party driver writers
184  //
185 
186  DebugPrint((0, "ClassInitialize: Class device-specific missing "
187  "required PDO entry\n"));
188 
190  }
191 
192  if((InitializationData->FdoData.ClassStopDevice == NULL) ||
193  ((InitializationData->ClassEnumerateDevice != NULL) &&
194  (InitializationData->PdoData.ClassStopDevice == NULL))) {
195 
196  //
197  // This DebugPrint is to help third-party driver writers
198  //
199 
200  DebugPrint((0, "ClassInitialize: Class device-specific missing "
201  "required PDO entry\n"));
202  ASSERT(FALSE);
204  }
205 
206  //
207  // Setup the default power handlers if the class driver didn't provide
208  // any.
209  //
210 
211  if(InitializationData->FdoData.ClassPowerDevice == NULL) {
212  InitializationData->FdoData.ClassPowerDevice = ClassMinimalPowerHandler;
213  }
214 
215  if((InitializationData->ClassEnumerateDevice != NULL) &&
216  (InitializationData->PdoData.ClassPowerDevice == NULL)) {
217  InitializationData->PdoData.ClassPowerDevice = ClassMinimalPowerHandler;
218  }
219 
220  //
221  // warn that unload is not supported
222  //
223  // ISSUE-2000/02/03-peterwie
224  // We should think about making this a fatal error.
225  //
226 
227  if(InitializationData->ClassUnload == NULL) {
228 
229  //
230  // This DebugPrint is to help third-party driver writers
231  //
232 
233  DebugPrint((0, "ClassInitialize: driver does not support unload %wZ\n",
234  RegistryPath));
235  }
236 
237  //
238  // Create an extension for the driver object
239  //
240 
243  sizeof(CLASS_DRIVER_EXTENSION),
244  (PVOID *)&driverExtension);
245 
246  if(NT_SUCCESS(status)) {
247 
248  //
249  // Copy the registry path into the driver extension so we can use it later
250  //
251 
252  driverExtension->RegistryPath.Length = RegistryPath->Length;
253  driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
254 
255  driverExtension->RegistryPath.Buffer =
258  '1CcS');
259 
260  if(driverExtension->RegistryPath.Buffer == NULL) {
261 
263  return status;
264  }
265 
267  &(driverExtension->RegistryPath),
268  RegistryPath);
269 
270  //
271  // Copy the initialization data into the driver extension so we can reuse
272  // it during our add device routine
273  //
274 
276  &(driverExtension->InitData),
278  sizeof(CLASS_INIT_DATA));
279 
280  driverExtension->DeviceCount = 0;
281 
282  } else if (status == STATUS_OBJECT_NAME_COLLISION) {
283 
284  //
285  // The extension already exists - get a pointer to it
286  //
287 
288  driverExtension = IoGetDriverObjectExtension(DriverObject,
290 
291  ASSERT(driverExtension != NULL);
292 
293  } else {
294 
295  DebugPrint((1, "ClassInitialize: Class driver extension could not be "
296  "allocated %lx\n", status));
297  return status;
298  }
299 
300  //
301  // Update driver object with entry points.
302  //
303 
315 
316  if (InitializationData->ClassStartIo) {
318  }
319 
320  if ((InitializationData->ClassUnload) && (ClassPnpAllowUnload != FALSE)) {
322  } else {
324  }
325 
327 
328  DbgPrint("Driver is ready to go\n");
330  return status;
331 } // end ClassInitialize()
332 
333 /*++////////////////////////////////////////////////////////////////////////////
334 
335 ClassInitializeEx()
336 
337 Routine Description:
338 
339  This routine is allows the caller to do any extra initialization or
340  setup that is not done in ClassInitialize. The operation is
341  controlled by the GUID that is passed and the contents of the Data
342  parameter is dependent upon the GUID.
343 
344  This is the list of supported operations:
345 
346  Guid - GUID_CLASSPNP_QUERY_REGINFOEX
347  Data - A PCLASS_QUERY_WMI_REGINFO_EX callback function pointer
348 
349  Initialized classpnp to callback a PCLASS_QUERY_WMI_REGINFO_EX
350  callback instead of a PCLASS_QUERY_WMI_REGINFO callback. The
351  former callback allows the driver to specify the name of the
352  mof resource.
353 
354 Arguments:
355 
356  DriverObject
357  Guid
358  Data
359 
360 Return Value:
361 
362  Status Code
363 
364 --*/
365 ULONG
366 NTAPI
369  IN LPGUID Guid,
370  IN PVOID Data
371  )
372 {
373  PCLASS_DRIVER_EXTENSION driverExtension;
374 
376 
377  PAGED_CODE();
378 
379  driverExtension = IoGetDriverObjectExtension( DriverObject,
381  );
383  {
385 
386  //
387  // Indicate the device supports PCLASS_QUERY_REGINFO_EX
388  // callback instead of PCLASS_QUERY_REGINFO callback.
389  //
391 
392  if (List->Size == sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST))
393  {
394  driverExtension->ClassFdoQueryWmiRegInfoEx = List->ClassFdoQueryWmiRegInfoEx;
395  driverExtension->ClassPdoQueryWmiRegInfoEx = List->ClassPdoQueryWmiRegInfoEx;
397  } else {
399  }
400  } else {
402  }
403 
404  return(status);
405 
406 } // end ClassInitializeEx()
407 
408 /*++////////////////////////////////////////////////////////////////////////////
409 
410 ClassUnload()
411 
412 Routine Description:
413 
414  called when there are no more references to the driver. this allows
415  drivers to be updated without rebooting.
416 
417 Arguments:
418 
419  DriverObject - a pointer to the driver object that is being unloaded
420 
421 Status:
422 
423 --*/
424 VOID
425 NTAPI
428  )
429 {
430  PCLASS_DRIVER_EXTENSION driverExtension;
431  //NTSTATUS status;
432 
433  PAGED_CODE();
434 
436 
437  driverExtension = IoGetDriverObjectExtension( DriverObject,
439  );
440 
441  ASSERT(driverExtension != NULL);
442  ASSERT(driverExtension->RegistryPath.Buffer != NULL);
443  ASSERT(driverExtension->InitData.ClassUnload != NULL);
444 
445  DebugPrint((1, "ClassUnload: driver unloading %wZ\n",
446  &driverExtension->RegistryPath));
447 
448  //
449  // attempt to process the driver's unload routine first.
450  //
451 
452  driverExtension->InitData.ClassUnload(DriverObject);
453 
454  //
455  // free own allocated resources and return
456  //
457 
458  ExFreePool( driverExtension->RegistryPath.Buffer );
459  driverExtension->RegistryPath.Buffer = NULL;
460  driverExtension->RegistryPath.Length = 0;
461  driverExtension->RegistryPath.MaximumLength = 0;
462 
463  return;
464 } // end ClassUnload()
465 
466 /*++////////////////////////////////////////////////////////////////////////////
467 
468 ClassAddDevice()
469 
470 Routine Description:
471 
472  SCSI class driver add device routine. This is called by pnp when a new
473  physical device come into being.
474 
475  This routine will call out to the class driver to verify that it should
476  own this device then will create and attach a device object and then hand
477  it to the driver to initialize and create symbolic links
478 
479 Arguments:
480 
481  DriverObject - a pointer to the driver object that this is being created for
482  PhysicalDeviceObject - a pointer to the physical device object
483 
484 Status: STATUS_NO_SUCH_DEVICE if the class driver did not want this device
485  STATUS_SUCCESS if the creation and attachment was successful
486  status of device creation and initialization
487 
488 --*/
489 NTSTATUS
490 NTAPI
494  )
495 {
496  PCLASS_DRIVER_EXTENSION driverExtension =
499 
501 
502  PAGED_CODE();
503 
504  DbgPrint("got a device\n");
505  status = driverExtension->InitData.ClassAddDevice(DriverObject,
507  return status;
508 } // end ClassAddDevice()
509 
510 /*++////////////////////////////////////////////////////////////////////////////
511 
512 ClassDispatchPnp()
513 
514 Routine Description:
515 
516  Storage class driver pnp routine. This is called by the io system when
517  a PNP request is sent to the device.
518 
519 Arguments:
520 
521  DeviceObject - pointer to the device object
522 
523  Irp - pointer to the io request packet
524 
525 Return Value:
526 
527  status
528 
529 --*/
530 NTSTATUS
531 NTAPI
534  IN PIRP Irp
535  )
536 {
538  BOOLEAN isFdo = commonExtension->IsFdo;
539 
540  PCLASS_DRIVER_EXTENSION driverExtension;
541  PCLASS_INIT_DATA initData;
542  PCLASS_DEV_INFO devInfo;
543 
545 
546  NTSTATUS status = Irp->IoStatus.Status;
547  BOOLEAN completeRequest = TRUE;
548  BOOLEAN lockReleased = FALSE;
549 
550  PAGED_CODE();
551 
552  //
553  // Extract all the useful information out of the driver object
554  // extension
555  //
556 
557  driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
559  if (driverExtension){
560 
561  initData = &(driverExtension->InitData);
562 
563  if(isFdo) {
564  devInfo = &(initData->FdoData);
565  } else {
566  devInfo = &(initData->PdoData);
567  }
568 
570 
571  DebugPrint((2, "ClassDispatchPnp (%p,%p): minor code %#x for %s %p\n",
572  DeviceObject, Irp,
573  irpStack->MinorFunction,
574  isFdo ? "fdo" : "pdo",
575  DeviceObject));
576  DebugPrint((2, "ClassDispatchPnp (%p,%p): previous %#x, current %#x\n",
577  DeviceObject, Irp,
578  commonExtension->PreviousState,
579  commonExtension->CurrentState));
580 
581  switch(irpStack->MinorFunction) {
582 
583  case IRP_MN_START_DEVICE: {
584 
585  //
586  // if this is sent to the FDO we should forward it down the
587  // attachment chain before we start the FDO.
588  //
589 
590  if (isFdo) {
591  status = ClassForwardIrpSynchronous(commonExtension, Irp);
592  }
593  else {
595  }
596 
597  if (NT_SUCCESS(status)){
598  status = Irp->IoStatus.Status = ClassPnpStartDevice(DeviceObject);
599  }
600 
601  break;
602  }
603 
604 
606 
608  irpStack->Parameters.QueryDeviceRelations.Type;
609 
610  PDEVICE_RELATIONS deviceRelations = NULL;
611 
612  if(!isFdo) {
613 
614  if(type == TargetDeviceRelation) {
615 
616  //
617  // Device relations has one entry built in to it's size.
618  //
619 
621 
622  deviceRelations = ExAllocatePoolWithTag(PagedPool,
623  sizeof(DEVICE_RELATIONS),
624  '2CcS');
625 
626  if(deviceRelations != NULL) {
627 
628  RtlZeroMemory(deviceRelations,
629  sizeof(DEVICE_RELATIONS));
630 
631  Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
632 
633  deviceRelations->Count = 1;
634  deviceRelations->Objects[0] = DeviceObject;
635  ObReferenceObject(deviceRelations->Objects[0]);
636 
638  }
639 
640  } else {
641  //
642  // PDO's just complete enumeration requests without altering
643  // the status.
644  //
645 
646  status = Irp->IoStatus.Status;
647  }
648 
649  break;
650 
651  } else if (type == BusRelations) {
652 
653  ASSERT(commonExtension->IsInitialized);
654 
655  //
656  // Make sure we support enumeration
657  //
658 
659  if(initData->ClassEnumerateDevice == NULL) {
660 
661  //
662  // Just send the request down to the lower driver. Perhaps
663  // It can enumerate children.
664  //
665 
666  } else {
667 
668  //
669  // Re-enumerate the device
670  //
671 
673 
674  if(!NT_SUCCESS(status)) {
675  completeRequest = TRUE;
676  break;
677  }
678  }
679  }
680 
683  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
684  completeRequest = FALSE;
685 
686  break;
687  }
688 
689  case IRP_MN_QUERY_ID: {
690 
691  BUS_QUERY_ID_TYPE idType = irpStack->Parameters.QueryId.IdType;
692  UNICODE_STRING unicodeString;
693 
694  if(isFdo) {
695 
696  //
697  // FDO's should just forward the query down to the lower
698  // device objects
699  //
700 
703 
704  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
705  completeRequest = FALSE;
706  break;
707  }
708 
709  //
710  // PDO's need to give an answer - this is easy for now
711  //
712 
713  RtlInitUnicodeString(&unicodeString, NULL);
714 
716  idType,
717  &unicodeString);
718 
720  //
721  // The driver doesn't implement this ID (whatever it is).
722  // Use the status out of the IRP so that we don't mangle a
723  // response from someone else.
724  //
725 
726  status = Irp->IoStatus.Status;
727  } else if(NT_SUCCESS(status)) {
728  Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer;
729  } else {
730  Irp->IoStatus.Information = (ULONG_PTR) NULL;
731  }
732 
733  break;
734  }
735 
738 
739  DebugPrint((2, "ClassDispatchPnp (%p,%p): Processing QUERY_%s irp\n",
740  DeviceObject, Irp,
741  ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
742  "STOP" : "REMOVE")));
743 
744  //
745  // If this device is in use for some reason (paging, etc...)
746  // then we need to fail the request.
747  //
748 
749  if(commonExtension->PagingPathCount != 0) {
750 
751  DebugPrint((1, "ClassDispatchPnp (%p,%p): device is in paging "
752  "path and cannot be removed\n",
753  DeviceObject, Irp));
755  break;
756  }
757 
758  //
759  // Check with the class driver to see if the query operation
760  // can succeed.
761  //
762 
763  if(irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) {
765  irpStack->MinorFunction);
766  } else {
768  irpStack->MinorFunction);
769  }
770 
771  if(NT_SUCCESS(status)) {
772 
773  //
774  // ASSERT that we never get two queries in a row, as
775  // this will severely mess up the state machine
776  //
777  ASSERT(commonExtension->CurrentState != irpStack->MinorFunction);
778  commonExtension->PreviousState = commonExtension->CurrentState;
779  commonExtension->CurrentState = irpStack->MinorFunction;
780 
781  if(isFdo) {
782  DebugPrint((2, "ClassDispatchPnp (%p,%p): Forwarding QUERY_"
783  "%s irp\n", DeviceObject, Irp,
784  ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
785  "STOP" : "REMOVE")));
786  status = ClassForwardIrpSynchronous(commonExtension, Irp);
787  }
788  }
789  DebugPrint((2, "ClassDispatchPnp (%p,%p): Final status == %x\n",
790  DeviceObject, Irp, status));
791 
792  break;
793  }
794 
797 
798  //
799  // Check with the class driver to see if the query or cancel
800  // operation can succeed.
801  //
802 
803  if(irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) {
805  irpStack->MinorFunction);
806  NT_ASSERTMSGW(L"ClassDispatchPnp !! CANCEL_STOP_DEVICE should "
807  L"never be failed\n", NT_SUCCESS(status));
808  } else {
810  irpStack->MinorFunction);
811  NT_ASSERTMSGW(L"ClassDispatchPnp !! CANCEL_REMOVE_DEVICE should "
812  L"never be failed\n", NT_SUCCESS(status));
813  }
814 
815  Irp->IoStatus.Status = status;
816 
817  //
818  // We got a CANCEL - roll back to the previous state only
819  // if the current state is the respective QUERY state.
820  //
821 
822  if(((irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) &&
823  (commonExtension->CurrentState == IRP_MN_QUERY_STOP_DEVICE)
824  ) ||
825  ((irpStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) &&
826  (commonExtension->CurrentState == IRP_MN_QUERY_REMOVE_DEVICE)
827  )
828  ) {
829 
830  commonExtension->CurrentState =
831  commonExtension->PreviousState;
832  commonExtension->PreviousState = 0xff;
833 
834  }
835 
836  if(isFdo) {
839  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
840  completeRequest = FALSE;
841  } else {
843  }
844 
845  break;
846  }
847 
848  case IRP_MN_STOP_DEVICE: {
849 
850  //
851  // These all mean nothing to the class driver currently. The
852  // port driver will handle all queueing when necessary.
853  //
854 
855  DebugPrint((2, "ClassDispatchPnp (%p,%p): got stop request for %s\n",
856  DeviceObject, Irp,
857  (isFdo ? "fdo" : "pdo")
858  ));
859 
860  ASSERT(commonExtension->PagingPathCount == 0);
861 
862  //
863  // ISSUE-2000/02/03-peterwie
864  // if we stop the timer here then it means no class driver can
865  // do i/o in its ClassStopDevice routine. This is because the
866  // retry (among other things) is tied into the tick handler
867  // and disabling retries could cause the class driver to deadlock.
868  // Currently no class driver we're aware of issues i/o in its
869  // Stop routine but this is a case we may want to defend ourself
870  // against.
871  //
872 
873  if (DeviceObject->Timer) {
875  }
876 
878 
879  NT_ASSERTMSGW(L"ClassDispatchPnp !! STOP_DEVICE should "
880  L"never be failed\n", NT_SUCCESS(status));
881 
882  if(isFdo) {
883  status = ClassForwardIrpSynchronous(commonExtension, Irp);
884  }
885 
886  if(NT_SUCCESS(status)) {
887  commonExtension->CurrentState = irpStack->MinorFunction;
888  commonExtension->PreviousState = 0xff;
889  }
890 
891  break;
892  }
893 
896 
897  UCHAR removeType = irpStack->MinorFunction;
898 
899  if (commonExtension->PagingPathCount != 0) {
900  DBGTRACE(ClassDebugWarning, ("ClassDispatchPnp (%p,%p): paging device is getting removed!", DeviceObject, Irp));
901  }
902 
903  //
904  // Release the lock for this IRP before calling in.
905  //
907  lockReleased = TRUE;
908 
909  /*
910  * If a timer was started on the device, stop it.
911  */
912  if (DeviceObject->Timer) {
914  }
915 
916  /*
917  * "Fire-and-forget" the remove irp to the lower stack.
918  * Don't touch the irp (or the irp stack!) after this.
919  */
920  if (isFdo) {
922  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
924  completeRequest = FALSE;
925  }
926  else {
928  }
929 
930  /*
931  * Do our own cleanup and call the class driver's remove
932  * cleanup routine.
933  * For IRP_MN_REMOVE_DEVICE, this also deletes our device object,
934  * so don't touch the extension after this.
935  */
936  commonExtension->PreviousState = commonExtension->CurrentState;
937  commonExtension->CurrentState = removeType;
938  ClassRemoveDevice(DeviceObject, removeType);
939 
940  break;
941  }
942 
944 
945  switch(irpStack->Parameters.UsageNotification.Type) {
946 
947  case DeviceUsageTypePaging: {
948 
949  BOOLEAN setPagable;
950 
951  if((irpStack->Parameters.UsageNotification.InPath) &&
952  (commonExtension->CurrentState != IRP_MN_START_DEVICE)) {
953 
954  //
955  // Device isn't started. Don't allow adding a
956  // paging file, but allow a removal of one.
957  //
958 
960  break;
961  }
962 
963  ASSERT(commonExtension->IsInitialized);
964 
965  //
966  // need to synchronize this now...
967  //
968 
970  status = KeWaitForSingleObject(&commonExtension->PathCountEvent,
972  FALSE, NULL);
975 
976  //
977  // If the volume is removable we should try to lock it in
978  // place or unlock it once per paging path count
979  //
980 
981  if (commonExtension->IsFdo){
983  DeviceObject,
984  Irp,
986  (BOOLEAN)irpStack->Parameters.UsageNotification.InPath);
987  }
988 
989  if (!NT_SUCCESS(status)){
990  KeSetEvent(&commonExtension->PathCountEvent, IO_NO_INCREMENT, FALSE);
992  break;
993  }
994 
995  //
996  // if removing last paging device, need to set DO_POWER_PAGABLE
997  // bit here, and possible re-set it below on failure.
998  //
999 
1000  setPagable = FALSE;
1001 
1002  if (!irpStack->Parameters.UsageNotification.InPath &&
1003  commonExtension->PagingPathCount == 1
1004  ) {
1005 
1006  //
1007  // removing last paging file
1008  // must have DO_POWER_PAGABLE bits set, but only
1009  // if noone set the DO_POWER_INRUSH bit
1010  //
1011 
1012 
1014  DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
1015  "paging file removed, but "
1016  "DO_POWER_INRUSH was set, so NOT "
1017  "setting DO_POWER_PAGABLE\n",
1018  DeviceObject, Irp));
1019  } else {
1020  DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
1021  "paging file removed, "
1022  "setting DO_POWER_PAGABLE\n",
1023  DeviceObject, Irp));
1025  setPagable = TRUE;
1026  }
1027 
1028  }
1029 
1030  //
1031  // forward the irp before finishing handling the
1032  // special cases
1033  //
1034 
1035  status = ClassForwardIrpSynchronous(commonExtension, Irp);
1036 
1037  //
1038  // now deal with the failure and success cases.
1039  // note that we are not allowed to fail the irp
1040  // once it is sent to the lower drivers.
1041  //
1042 
1043  if (NT_SUCCESS(status)) {
1044 
1046  (PLONG)&commonExtension->PagingPathCount,
1047  irpStack->Parameters.UsageNotification.InPath);
1048 
1049  if (irpStack->Parameters.UsageNotification.InPath) {
1050  if (commonExtension->PagingPathCount == 1) {
1051  DebugPrint((2, "ClassDispatchPnp (%p,%p): "
1052  "Clearing PAGABLE bit\n",
1053  DeviceObject, Irp));
1055  }
1056  }
1057 
1058  } else {
1059 
1060  //
1061  // cleanup the changes done above
1062  //
1063 
1064  if (setPagable != FALSE) {
1065  DebugPrint((2, "ClassDispatchPnp (%p,%p): Unsetting "
1066  "PAGABLE bit due to irp failure\n",
1067  DeviceObject, Irp));
1069  setPagable = FALSE;
1070  }
1071 
1072  //
1073  // relock or unlock the media if needed.
1074  //
1075 
1076  if (commonExtension->IsFdo) {
1077 
1079  DeviceObject,
1080  Irp,
1082  (BOOLEAN)!irpStack->Parameters.UsageNotification.InPath);
1083  }
1084  }
1085 
1086  //
1087  // set the event so the next one can occur.
1088  //
1089 
1090  KeSetEvent(&commonExtension->PathCountEvent,
1093  break;
1094  }
1095 
1097 
1099  (PLONG)&commonExtension->HibernationPathCount,
1100  irpStack->Parameters.UsageNotification.InPath
1101  );
1102  status = ClassForwardIrpSynchronous(commonExtension, Irp);
1103  if (!NT_SUCCESS(status)) {
1105  (PLONG)&commonExtension->HibernationPathCount,
1106  !irpStack->Parameters.UsageNotification.InPath
1107  );
1108  }
1109 
1110  break;
1111  }
1112 
1113  case DeviceUsageTypeDumpFile: {
1115  (PLONG)&commonExtension->DumpPathCount,
1116  irpStack->Parameters.UsageNotification.InPath
1117  );
1118  status = ClassForwardIrpSynchronous(commonExtension, Irp);
1119  if (!NT_SUCCESS(status)) {
1121  (PLONG)&commonExtension->DumpPathCount,
1122  !irpStack->Parameters.UsageNotification.InPath
1123  );
1124  }
1125 
1126  break;
1127  }
1128 
1129  default: {
1131  break;
1132  }
1133  }
1134  break;
1135  }
1136 
1138 
1139  DebugPrint((2, "ClassDispatchPnp (%p,%p): QueryCapabilities\n",
1140  DeviceObject, Irp));
1141 
1142  if(!isFdo) {
1143 
1145  DeviceObject,
1146  irpStack->Parameters.DeviceCapabilities.Capabilities
1147  );
1148 
1149  break;
1150 
1151  } else {
1152 
1153  PDEVICE_CAPABILITIES deviceCapabilities;
1154  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1155  PCLASS_PRIVATE_FDO_DATA fdoData;
1156 
1157  fdoExtension = DeviceObject->DeviceExtension;
1158  fdoData = fdoExtension->PrivateFdoData;
1159  deviceCapabilities =
1160  irpStack->Parameters.DeviceCapabilities.Capabilities;
1161 
1162  //
1163  // forward the irp before handling the special cases
1164  //
1165 
1166  status = ClassForwardIrpSynchronous(commonExtension, Irp);
1167  if (!NT_SUCCESS(status)) {
1168  break;
1169  }
1170 
1171  //
1172  // we generally want to remove the device from the hotplug
1173  // applet, which requires the SR-OK bit to be set.
1174  // only when the user specifies that they are capable of
1175  // safely removing things do we want to clear this bit
1176  // (saved in WriteCacheEnableOverride)
1177  //
1178  // setting of this bit is done either above, or by the
1179  // lower driver.
1180  //
1181  // note: may not be started, so check we have FDO data first.
1182  //
1183 
1184  if (fdoData &&
1186  if (deviceCapabilities->SurpriseRemovalOK) {
1187  DebugPrint((1, "Classpnp: Clearing SR-OK bit in "
1188  "device capabilities due to hotplug "
1189  "device or media\n"));
1190  }
1191  deviceCapabilities->SurpriseRemovalOK = FALSE;
1192  }
1193  break;
1194 
1195  } // end QUERY_CAPABILITIES for FDOs
1196 
1197  ASSERT(FALSE);
1198  break;
1199 
1200 
1201  } // end QUERY_CAPABILITIES
1202 
1203  default: {
1204 
1205  if (isFdo){
1207 
1209  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1210 
1211  completeRequest = FALSE;
1212  }
1213 
1214  break;
1215  }
1216  }
1217  }
1218  else {
1219  ASSERT(driverExtension);
1221  }
1222 
1223  if (completeRequest){
1224  Irp->IoStatus.Status = status;
1225 
1226  if (!lockReleased){
1228  }
1229 
1231 
1232  DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving with previous %#x, current %#x.", DeviceObject, Irp, commonExtension->PreviousState, commonExtension->CurrentState));
1233  }
1234  else {
1235  /*
1236  * The irp is already completed so don't touch it.
1237  * This may be a remove so don't touch the device extension.
1238  */
1239  DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving.", DeviceObject, Irp));
1240  }
1241 
1242  return status;
1243 } // end ClassDispatchPnp()
1244 
1245 /*++////////////////////////////////////////////////////////////////////////////
1246 
1247 ClassPnpStartDevice()
1248 
1249 Routine Description:
1250 
1251  Storage class driver routine for IRP_MN_START_DEVICE requests.
1252  This routine kicks off any device specific initialization
1253 
1254 Arguments:
1255 
1256  DeviceObject - a pointer to the device object
1257 
1258  Irp - a pointer to the io request packet
1259 
1260 Return Value:
1261 
1262  none
1263 
1264 --*/
1266 {
1267  PCLASS_DRIVER_EXTENSION driverExtension;
1268  PCLASS_INIT_DATA initData;
1269 
1270  PCLASS_DEV_INFO devInfo;
1271 
1274  BOOLEAN isFdo = commonExtension->IsFdo;
1275 
1276  BOOLEAN isMountedDevice = TRUE;
1277  //UNICODE_STRING interfaceName;
1278 
1279  BOOLEAN timerStarted;
1280 
1282 
1283  PAGED_CODE();
1284 
1285  driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
1287 
1288  initData = &(driverExtension->InitData);
1289  if(isFdo) {
1290  devInfo = &(initData->FdoData);
1291  } else {
1292  devInfo = &(initData->PdoData);
1293  }
1294 
1295  ASSERT(devInfo->ClassInitDevice != NULL);
1296  ASSERT(devInfo->ClassStartDevice != NULL);
1297 
1298  if (!commonExtension->IsInitialized){
1299 
1300  //
1301  // perform FDO/PDO specific initialization
1302  //
1303 
1304  if (isFdo){
1305  STORAGE_PROPERTY_ID propertyId;
1306 
1307  //
1308  // allocate a private extension for class data
1309  //
1310 
1311  if (fdoExtension->PrivateFdoData == NULL) {
1312  fdoExtension->PrivateFdoData =
1314  sizeof(CLASS_PRIVATE_FDO_DATA),
1316  );
1317  }
1318 
1319  if (fdoExtension->PrivateFdoData == NULL) {
1320  DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for "
1321  "private fdo data\n"));
1323  }
1324 
1325  //
1326  // initialize the struct's various fields.
1327  //
1328 
1329  RtlZeroMemory(fdoExtension->PrivateFdoData,
1330  sizeof(CLASS_PRIVATE_FDO_DATA)
1331  );
1332  KeInitializeTimer(&fdoExtension->PrivateFdoData->Retry.Timer);
1333  KeInitializeDpc(&fdoExtension->PrivateFdoData->Retry.Dpc,
1335  DeviceObject);
1336  KeInitializeSpinLock(&fdoExtension->PrivateFdoData->Retry.Lock);
1337  fdoExtension->PrivateFdoData->Retry.Granularity =
1339  commonExtension->Reserved4 = (ULONG_PTR)(' GPH'); // debug aid
1340 
1341  //
1342  // NOTE: the old interface allowed the class driver to allocate
1343  // this. this was unsafe for low-memory conditions. allocate one
1344  // unconditionally now, and modify our internal functions to use
1345  // our own exclusively as it is the only safe way to do this.
1346  //
1347 
1348  status = ClasspAllocateReleaseQueueIrp(fdoExtension);
1349  if (!NT_SUCCESS(status)) {
1350  DebugPrint((0, "ClassPnpStartDevice: Cannot allocate the "
1351  "private release queue irp\n"));
1352  return status;
1353  }
1354 
1355  //
1356  // Call port driver to get adapter capabilities.
1357  //
1358 
1359  propertyId = StorageAdapterProperty;
1360 
1362  commonExtension->LowerDeviceObject,
1363  &propertyId,
1364  (PSTORAGE_DESCRIPTOR_HEADER *)&fdoExtension->AdapterDescriptor);
1365 
1366  if(!NT_SUCCESS(status)) {
1367 
1368  //
1369  // This DebugPrint is to help third-party driver writers
1370  //
1371 
1372  DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor "
1373  "[ADAPTER] failed %lx\n", status));
1374  return status;
1375  }
1376 
1377  //
1378  // Call port driver to get device descriptor.
1379  //
1380 
1381  propertyId = StorageDeviceProperty;
1382 
1384  commonExtension->LowerDeviceObject,
1385  &propertyId,
1386  (PSTORAGE_DESCRIPTOR_HEADER *)&fdoExtension->DeviceDescriptor);
1387 
1388  if(!NT_SUCCESS(status)) {
1389 
1390  //
1391  // This DebugPrint is to help third-party driver writers
1392  //
1393 
1394  DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor "
1395  "[DEVICE] failed %lx\n", status));
1396  return status;
1397  }
1398 
1399  ClasspScanForSpecialInRegistry(fdoExtension);
1400  ClassScanForSpecial(fdoExtension,
1401  ClassBadItems,
1403 
1404  //
1405  // allow perf to be re-enabled after a given number of failed IOs
1406  // require this number to be at least CLASS_PERF_RESTORE_MINIMUM
1407  //
1408 
1409  {
1410  ULONG t = 0;
1411  ClassGetDeviceParameter(fdoExtension,
1414  &t);
1415  if (t >= CLASS_PERF_RESTORE_MINIMUM) {
1416  fdoExtension->PrivateFdoData->Perf.ReEnableThreshold = t;
1417  }
1418  }
1419 
1420 
1421  //
1422  // compatibility comes first. writable cd media will not
1423  // get a SYNCH_CACHE on power down.
1424  //
1425 
1426  if (fdoExtension->DeviceObject->DeviceType != FILE_DEVICE_DISK) {
1427  SET_FLAG(fdoExtension->PrivateFdoData->HackFlags,
1429  }
1430 
1431  //
1432  // initialize the hotplug information only after the ScanForSpecial
1433  // routines, as it relies upon the hack flags.
1434  //
1435 
1436  status = ClasspInitializeHotplugInfo(fdoExtension);
1437 
1438  if (!NT_SUCCESS(status)) {
1439  DebugPrint((1, "ClassPnpStartDevice: Could not initialize "
1440  "hotplug information %lx\n", status));
1441  return status;
1442  }
1443 
1444  /*
1445  * Allocate/initialize TRANSFER_PACKETs and related resources.
1446  */
1448  }
1449 
1450  //
1451  // ISSUE - drivers need to disable write caching on the media
1452  // if hotplug and !useroverride. perhaps we should
1453  // allow registration of a callback to enable/disable
1454  // write cache instead.
1455  //
1456 
1457  if (NT_SUCCESS(status)){
1458  status = devInfo->ClassInitDevice(DeviceObject);
1459  }
1460 
1461  }
1462 
1463  if (!NT_SUCCESS(status)){
1464 
1465  //
1466  // Just bail out - the remove that comes down will clean up the
1467  // initialized scraps.
1468  //
1469 
1470  return status;
1471  } else {
1472  commonExtension->IsInitialized = TRUE;
1473 
1474  if (commonExtension->IsFdo) {
1475  fdoExtension->PrivateFdoData->Perf.OriginalSrbFlags = fdoExtension->SrbFlags;
1476  }
1477 
1478  }
1479 
1480  //
1481  // If device requests autorun functionality or a once a second callback
1482  // then enable the once per second timer.
1483  //
1484  // NOTE: This assumes that ClassInitializeMediaChangeDetection is always
1485  // called in the context of the ClassInitDevice callback. If called
1486  // after then this check will have already been made and the
1487  // once a second timer will not have been enabled.
1488  //
1489  if ((isFdo) &&
1490  ((initData->ClassTick != NULL) ||
1491  (fdoExtension->MediaChangeDetectionInfo != NULL) ||
1492  ((fdoExtension->FailurePredictionInfo != NULL) &&
1493  (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone))))
1494  {
1496  timerStarted = TRUE;
1497  } else {
1498  timerStarted = FALSE;
1499  }
1500 
1501  //
1502  // NOTE: the timer looks at commonExtension->CurrentState now
1503  // to prevent Media Change Notification code from running
1504  // until the device is started, but allows the device
1505  // specific tick handler to run. therefore it is imperative
1506  // that commonExtension->CurrentState not be updated until
1507  // the device specific startdevice handler has finished.
1508  //
1509 
1510  status = devInfo->ClassStartDevice(DeviceObject);
1511 
1512  if(NT_SUCCESS(status)) {
1513  commonExtension->CurrentState = IRP_MN_START_DEVICE;
1514 
1515  if((isFdo) && (initData->ClassEnumerateDevice != NULL)) {
1516  isMountedDevice = FALSE;
1517  }
1518 
1519  if((DeviceObject->DeviceType != FILE_DEVICE_DISK) &&
1520  (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)) {
1521 
1522  isMountedDevice = FALSE;
1523  }
1524 
1525 
1526  if(isMountedDevice) {
1528  }
1529 
1530  if((commonExtension->IsFdo) &&
1531  (devInfo->ClassWmiInfo.GuidRegInfo != NULL)) {
1532 
1534  }
1535  } else {
1536 
1537  if (timerStarted) {
1539  }
1540  }
1541 
1542  return status;
1543 }
1544 
1545 
1546 /*++////////////////////////////////////////////////////////////////////////////
1547 
1548 ClassReadWrite()
1549 
1550 Routine Description:
1551 
1552  This is the system entry point for read and write requests. The
1553  device-specific handler is invoked to perform any validation necessary.
1554 
1555  If the device object is a PDO (partition object) then the request will
1556  simply be adjusted for Partition0 and issued to the lower device driver.
1557 
1558  IF the device object is an FDO (partition 0 object), the number of bytes
1559  in the request are checked against the maximum byte counts that the adapter
1560  supports and requests are broken up into
1561  smaller sizes if necessary.
1562 
1563 Arguments:
1564 
1565  DeviceObject - a pointer to the device object for this request
1566 
1567  Irp - IO request
1568 
1569 Return Value:
1570 
1571  NT Status
1572 
1573 --*/
1575 {
1577  PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
1579  //LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
1580  ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1581  ULONG isRemoved;
1582  NTSTATUS status;
1583 
1584  /*
1585  * Grab the remove lock. If we can't acquire it, bail out.
1586  */
1587  isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
1588  if (isRemoved) {
1589  Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
1593  }
1595  (currentIrpStack->MinorFunction != CLASSP_VOLUME_VERIFY_CHECKED) &&
1596  !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)){
1597 
1598  /*
1599  * DO_VERIFY_VOLUME is set for the device object,
1600  * but this request is not itself a verify request.
1601  * So fail this request.
1602  */
1604  Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1605  Irp->IoStatus.Information = 0;
1609  }
1610  else {
1611 
1612  /*
1613  * Since we've bypassed the verify-required tests we don't need to repeat
1614  * them with this IRP - in particular we don't want to worry about
1615  * hitting them at the partition 0 level if the request has come through
1616  * a non-zero partition.
1617  */
1618  currentIrpStack->MinorFunction = CLASSP_VOLUME_VERIFY_CHECKED;
1619 
1620  /*
1621  * Call the miniport driver's pre-pass filter to check if we
1622  * should continue with this transfer.
1623  */
1624  ASSERT(commonExtension->DevInfo->ClassReadWriteVerification);
1626  if (!NT_SUCCESS(status)){
1627  ASSERT(Irp->IoStatus.Status == status);
1630  }
1631  else if (status == STATUS_PENDING){
1632  /*
1633  * ClassReadWriteVerification queued this request.
1634  * So don't touch the irp anymore.
1635  */
1636  }
1637  else {
1638 
1639  if (transferByteCount == 0) {
1640  /*
1641  * Several parts of the code turn 0 into 0xffffffff,
1642  * so don't process a zero-length request any further.
1643  */
1644  Irp->IoStatus.Status = STATUS_SUCCESS;
1645  Irp->IoStatus.Information = 0;
1649  }
1650  else {
1651  /*
1652  * If the driver has its own StartIo routine, call it.
1653  */
1654  if (commonExtension->DriverExtension->InitData.ClassStartIo) {
1658  }
1659  else {
1660  /*
1661  * The driver does not have its own StartIo routine.
1662  * So process this request ourselves.
1663  */
1664 
1665  /*
1666  * Add partition byte offset to make starting byte relative to
1667  * beginning of disk.
1668  */
1669  currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
1670  commonExtension->StartingOffset.QuadPart;
1671 
1672  if (commonExtension->IsFdo){
1673 
1674  /*
1675  * Add in any skew for the disk manager software.
1676  */
1677  currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
1678  commonExtension->PartitionZeroExtension->DMByteSkew;
1679 
1680  /*
1681  * Perform the actual transfer(s) on the hardware
1682  * to service this request.
1683  */
1686  }
1687  else {
1688  /*
1689  * This is a child PDO enumerated for our FDO by e.g. disk.sys
1690  * and owned by e.g. partmgr. Send it down to the next device
1691  * and the same irp will come back to us for the FDO.
1692  */
1695  status = IoCallDriver(lowerDeviceObject, Irp);
1696  }
1697  }
1698  }
1699  }
1700  }
1701 
1702  return status;
1703 }
1704 
1705 
1706 /*++////////////////////////////////////////////////////////////////////////////
1707 
1708 ClassReadDriveCapacity()
1709 
1710 Routine Description:
1711 
1712  This routine sends a READ CAPACITY to the requested device, updates
1713  the geometry information in the device object and returns
1714  when it is complete. This routine is synchronous.
1715 
1716  This routine must be called with the remove lock held or some other
1717  assurance that the Fdo will not be removed while processing.
1718 
1719 Arguments:
1720 
1721  DeviceObject - Supplies a pointer to the device object that represents
1722  the device whose capacity is to be read.
1723 
1724 Return Value:
1725 
1726  Status is returned.
1727 
1728 --*/
1730 {
1731  READ_CAPACITY_DATA readCapacityBuffer = {0};
1732  NTSTATUS status;
1733  PMDL driveCapMdl;
1734 
1735  driveCapMdl = BuildDeviceInputMdl(&readCapacityBuffer, sizeof(READ_CAPACITY_DATA));
1736  if (driveCapMdl){
1737 
1739  if (pkt){
1740  PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
1741  KEVENT event;
1742  //NTSTATUS pktStatus;
1743  IRP pseudoIrp = {0};
1744 
1745  /*
1746  * Our engine needs an "original irp" to write the status back to
1747  * and to count down packets (one in this case).
1748  * Just use a pretend irp for this.
1749  */
1750  pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
1751  pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
1752  pseudoIrp.IoStatus.Information = 0;
1753  pseudoIrp.MdlAddress = driveCapMdl;
1754 
1755  /*
1756  * Set this up as a SYNCHRONOUS transfer, submit it,
1757  * and wait for the packet to complete. The result
1758  * status will be written to the original irp.
1759  */
1762  &readCapacityBuffer,
1763  sizeof(READ_CAPACITY_DATA),
1764  &event,
1765  &pseudoIrp);
1766  SubmitTransferPacket(pkt);
1768 
1769  status = pseudoIrp.IoStatus.Status;
1770 
1771  /*
1772  * If we got an UNDERRUN, retry exactly once.
1773  * (The transfer_packet engine didn't retry because the result
1774  * status was success).
1775  */
1776  if (NT_SUCCESS(status) &&
1777  (pseudoIrp.IoStatus.Information < sizeof(READ_CAPACITY_DATA))){
1778  DBGERR(("ClassReadDriveCapacity: read len (%xh) < %xh, retrying ...", (ULONG)pseudoIrp.IoStatus.Information, sizeof(READ_CAPACITY_DATA)));
1779 
1780  pkt = DequeueFreeTransferPacket(Fdo, TRUE);
1781  if (pkt){
1782  pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
1783  pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
1784  pseudoIrp.IoStatus.Information = 0;
1787  &readCapacityBuffer,
1788  sizeof(READ_CAPACITY_DATA),
1789  &event,
1790  &pseudoIrp);
1791  SubmitTransferPacket(pkt);
1793  status = pseudoIrp.IoStatus.Status;
1794  if (pseudoIrp.IoStatus.Information < sizeof(READ_CAPACITY_DATA)){
1796  }
1797  }
1798  else {
1800  }
1801  }
1802 
1803 
1804  if (NT_SUCCESS(status)){
1805  /*
1806  * The request succeeded.
1807  * Read out and store the drive information.
1808  */
1809  ULONG cylinderSize;
1810  ULONG bytesPerSector;
1811  ULONG tmp;
1812  ULONG lastSector;
1813 
1814  /*
1815  * Read the bytesPerSector value,
1816  * which is big-endian in the returned buffer.
1817  * Default to the standard 512 bytes.
1818  */
1819  tmp = readCapacityBuffer.BytesPerBlock;
1820  ((PFOUR_BYTE)&bytesPerSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
1821  ((PFOUR_BYTE)&bytesPerSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
1822  ((PFOUR_BYTE)&bytesPerSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
1823  ((PFOUR_BYTE)&bytesPerSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
1824  if (bytesPerSector == 0) {
1825  bytesPerSector = 512;
1826  }
1827  else {
1828  /*
1829  * Clear all but the highest set bit.
1830  * That will give us a bytesPerSector value that is a power of 2.
1831  */
1832  while (bytesPerSector & (bytesPerSector-1)) {
1833  bytesPerSector &= bytesPerSector-1;
1834  }
1835  }
1836  fdoExt->DiskGeometry.BytesPerSector = bytesPerSector;
1837 
1838  //
1839  // Copy last sector in reverse byte order.
1840  //
1841 
1842  tmp = readCapacityBuffer.LogicalBlockAddress;
1843  ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
1844  ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
1845  ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
1846  ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
1847 
1848  //
1849  // Calculate sector to byte shift.
1850  //
1851 
1853 
1854  DebugPrint((2,"SCSI ClassReadDriveCapacity: Sector size is %d\n",
1855  fdoExt->DiskGeometry.BytesPerSector));
1856 
1857  DebugPrint((2,"SCSI ClassReadDriveCapacity: Number of Sectors is %d\n",
1858  lastSector + 1));
1859 
1860  if (fdoExt->DMActive){
1861  DebugPrint((1, "SCSI ClassReadDriveCapacity: reducing number of sectors by %d\n",
1862  fdoExt->DMSkew));
1863  lastSector -= fdoExt->DMSkew;
1864  }
1865 
1866  /*
1867  * Check to see if we have a geometry we should be using already.
1868  */
1869  cylinderSize = (fdoExt->DiskGeometry.TracksPerCylinder *
1870  fdoExt->DiskGeometry.SectorsPerTrack);
1871  if (cylinderSize == 0){
1872  DebugPrint((1, "ClassReadDriveCapacity: resetting H & S geometry "
1873  "values from %#x/%#x to %#x/%#x\n",
1875  fdoExt->DiskGeometry.SectorsPerTrack,
1876  0xff,
1877  0x3f));
1878 
1879  fdoExt->DiskGeometry.TracksPerCylinder = 0xff;
1880  fdoExt->DiskGeometry.SectorsPerTrack = 0x3f;
1881 
1882 
1883  cylinderSize = (fdoExt->DiskGeometry.TracksPerCylinder *
1884  fdoExt->DiskGeometry.SectorsPerTrack);
1885  }
1886 
1887  //
1888  // Calculate number of cylinders.
1889  //
1890 
1891  fdoExt->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/cylinderSize);
1892 
1893  //
1894  // if there are zero cylinders, then the device lied AND it's
1895  // smaller than 0xff*0x3f (about 16k sectors, usually 8 meg)
1896  // this can fit into a single LONGLONG, so create another usable
1897  // geometry, even if it's unusual looking. This allows small,
1898  // non-standard devices, such as Sony's Memory Stick, to show
1899  // up as having a partition.
1900  //
1901 
1902  if (fdoExt->DiskGeometry.Cylinders.QuadPart == (LONGLONG)0) {
1903  fdoExt->DiskGeometry.SectorsPerTrack = 1;
1904  fdoExt->DiskGeometry.TracksPerCylinder = 1;
1905  fdoExt->DiskGeometry.Cylinders.QuadPart = lastSector;
1906  }
1907 
1908 
1909  //
1910  // Calculate media capacity in bytes.
1911  //
1912 
1913  fdoExt->CommonExtension.PartitionLength.QuadPart =
1914  ((LONGLONG)(lastSector + 1)) << fdoExt->SectorShift;
1915 
1916  /*
1917  * Is this removable or fixed media
1918  */
1919  if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
1921  }
1922  else {
1923  fdoExt->DiskGeometry.MediaType = FixedMedia;
1924  }
1925  }
1926  else {
1927  /*
1928  * The request failed.
1929  */
1930 
1931  //
1932  // ISSUE - 2000/02/04 - henrygab - non-512-byte sector sizes and failed geometry update
1933  // what happens when the disk's sector size is bigger than
1934  // 512 bytes and we hit this code path? this is untested.
1935  //
1936  // If the read capacity fails, set the geometry to reasonable parameter
1937  // so things don't fail at unexpected places. Zero the geometry
1938  // except for the bytes per sector and sector shift.
1939  //
1940 
1941  /*
1942  * This request can sometimes fail legitimately
1943  * (e.g. when a SCSI device is attached but turned off)
1944  * so this is not necessarily a device/driver bug.
1945  */
1946  DBGTRACE(ClassDebugWarning, ("ClassReadDriveCapacity on Fdo %xh failed with status %xh.", Fdo, status));
1947 
1948  /*
1949  * Write in a default disk geometry which we HOPE is right (??).
1950  * BUGBUG !!
1951  */
1952  RtlZeroMemory(&fdoExt->DiskGeometry, sizeof(DISK_GEOMETRY));
1953  fdoExt->DiskGeometry.BytesPerSector = 512;
1954  fdoExt->SectorShift = 9;
1955  fdoExt->CommonExtension.PartitionLength.QuadPart = (LONGLONG) 0;
1956 
1957  /*
1958  * Is this removable or fixed media
1959  */
1960  if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
1962  }
1963  else {
1964  fdoExt->DiskGeometry.MediaType = FixedMedia;
1965  }
1966  }
1967 
1968  }
1969  else {
1971  }
1972 
1973  FreeDeviceInputMdl(driveCapMdl);
1974  }
1975  else {
1977  }
1978 
1979  return status;
1980 }
1981 
1982 
1983 /*++////////////////////////////////////////////////////////////////////////////
1984 
1985 ClassSendStartUnit()
1986 
1987 Routine Description:
1988 
1989  Send command to SCSI unit to start or power up.
1990  Because this command is issued asynchronously, that is, without
1991  waiting on it to complete, the IMMEDIATE flag is not set. This
1992  means that the CDB will not return until the drive has powered up.
1993  This should keep subsequent requests from being submitted to the
1994  device before it has completely spun up.
1995 
1996  This routine is called from the InterpretSense routine, when a
1997  request sense returns data indicating that a drive must be
1998  powered up.
1999 
2000  This routine may also be called from a class driver's error handler,
2001  or anytime a non-critical start device should be sent to the device.
2002 
2003 Arguments:
2004 
2005  Fdo - The functional device object for the stopped device.
2006 
2007 Return Value:
2008 
2009  None.
2010 
2011 --*/
2012 VOID
2013 NTAPI
2015  IN PDEVICE_OBJECT Fdo
2016  )
2017 {
2018  PIO_STACK_LOCATION irpStack;
2019  PIRP irp;
2020  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2021  PSCSI_REQUEST_BLOCK srb;
2023  PCDB cdb;
2024 
2025  //
2026  // Allocate Srb from nonpaged pool.
2027  //
2028 
2030  sizeof(COMPLETION_CONTEXT),
2031  '6CcS');
2032 
2033  if(context == NULL) {
2034 
2035  //
2036  // ISSUE-2000/02/03-peterwie
2037  // This code path was inherited from the NT 4.0 class2.sys driver.
2038  // It needs to be changed to survive low-memory conditions.
2039  //
2040 
2041  KeBugCheck(SCSI_DISK_DRIVER_INTERNAL);
2042  }
2043 
2044  //
2045  // Save the device object in the context for use by the completion
2046  // routine.
2047  //
2048 
2049  context->DeviceObject = Fdo;
2050  srb = &context->Srb;
2051 
2052  //
2053  // Zero out srb.
2054  //
2055 
2056  RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
2057 
2058  //
2059  // Write length to SRB.
2060  //
2061 
2062  srb->Length = sizeof(SCSI_REQUEST_BLOCK);
2063 
2065 
2066  //
2067  // Set timeout value large enough for drive to spin up.
2068  //
2069 
2071 
2072  //
2073  // Set the transfer length.
2074  //
2075 
2079 
2080  //
2081  // Build the start unit CDB.
2082  //
2083 
2084  srb->CdbLength = 6;
2085  cdb = (PCDB)srb->Cdb;
2086 
2087  cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
2088  cdb->START_STOP.Start = 1;
2089  cdb->START_STOP.Immediate = 0;
2090  cdb->START_STOP.LogicalUnitNumber = srb->Lun;
2091 
2092  //
2093  // Build the asynchronous request to be sent to the port driver.
2094  // Since this routine is called from a DPC the IRP should always be
2095  // available.
2096  //
2097 
2098  irp = IoAllocateIrp(Fdo->StackSize, FALSE);
2099 
2100  if(irp == NULL) {
2101 
2102  //
2103  // ISSUE-2000/02/03-peterwie
2104  // This code path was inherited from the NT 4.0 class2.sys driver.
2105  // It needs to be changed to survive low-memory conditions.
2106  //
2107 
2108  KeBugCheck(SCSI_DISK_DRIVER_INTERNAL);
2109 
2110  }
2111 
2112  ClassAcquireRemoveLock(Fdo, irp);
2113 
2116  context,
2117  TRUE,
2118  TRUE,
2119  TRUE);
2120 
2121  irpStack = IoGetNextIrpStackLocation(irp);
2122  irpStack->MajorFunction = IRP_MJ_SCSI;
2123  srb->OriginalRequest = irp;
2124 
2125  //
2126  // Store the SRB address in next stack for port driver.
2127  //
2128 
2129  irpStack->Parameters.Scsi.Srb = srb;
2130 
2131  //
2132  // Call the port driver with the IRP.
2133  //
2134 
2135  IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
2136 
2137  return;
2138 
2139 } // end StartUnit()
2140 
2141 /*++////////////////////////////////////////////////////////////////////////////
2142 
2143 ClassAsynchronousCompletion() ISSUE-2000/02/18-henrygab - why public?!
2144 
2145 Routine Description:
2146 
2147  This routine is called when an asynchronous I/O request
2148  which was issued by the class driver completes. Examples of such requests
2149  are release queue or START UNIT. This routine releases the queue if
2150  necessary. It then frees the context and the IRP.
2151 
2152 Arguments:
2153 
2154  DeviceObject - The device object for the logical unit; however since this
2155  is the top stack location the value is NULL.
2156 
2157  Irp - Supplies a pointer to the Irp to be processed.
2158 
2159  Context - Supplies the context to be used to process this request.
2160 
2161 Return Value:
2162 
2163  None.
2164 
2165 --*/
2166 NTSTATUS
2167 NTAPI
2170  PIRP Irp,
2171  PVOID Context
2172  )
2173 {
2175  PSCSI_REQUEST_BLOCK srb;
2176 
2177  if(DeviceObject == NULL) {
2178 
2179  DeviceObject = context->DeviceObject;
2180  }
2181 
2182  srb = &context->Srb;
2183 
2184  //
2185  // If this is an execute srb, then check the return status and make sure.
2186  // the queue is not frozen.
2187  //
2188 
2189  if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
2190 
2191  //
2192  // Check for a frozen queue.
2193  //
2194 
2195  if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2196 
2197  //
2198  // Unfreeze the queue getting the device object from the context.
2199  //
2200 
2201  ClassReleaseQueue(context->DeviceObject);
2202  }
2203  }
2204 
2205  { // free port-allocated sense buffer if we can detect
2206 
2208 
2210  if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
2211  FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
2212  }
2213 
2214  } else {
2215 
2217 
2218  }
2219  }
2220 
2221 
2222  //
2223  // Free the context and the Irp.
2224  //
2225 
2226  if (Irp->MdlAddress != NULL) {
2227  MmUnlockPages(Irp->MdlAddress);
2228  IoFreeMdl(Irp->MdlAddress);
2229 
2230  Irp->MdlAddress = NULL;
2231  }
2232 
2234 
2236  IoFreeIrp(Irp);
2237 
2238  //
2239  // Indicate the I/O system should stop processing the Irp completion.
2240  //
2241 
2243 
2244 } // end ClassAsynchronousCompletion()
2245 
2247 {
2248  //PCOMMON_DEVICE_EXTENSION commonExt = Fdo->DeviceExtension;
2250  PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
2251  //PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExt->PartitionZeroExtension->AdapterDescriptor;
2253  ULONG entireXferLen = currentSp->Parameters.Read.Length;
2254  PUCHAR bufPtr = MmGetMdlVirtualAddress(Irp->MdlAddress);
2255  LARGE_INTEGER targetLocation = currentSp->Parameters.Read.ByteOffset;
2256  PTRANSFER_PACKET pkt;
2257  SINGLE_LIST_ENTRY pktList;
2258  PSINGLE_LIST_ENTRY slistEntry;
2259  ULONG numPackets;
2260  //KIRQL oldIrql;
2261  ULONG i;
2262 
2263  /*
2264  * Compute the number of hw xfers we'll have to do.
2265  * Calculate this without allowing for an overflow condition.
2266  */
2267  ASSERT(fdoData->HwMaxXferLen >= PAGE_SIZE);
2268  numPackets = entireXferLen/fdoData->HwMaxXferLen;
2269  if (entireXferLen % fdoData->HwMaxXferLen){
2270  numPackets++;
2271  }
2272 
2273  /*
2274  * First get all the TRANSFER_PACKETs that we'll need at once.
2275  * Use our 'simple' slist functions since we don't need interlocked.
2276  */
2277  SimpleInitSlistHdr(&pktList);
2278  for (i = 0; i < numPackets; i++){
2279  pkt = DequeueFreeTransferPacket(Fdo, TRUE);
2280  if (pkt){
2281  SimplePushSlist(&pktList, &pkt->SlistEntry);
2282  }
2283  else {
2284  break;
2285  }
2286  }
2287 
2288  if (i == numPackets){
2289  /*
2290  * Initialize the original IRP's status to success.
2291  * If any of the packets fail, they will set it to an error status.
2292  * The IoStatus.Information field will be incremented to the
2293  * transfer length as the pieces complete.
2294  */
2295  Irp->IoStatus.Status = STATUS_SUCCESS;
2296  Irp->IoStatus.Information = 0;
2297 
2298  /*
2299  * Store the number of transfer pieces inside the original IRP.
2300  * It will be used to count down the pieces as they complete.
2301  */
2302  Irp->Tail.Overlay.DriverContext[0] = LongToPtr(numPackets);
2303 
2304  /*
2305  * We are proceeding with the transfer.
2306  * Mark the client IRP pending since it may complete on a different thread.
2307  */
2309 
2310  /*
2311  * Transmit the pieces of the transfer.
2312  */
2313  while (entireXferLen > 0){
2314  ULONG thisPieceLen = MIN(fdoData->HwMaxXferLen, entireXferLen);
2315 
2316  /*
2317  * Set up a TRANSFER_PACKET for this piece and send it.
2318  */
2319  slistEntry = SimplePopSlist(&pktList);
2320  ASSERT(slistEntry);
2321  pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
2323  bufPtr,
2324  thisPieceLen,
2325  targetLocation,
2326  Irp);
2327  SubmitTransferPacket(pkt);
2328 
2329  entireXferLen -= thisPieceLen;
2330  bufPtr += thisPieceLen;
2331  targetLocation.QuadPart += thisPieceLen;
2332  }
2333  ASSERT(SimpleIsSlistEmpty(&pktList));
2334  }
2335  else if (i >= 1){
2336  /*
2337  * We were unable to get all the TRANSFER_PACKETs we need,
2338  * but we did get at least one.
2339  * That means that we are in extreme low-memory stress.
2340  * We'll try doing this transfer using a single packet.
2341  * The port driver is certainly also in stress, so use one-page
2342  * transfers.
2343  */
2344 
2345  /*
2346  * Free all but one of the TRANSFER_PACKETs.
2347  */
2348  while (i-- > 1){
2349  slistEntry = SimplePopSlist(&pktList);
2350  ASSERT(slistEntry);
2351  pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
2352  EnqueueFreeTransferPacket(Fdo, pkt);
2353  }
2354 
2355  /*
2356  * Get the single TRANSFER_PACKET that we'll be using.
2357  */
2358  slistEntry = SimplePopSlist(&pktList);
2359  ASSERT(slistEntry);
2360  ASSERT(SimpleIsSlistEmpty(&pktList));
2361  pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
2362  DBGWARN(("Insufficient packets available in ServiceTransferRequest - entering lowMemRetry with pkt=%xh.", pkt));
2363 
2364  /*
2365  * Set default status and the number of transfer packets (one)
2366  * inside the original irp.
2367  */
2368  Irp->IoStatus.Status = STATUS_SUCCESS;
2369  Irp->IoStatus.Information = 0;
2370  Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1);
2371 
2372  /*
2373  * Mark the client irp pending since it may complete on
2374  * another thread.
2375  */
2377 
2378  /*
2379  * Set up the TRANSFER_PACKET for a lowMem transfer and launch.
2380  */
2382  bufPtr,
2383  entireXferLen,
2384  targetLocation,
2385  Irp);
2386  InitLowMemRetry(pkt, bufPtr, entireXferLen, targetLocation);
2387  StepLowMemRetry(pkt);
2388  }
2389  else {
2390  /*
2391  * We were unable to get ANY TRANSFER_PACKETs.
2392  * Defer this client irp until some TRANSFER_PACKETs free up.
2393  */
2394  DBGWARN(("No packets available in ServiceTransferRequest - deferring transfer (Irp=%xh)...", Irp));
2396  EnqueueDeferredClientIrp(fdoData, Irp);
2397  }
2398 
2399 }
2400 
2401 /*++////////////////////////////////////////////////////////////////////////////
2402 
2403 ClassIoComplete()
2404 
2405 Routine Description:
2406 
2407  This routine executes when the port driver has completed a request.
2408  It looks at the SRB status in the completing SRB and if not success
2409  it checks for valid request sense buffer information. If valid, the
2410  info is used to update status with more precise message of type of
2411  error. This routine deallocates the SRB.
2412 
2413  This routine should only be placed on the stack location for a class
2414  driver FDO.
2415 
2416 Arguments:
2417 
2418  Fdo - Supplies the device object which represents the logical
2419  unit.
2420 
2421  Irp - Supplies the Irp which has completed.
2422 
2423  Context - Supplies a pointer to the SRB.
2424 
2425 Return Value:
2426 
2427  NT status
2428 
2429 --*/
2430 NTSTATUS
2431 NTAPI
2433  IN PDEVICE_OBJECT Fdo,
2434  IN PIRP Irp,
2435  IN PVOID Context
2436  )
2437 {
2440  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2441  PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
2442  NTSTATUS status;
2443  BOOLEAN retry;
2444  BOOLEAN callStartNextPacket;
2445 
2446  ASSERT(fdoExtension->CommonExtension.IsFdo);
2447 
2448  //
2449  // Check SRB status for success of completing request.
2450  //
2451 
2452  if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2453  ULONG retryInterval;
2454 
2455  DebugPrint((2, "ClassIoComplete: IRP %p, SRB %p\n", Irp, srb));
2456 
2457  //
2458  // Release the queue if it is frozen.
2459  //
2460 
2461  if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2462  ClassReleaseQueue(Fdo);
2463  }
2464 
2465  retry = ClassInterpretSenseInfo(
2466  Fdo,
2467  srb,
2468  irpStack->MajorFunction,
2469  irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ?
2470  irpStack->Parameters.DeviceIoControl.IoControlCode :
2471  0,
2472  MAXIMUM_RETRIES -
2473  ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
2474  &status,
2475  &retryInterval);
2476 
2477  //
2478  // If the status is verified required and the this request
2479  // should bypass verify required then retry the request.
2480  //
2481 
2482  if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
2484 
2486  retry = TRUE;
2487  }
2488 
2489  if (retry && ((*(PCHAR*)&irpStack->Parameters.Others.Argument4)--)) {
2490 
2491  //
2492  // Retry request.
2493  //
2494 
2495  DebugPrint((1, "Retry request %p\n", Irp));
2496 
2497  if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
2498  FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
2499  }
2500 
2501  RetryRequest(Fdo, Irp, srb, FALSE, retryInterval);
2503  }
2504 
2505  } else {
2506 
2507  //
2508  // Set status for successful request
2509  //
2511  ClasspPerfIncrementSuccessfulIo(fdoExtension);
2513  } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)
2514 
2515 
2516  //
2517  // ensure we have returned some info, and it matches what the
2518  // original request wanted for PAGING operations only
2519  //
2520 
2521  if ((NT_SUCCESS(status)) && TEST_FLAG(Irp->Flags, IRP_PAGING_IO)) {
2522  ASSERT(Irp->IoStatus.Information != 0);
2523  ASSERT(irpStack->Parameters.Read.Length == Irp->IoStatus.Information);
2524  }
2525 
2526  //
2527  // remember if the caller wanted to skip calling IoStartNextPacket.
2528  // for legacy reasons, we cannot call IoStartNextPacket for IoDeviceControl
2529  // calls. this setting only affects device objects with StartIo routines.
2530  //
2531 
2532  callStartNextPacket = !TEST_FLAG(srb->SrbFlags, SRB_FLAGS_DONT_START_NEXT_PACKET);
2533  if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
2534  callStartNextPacket = FALSE;
2535  }
2536 
2537  //
2538  // Free the srb
2539  //
2540 
2542 
2543  if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
2544  FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
2545  }
2546 
2547  if (fdoExtension->CommonExtension.IsSrbLookasideListInitialized){
2548  ClassFreeOrReuseSrb(fdoExtension, srb);
2549  }
2550  else {
2551  DBGWARN(("ClassIoComplete is freeing an SRB (possibly) on behalf of another driver."));
2552  ExFreePool(srb);
2553  }
2554 
2555  } else {
2556 
2557  DebugPrint((2, "ClassIoComplete: Not Freeing srb @ %p because "
2558  "SRB_CLASS_FLAGS_PERSISTANT set\n", srb));
2559  if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
2560  DebugPrint((2, "ClassIoComplete: Not Freeing sensebuffer @ %p "
2561  " because SRB_CLASS_FLAGS_PERSISTANT set\n",
2562  srb->SenseInfoBuffer));
2563  }
2564 
2565  }
2566 
2567  //
2568  // Set status in completing IRP.
2569  //
2570 
2571  Irp->IoStatus.Status = status;
2572 
2573  //
2574  // Set the hard error if necessary.
2575  //
2576 
2577  if (!NT_SUCCESS(status) &&
2579  (Irp->Tail.Overlay.Thread != NULL)
2580  ) {
2581 
2582  //
2583  // Store DeviceObject for filesystem, and clear
2584  // in IoStatus.Information field.
2585  //
2586 
2588  Irp->IoStatus.Information = 0;
2589  }
2590 
2591  //
2592  // If pending has be returned for this irp then mark the current stack as
2593  // pending.
2594  //
2595 
2596  if (Irp->PendingReturned) {
2598  }
2599 
2600  if (fdoExtension->CommonExtension.DriverExtension->InitData.ClassStartIo) {
2601  if (callStartNextPacket) {
2602  KIRQL oldIrql;
2603  KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
2604  IoStartNextPacket(Fdo, FALSE);
2605  KeLowerIrql(oldIrql);
2606  }
2607  }
2608 
2610 
2611  return status;
2612 
2613 } // end ClassIoComplete()
2614 
2615 /*++////////////////////////////////////////////////////////////////////////////
2616 
2617 ClassSendSrbSynchronous()
2618 
2619 Routine Description:
2620 
2621  This routine is called by SCSI device controls to complete an
2622  SRB and send it to the port driver synchronously (ie wait for
2623  completion). The CDB is already completed along with the SRB CDB
2624  size and request timeout value.
2625 
2626 Arguments:
2627 
2628  Fdo - Supplies the functional device object which represents the target.
2629 
2630  Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
2631 
2632  BufferAddress - Supplies the address of the buffer.
2633 
2634  BufferLength - Supplies the length in bytes of the buffer.
2635 
2636  WriteToDevice - Indicates the data should be transfer to the device.
2637 
2638 Return Value:
2639 
2640  NTSTATUS indicating the final results of the operation.
2641 
2642  If NT_SUCCESS(), then the amount of usable data is contained in the field
2643  Srb->DataTransferLength
2644 
2645 --*/
2646 NTSTATUS
2647 NTAPI
2649  PDEVICE_OBJECT Fdo,
2651  PVOID BufferAddress,
2653  BOOLEAN WriteToDevice
2654  )
2655 {
2656 
2657  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2658  PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
2659  IO_STATUS_BLOCK ioStatus;
2660  //ULONG controlType;
2661  PIRP irp;
2662  PIO_STACK_LOCATION irpStack;
2663  KEVENT event;
2664  PUCHAR senseInfoBuffer;
2665  ULONG retryCount = MAXIMUM_RETRIES;
2666  NTSTATUS status;
2667  BOOLEAN retry;
2668 
2669  //
2670  // NOTE: This code is only pageable because we are not freezing
2671  // the queue. Allowing the queue to be frozen from a pageable
2672  // routine could leave the queue frozen as we try to page in
2673  // the code to unfreeze the queue. The result would be a nice
2674  // case of deadlock. Therefore, since we are unfreezing the
2675  // queue regardless of the result, just set the NO_FREEZE_QUEUE
2676  // flag in the SRB.
2677  //
2678 
2680  ASSERT(fdoExtension->CommonExtension.IsFdo);
2681 
2682  //
2683  // Write length to SRB.
2684  //
2685 
2686  Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
2687 
2688  //
2689  // Set SCSI bus address.
2690  //
2691 
2692  Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2693 
2694  //
2695  // Enable auto request sense.
2696  //
2697 
2698  Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
2699 
2700  //
2701  // Sense buffer is in aligned nonpaged pool.
2702  //
2703  //
2706  '7CcS');
2707 
2708  if (senseInfoBuffer == NULL) {
2709 
2710  DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate request sense "
2711  "buffer\n"));
2713  }
2714 
2715  Srb->SenseInfoBuffer = senseInfoBuffer;
2716  Srb->DataBuffer = BufferAddress;
2717 
2718  //
2719  // Start retries here.
2720  //
2721 
2722 retry:
2723 
2724  //
2725  // use fdoextension's flags by default.
2726  // do not move out of loop, as the flag may change due to errors
2727  // sending this command.
2728  //
2729 
2730  Srb->SrbFlags = fdoExtension->SrbFlags;
2731 
2732  if(BufferAddress != NULL) {
2733  if(WriteToDevice) {
2734  SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT);
2735  } else {
2736  SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
2737  }
2738  }
2739 
2740  //
2741  // Initialize the QueueAction field.
2742  //
2743 
2744  Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
2745 
2746  //
2747  // Disable synchronous transfer for these requests.
2748  // Disable freezing the queue, since all we do is unfreeze it anyways.
2749  //
2750 
2753 
2754  //
2755  // Set the event object to the unsignaled state.
2756  // It will be used to signal request completion.
2757  //
2758 
2760 
2761  //
2762  // Build device I/O control request with METHOD_NEITHER data transfer.
2763  // We'll queue a completion routine to cleanup the MDL's and such ourself.
2764  //
2765 
2766  irp = IoAllocateIrp(
2767  (CCHAR) (fdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1),
2768  FALSE);
2769 
2770  if(irp == NULL) {
2771  ExFreePool(senseInfoBuffer);
2772  DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate Irp\n"));
2774  }
2775 
2776  //
2777  // Get next stack location.
2778  //
2779 
2780  irpStack = IoGetNextIrpStackLocation(irp);
2781 
2782  //
2783  // Set up SRB for execute scsi request. Save SRB address in next stack
2784  // for the port driver.
2785  //
2786 
2787  irpStack->MajorFunction = IRP_MJ_SCSI;
2788  irpStack->Parameters.Scsi.Srb = Srb;
2789 
2792  Srb,
2793  TRUE,
2794  TRUE,
2795  TRUE);
2796 
2797  irp->UserIosb = &ioStatus;
2798  irp->UserEvent = &event;
2799 
2800  if(BufferAddress) {
2801  //
2802  // Build an MDL for the data buffer and stick it into the irp. The
2803  // completion routine will unlock the pages and free the MDL.
2804  //
2805 
2806  irp->MdlAddress = IoAllocateMdl( BufferAddress,
2807  BufferLength,
2808  FALSE,
2809  FALSE,
2810  irp );
2811  if (irp->MdlAddress == NULL) {
2812  ExFreePool(senseInfoBuffer);
2813  Srb->SenseInfoBuffer = NULL;
2814  IoFreeIrp( irp );
2815  DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate MDL\n"));
2817  }
2818 
2819  _SEH2_TRY {
2820 
2821  //
2822  // the io manager unlocks these pages upon completion
2823  //
2824 
2825  MmProbeAndLockPages( irp->MdlAddress,
2826  KernelMode,
2827  (WriteToDevice ? IoReadAccess :
2828  IoWriteAccess));
2829 
2832 
2833  ExFreePool(senseInfoBuffer);
2834  Srb->SenseInfoBuffer = NULL;
2835  IoFreeMdl(irp->MdlAddress);
2836  IoFreeIrp(irp);
2837 
2838  DebugPrint((1, "ClassSendSrbSynchronous: Exception %lx "
2839  "locking buffer\n", status));
2840  _SEH2_YIELD(return status);
2841  } _SEH2_END;
2842  }
2843 
2844  //
2845  // Set the transfer length.
2846  //
2847 
2848  Srb->DataTransferLength = BufferLength;
2849 
2850  //
2851  // Zero out status.
2852  //
2853 
2854  Srb->ScsiStatus = Srb->SrbStatus = 0;
2855  Srb->NextSrb = 0;
2856 
2857  //
2858  // Set up IRP Address.
2859  //
2860 
2861  Srb->OriginalRequest = irp;
2862 
2863  //
2864  // Call the port driver with the request and wait for it to complete.
2865  //
2866 
2867  status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
2868 
2869  if (status == STATUS_PENDING) {
2871  status = ioStatus.Status;
2872  }
2873 
2874  //
2875  // Check that request completed without error.
2876  //
2877 
2878  if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2879 
2880  ULONG retryInterval;
2881 
2882  DBGTRACE(ClassDebugWarning, ("ClassSendSrbSynchronous - srb %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s)", Srb, DBGGETSCSIOPSTR(Srb), DBGGETSRBSTATUSSTR(Srb), (ULONG)Srb->SrbStatus, status, DBGGETSENSECODESTR(Srb), DBGGETADSENSECODESTR(Srb), DBGGETADSENSEQUALIFIERSTR(Srb)));
2883 
2884  //
2885  // assert that the queue is not frozen
2886  //
2887 
2889 
2890  //
2891  // Update status and determine if request should be retried.
2892  //
2893 
2894  retry = ClassInterpretSenseInfo(Fdo,
2895  Srb,
2896  IRP_MJ_SCSI,
2897  0,
2898  MAXIMUM_RETRIES - retryCount,
2899  &status,
2900  &retryInterval);
2901 
2902 
2903  if (retry) {
2904 
2905  if ((status == STATUS_DEVICE_NOT_READY &&
2906  ((PSENSE_DATA) senseInfoBuffer)->AdditionalSenseCode ==
2908  (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) {
2909 
2911 
2912  //
2913  // Delay for at least 2 seconds.
2914  //
2915 
2916  if(retryInterval < 2) {
2917  retryInterval = 2;
2918  }
2919 
2920  delay.QuadPart = (LONGLONG)( - 10 * 1000 * (LONGLONG)1000 * retryInterval);
2921 
2922  //
2923  // Stall for a while to let the device become ready
2924  //
2925 
2927 
2928  }
2929 
2930  //
2931  // If retries are not exhausted then retry this operation.
2932  //
2933 
2934  if (retryCount--) {
2935 
2936  if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) {
2937  FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb);
2938  }
2939 
2940  goto retry;
2941  }
2942  }
2943 
2944  } else {
2947  }
2948 
2949  //
2950  // required even though we allocated our own, since the port driver may
2951  // have allocated one also
2952  //
2953 
2954  if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) {
2955  FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb);
2956  }
2957 
2958  Srb->SenseInfoBuffer = NULL;
2959  ExFreePool(senseInfoBuffer);
2960 
2961  return status;
2962 }
2963 
2964 /*++////////////////////////////////////////////////////////////////////////////
2965 
2966 ClassInterpretSenseInfo()
2967 
2968 Routine Description:
2969 
2970  This routine interprets the data returned from the SCSI
2971  request sense. It determines the status to return in the
2972  IRP and whether this request can be retried.
2973 
2974 Arguments:
2975 
2976  DeviceObject - Supplies the device object associated with this request.
2977 
2978  Srb - Supplies the scsi request block which failed.
2979 
2980  MajorFunctionCode - Supplies the function code to be used for logging.
2981 
2982  IoDeviceCode - Supplies the device code to be used for logging.
2983 
2984  Status - Returns the status for the request.
2985 
2986 Return Value:
2987 
2988  BOOLEAN TRUE: Drivers should retry this request.
2989  FALSE: Drivers should not retry this request.
2990 
2991 --*/
2992 BOOLEAN
2993 NTAPI
2995  IN PDEVICE_OBJECT Fdo,
2999  IN ULONG RetryCount,
3000  OUT NTSTATUS *Status,
3001  OUT OPTIONAL ULONG *RetryInterval
3002  )
3003 {
3004  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3005  PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
3006 
3007  PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
3008 
3009  BOOLEAN retry = TRUE;
3010  BOOLEAN logError = FALSE;
3011  BOOLEAN unhandledError = FALSE;
3012  BOOLEAN incrementErrorCount = FALSE;
3013 
3014  ULONG badSector = 0;
3015  ULONG uniqueId = 0;
3016 
3017  NTSTATUS logStatus;
3018 
3019  ULONG readSector;
3020  ULONG index;
3021 
3022  ULONG retryInterval = 0;
3023  KIRQL oldIrql;
3024 
3025 
3026  logStatus = -1;
3027 
3028  if(TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) {
3029 
3030  //
3031  // Log anything remotely incorrect about paging i/o
3032  //
3033 
3034  logError = TRUE;
3035  uniqueId = 301;
3036  logStatus = IO_WARNING_PAGING_FAILURE;
3037  }
3038 
3039  //
3040  // Check that request sense buffer is valid.
3041  //
3042 
3043  ASSERT(fdoExtension->CommonExtension.IsFdo);
3044 
3045 
3046  //
3047  // must handle the SRB_STATUS_INTERNAL_ERROR case first,
3048  // as it has all the flags set.
3049  //
3050 
3051  if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR) {
3052 
3054  "ClassInterpretSenseInfo: Internal Error code is %x\n",
3055  Srb->InternalStatus));
3056 
3057  retry = FALSE;
3058  *Status = Srb->InternalStatus;
3059 
3060  } else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
3061  (Srb->SenseInfoBufferLength >=
3062  offsetof(SENSE_DATA, CommandSpecificInformation))) {
3063 
3064  //
3065  // Zero the additional sense code and additional sense code qualifier
3066  // if they were not returned by the device.
3067  //
3068 
3069  readSector = senseBuffer->AdditionalSenseLength +
3070  offsetof(SENSE_DATA, AdditionalSenseLength);
3071 
3072  if (readSector > Srb->SenseInfoBufferLength) {
3073  readSector = Srb->SenseInfoBufferLength;
3074  }
3075 
3076  if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCode)) {
3077  senseBuffer->AdditionalSenseCode = 0;
3078  }
3079 
3080  if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCodeQualifier)) {
3081  senseBuffer->AdditionalSenseCodeQualifier = 0;
3082  }
3083 
3085  "ClassInterpretSenseInfo: Error code is %x\n",
3086  senseBuffer->ErrorCode));
3088  "ClassInterpretSenseInfo: Sense key is %x\n",
3089  senseBuffer->SenseKey));
3091  "ClassInterpretSenseInfo: Additional sense code is %x\n",
3092  senseBuffer->AdditionalSenseCode));
3094  "ClassInterpretSenseInfo: Additional sense code qualifier "
3095  "is %x\n",
3096  senseBuffer->AdditionalSenseCodeQualifier));
3097 
3098 
3099  switch (senseBuffer->SenseKey & 0xf) {
3100 
3101  case SCSI_SENSE_NOT_READY: {
3102 
3103  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3104  "Device not ready\n"));
3106 
3107  switch (senseBuffer->AdditionalSenseCode) {
3108 
3110 
3111  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3112  "Lun not ready\n"));
3113 
3114  switch (senseBuffer->AdditionalSenseCodeQualifier) {
3115 
3117  DEVICE_EVENT_BECOMING_READY notReady;
3118 
3119  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3120  "Operation In Progress\n"));
3121  retryInterval = NOT_READY_RETRY_INTERVAL;
3122 
3123  RtlZeroMemory(&notReady, sizeof(DEVICE_EVENT_BECOMING_READY));
3124  notReady.Version = 1;
3125  notReady.Reason = 2;
3126  notReady.Estimated100msToReady = retryInterval * 10;
3127  ClasspSendNotification(fdoExtension,
3128  &GUID_IO_DEVICE_BECOMING_READY,
3130  &notReady);
3131 
3132  break;
3133  }
3134 
3136  DEVICE_EVENT_BECOMING_READY notReady;
3137 
3138  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3139  "In process of becoming ready\n"));
3140  retryInterval = NOT_READY_RETRY_INTERVAL;
3141 
3142  RtlZeroMemory(&notReady, sizeof(DEVICE_EVENT_BECOMING_READY));
3143  notReady.Version = 1;
3144  notReady.Reason = 1;
3145  notReady.Estimated100msToReady = retryInterval * 10;
3146  ClasspSendNotification(fdoExtension,
3147  &GUID_IO_DEVICE_BECOMING_READY,
3149  &notReady);
3150  break;
3151  }
3152 
3154  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3155  "Long write in progress\n"));
3156  retry = FALSE;
3157  break;
3158  }
3159 
3161  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3162  "Manual intervention required\n"));
3164  retry = FALSE;
3165  break;
3166  }
3167 
3169  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3170  "Format in progress\n"));
3171  retry = FALSE;
3172  break;
3173  }
3174 
3176 
3177  if(!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
3179 
3181  "ClassInterpretSenseInfo: "
3182  "not ready, cause unknown\n"));
3183  /*
3184  Many non-WHQL certified drives (mostly CD-RW) return
3185  this when they have no media instead of the obvious
3186  choice of:
3187 
3188  SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
3189 
3190  These drives should not pass WHQL certification due
3191  to this discrepancy.
3192 
3193  */
3194  retry = FALSE;
3195  break;
3196 
3197  } else {
3198 
3199  //
3200  // Treat this as init command required and fall through.
3201  //
3202  }
3203  }
3204 
3206  default: {
3207  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3208  "Initializing command required\n"));
3209 
3210  //
3211  // This sense code/additional sense code
3212  // combination may indicate that the device
3213  // needs to be started. Send an start unit if this
3214  // is a disk device.
3215  //
3216 
3217  if(TEST_FLAG(fdoExtension->DeviceFlags,
3219  !TEST_FLAG(Srb->SrbFlags,
3221  ClassSendStartUnit(Fdo);
3222  }
3223  break;
3224  }
3225 
3226 
3227  } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
3228  break;
3229  }
3230 
3232  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3233  "No Media in device.\n"));
3235  retry = FALSE;
3236 
3237  //
3238  // signal MCN that there isn't any media in the device
3239  //
3240  if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
3241  DebugPrint((ClassDebugError, "ClassInterpretSenseInfo: "
3242  "No Media in a non-removable device %p\n",
3243  Fdo));
3244  }
3246 
3247  break;
3248  }
3249  } // end switch (senseBuffer->AdditionalSenseCode)
3250 
3251  break;
3252  } // end SCSI_SENSE_NOT_READY
3253 
3254  case SCSI_SENSE_DATA_PROTECT: {
3255  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3256  "Media write protected\n"));
3258  retry = FALSE;
3259  break;
3260  } // end SCSI_SENSE_DATA_PROTECT
3261 
3262  case SCSI_SENSE_MEDIUM_ERROR: {
3263  DebugPrint((ClassDebugSenseInfo,"ClassInterpretSenseInfo: "
3264  "Medium Error (bad block)\n"));
3266 
3267  retry = FALSE;
3268  logError = TRUE;
3269  uniqueId = 256;
3270  logStatus = IO_ERR_BAD_BLOCK;
3271 
3272  //
3273  // Check if this error is due to unknown format
3274  //
3275  if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_INVALID_MEDIA){
3276 
3277  switch (senseBuffer->AdditionalSenseCodeQualifier) {
3278 
3280 
3282 
3283  //
3284  // Log error only if this is a paging request
3285  //
3286  if(!TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) {
3287  logError = FALSE;
3288  }
3289  break;
3290  }
3291 
3293 
3295  logError = FALSE;
3296  break;
3297 
3298  }
3299  default: {
3300  break;
3301  }
3302  } // end switch AdditionalSenseCodeQualifier
3303 
3304  } // end SCSI_ADSENSE_INVALID_MEDIA
3305 
3306  break;
3307 
3308  } // end SCSI_SENSE_MEDIUM_ERROR
3309 
3311  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3312  "Hardware error\n"));
3314  logError = TRUE;
3315  uniqueId = 257;
3316  logStatus = IO_ERR_CONTROLLER_ERROR;
3317  break;
3318  } // end SCSI_SENSE_HARDWARE_ERROR
3319 
3321 
3322  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3323  "Illegal SCSI request\n"));
3325  retry = FALSE;
3326 
3327  switch (senseBuffer->AdditionalSenseCode) {
3328 
3330  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3331  "Illegal command\n"));
3332  break;
3333  }
3334 
3336  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3337  "Illegal block address\n"));
3339  break;
3340  }
3341 
3342  case SCSI_ADSENSE_INVALID_LUN: {
3343  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3344  "Invalid LUN\n"));
3346  break;
3347  }
3348 
3349  case SCSI_ADSENSE_MUSIC_AREA: {
3350  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3351  "Music area\n"));
3352  break;
3353  }
3354 
3355  case SCSI_ADSENSE_DATA_AREA: {
3356  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3357  "Data area\n"));
3358  break;
3359  }
3360 
3362  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3363  "Volume overflow\n"));
3364  break;
3365  }
3366 
3368  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3369  "Copy protection failure\n"));
3370 
3372 
3373  switch (senseBuffer->AdditionalSenseCodeQualifier) {
3376  "ClassInterpretSenseInfo: "
3377  "Authentication failure\n"));
3379  break;
3382  "ClassInterpretSenseInfo: "
3383  "Key not present\n"));
3385  break;
3388  "ClassInterpretSenseInfo: "
3389  "Key not established\n"));
3391  break;
3394  "ClassInterpretSenseInfo: "
3395  "Read of scrambled sector w/o "
3396  "authentication\n"));
3398  break;
3401  "ClassInterpretSenseInfo: "
3402  "Media region does not logical unit "
3403  "region\n"));
3405  break;
3408  "ClassInterpretSenseInfo: "
3409  "Region set error -- region may "
3410  "be permanent\n"));
3412  break;
3413  } // end switch of ASCQ for COPY_PROTECTION_FAILURE
3414 
3415  break;
3416  }
3417 
3418 
3419  case SCSI_ADSENSE_INVALID_CDB: {
3420  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3421  "Invalid CDB\n"));
3422 
3423  //
3424  // Note: the retry interval is not typically used.
3425  // it is set here only because a ClassErrorHandler
3426  // cannot set the retryInterval, and the error may
3427  // require a few commands to be sent to clear whatever
3428  // caused this condition (i.e. disk clears the write
3429  // cache, requiring at least two commands)
3430  //
3431  // hopefully, this shortcoming can be changed for
3432  // blackcomb.
3433  //
3434 
3435  retryInterval = 3;
3436  break;
3437  }
3438 
3439  } // end switch (senseBuffer->AdditionalSenseCode)
3440 
3441  break;
3442  } // end SCSI_SENSE_ILLEGAL_REQUEST
3443 
3445 
3446  //PVPB vpb;
3447  ULONG count;
3448 
3449  //
3450  // A media change may have occured so increment the change
3451  // count for the physical device
3452  //
3453 
3454  count = InterlockedIncrement((PLONG)&fdoExtension->MediaChangeCount);
3455  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3456  "Media change count for device %d incremented to %#lx\n",
3457  fdoExtension->DeviceNumber, count));
3458 
3459 
3460  switch (senseBuffer->AdditionalSenseCode) {
3462  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3463  "Media changed\n"));
3464 
3465  if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
3466  DebugPrint((ClassDebugError, "ClassInterpretSenseInfo: "
3467  "Media Changed on non-removable device %p\n",
3468  Fdo));
3469  }
3471  break;
3472  }
3473 
3474  case SCSI_ADSENSE_BUS_RESET: {
3475  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3476  "Bus reset\n"));
3477  break;
3478  }
3479 
3481  switch (senseBuffer->AdditionalSenseCodeQualifier) {
3482 
3484  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3485  "Ejection request received!\n"));
3486  ClassSendEjectionNotification(fdoExtension);
3487  break;
3488  }
3489 
3491  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3492  "Operator selected write permit?! "
3493  "(unsupported!)\n"));
3494  break;
3495  }
3496 
3498  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3499  "Operator selected write protect?! "
3500  "(unsupported!)\n"));
3501  break;
3502  }
3503 
3504  }
3505  break;
3506  }
3507 
3508  default: {
3509  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3510  "Unit attention\n"));
3511  break;
3512  }
3513 
3514  } // end switch (senseBuffer->AdditionalSenseCode)
3515 
3516  if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA))
3517  {
3518  //
3519  // TODO : Is the media lockable?
3520  //
3521 
3522  if ((ClassGetVpb(Fdo) != NULL) && (ClassGetVpb(Fdo)->Flags & VPB_MOUNTED))
3523  {
3524  //
3525  // Set bit to indicate that media may have changed
3526  // and volume needs verification.
3527  //
3528 
3529  SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME);
3530 
3532  retry = FALSE;
3533  }
3534  }
3535  else
3536  {
3538  }
3539 
3540  break;
3541 
3542  } // end SCSI_SENSE_UNIT_ATTENTION
3543 
3545  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3546  "Command aborted\n"));
3548  retryInterval = 1;
3549  break;
3550  } // end SCSI_SENSE_ABORTED_COMMAND
3551 
3552  case SCSI_SENSE_BLANK_CHECK: {
3553  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3554  "Media blank check\n"));
3555  retry = FALSE;
3557  break;
3558  } // end SCSI_SENSE_BLANK_CHECK
3559 
3561 
3562  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3563  "Recovered error\n"));
3565  retry = FALSE;
3566  logError = TRUE;
3567  uniqueId = 258;
3568 
3569  switch(senseBuffer->AdditionalSenseCode) {
3571  case SCSI_ADSENSE_TRACK_ERROR: {
3572  logStatus = IO_ERR_SEEK_ERROR;
3573  break;
3574  }
3575 
3578  logStatus = IO_RECOVERED_VIA_ECC;
3579  break;
3580  }
3581 
3583  UCHAR wmiEventData[5];
3584 
3585  *((PULONG)wmiEventData) = sizeof(UCHAR);
3586  wmiEventData[sizeof(ULONG)] = senseBuffer->AdditionalSenseCodeQualifier;
3587 
3588  //
3589  // Don't log another eventlog if we have already logged once
3590  // NOTE: this should have been interlocked, but the structure
3591  // was publicly defined to use a BOOLEAN (char). Since
3592  // media only reports these errors once per X minutes,
3593  // the potential race condition is nearly non-existant.
3594  // the worst case is duplicate log entries, so ignore.
3595  //
3596 
3597  if (fdoExtension->FailurePredicted == 0) {
3598  logError = TRUE;
3599  }
3600  fdoExtension->FailurePredicted = TRUE;
3601  fdoExtension->FailureReason = senseBuffer->AdditionalSenseCodeQualifier;
3602  logStatus = IO_WRN_FAILURE_PREDICTED;
3603 
3604  ClassNotifyFailurePredicted(fdoExtension,
3605  (PUCHAR)&wmiEventData,
3606  sizeof(wmiEventData),
3607  0,
3608  4,
3609  Srb->PathId,
3610  Srb->TargetId,
3611  Srb->Lun);
3612  break;
3613  }
3614 
3615  default: {
3616  logStatus = IO_ERR_CONTROLLER_ERROR;
3617  break;
3618  }
3619 
3620  } // end switch(senseBuffer->AdditionalSenseCode)
3621 
3622  if (senseBuffer->IncorrectLength) {
3623 
3624  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3625  "Incorrect length detected.\n"));
3627  }
3628 
3629  break;
3630  } // end SCSI_SENSE_RECOVERED_ERROR
3631 
3632  case SCSI_SENSE_NO_SENSE: {
3633 
3634  //
3635  // Check other indicators.
3636  //
3637 
3638  if (senseBuffer->IncorrectLength) {
3639 
3640  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3641  "Incorrect length detected.\n"));
3643  retry = FALSE;
3644 
3645  } else {
3646 
3647  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3648  "No specific sense key\n"));
3650  retry = TRUE;
3651  }
3652 
3653  break;
3654  } // end SCSI_SENSE_NO_SENSE
3655 
3656  default: {
3657  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3658  "Unrecognized sense code\n"));
3660  break;
3661  }
3662 
3663  } // end switch (senseBuffer->SenseKey & 0xf)
3664 
3665  //
3666  // Try to determine the bad sector from the inquiry data.
3667  //
3668 
3669  if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ ||
3670  ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY ||
3671  ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) {
3672 
3673  for (index = 0; index < 4; index++) {
3674  badSector = (badSector << 8) | senseBuffer->Information[index];
3675  }
3676 
3677  readSector = 0;
3678  for (index = 0; index < 4; index++) {
3679  readSector = (readSector << 8) | Srb->Cdb[index+2];
3680  }
3681 
3682  index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) |
3683  ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
3684 
3685  //
3686  // Make sure the bad sector is within the read sectors.
3687  //
3688 
3689  if (!(badSector >= readSector && badSector < readSector + index)) {
3690  badSector = readSector;
3691  }
3692  }
3693 
3694  } else {
3695 
3696  //
3697  // Request sense buffer not valid. No sense information
3698  // to pinpoint the error. Return general request fail.
3699  //
3700 
3701  DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3702  "Request sense info not valid. SrbStatus %2x\n",
3703  SRB_STATUS(Srb->SrbStatus)));
3704  retry = TRUE;
3705 
3706  switch (SRB_STATUS(Srb->SrbStatus)) {
3709  case SRB_STATUS_NO_DEVICE:
3710  case SRB_STATUS_NO_HBA:
3713  retry = FALSE;
3714  break;
3715  }
3716 
3718  case SRB_STATUS_TIMEOUT: {
3719 
3720  //
3721  // Update the error count for the device.
3722  //
3723 
3724  incrementErrorCount = TRUE;
3726  break;
3727  }
3728 
3729  case SRB_STATUS_ABORTED: {
3730 
3731  //
3732  // Update the error count for the device.
3733  //
3734 
3735  incrementErrorCount = TRUE;
3737  retryInterval = 1;
3738  break;
3739  }
3740 
3741 
3743  logError = TRUE;
3744  logStatus = IO_ERR_NOT_READY;
3745  uniqueId = 260;
3747  retry = FALSE;
3748  break;
3749  }
3750 
3751  case SRB_STATUS_DATA_OVERRUN: {
3753  retry = FALSE;
3754  break;
3755  }
3756 
3758 
3759  //
3760  // Update the error count for the device.
3761  //
3762 
3763  incrementErrorCount = TRUE;
3765 
3766  //
3767  // If there was phase sequence error then limit the number of
3768  // retries.
3769  //
3770 
3771  if (RetryCount > 1 ) {
3772  retry = FALSE;
3773  }
3774 
3775  break;
3776  }
3777 
3779 
3780  //
3781  // If the status needs verification bit is set. Then set
3782  // the status to need verification and no retry; otherwise,
3783  // just retry the request.
3784  //
3785 
3786  if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME)) {
3787 
3789  retry = FALSE;
3790 
3791  } else {
3793  }
3794 
3795  break;
3796  }
3797 
3800  retry = FALSE;
3801  break;
3802  }
3803 
3806 
3807  //
3808  // Update the error count for the device
3809  // and fall through to below
3810  //
3811 
3812  incrementErrorCount = TRUE;
3813 
3814  case SRB_STATUS_BUS_RESET: {
3816  break;
3817  }
3818 
3819  case SRB_STATUS_ERROR: {
3820 
3822  if (Srb->ScsiStatus == 0) {
3823 
3824  //
3825  // This is some strange return code. Update the error
3826  // count for the device.
3827  //
3828 
3829  incrementErrorCount = TRUE;
3830 
3831  } if (Srb->ScsiStatus == SCSISTAT_BUSY) {
3832 
3834 
3835  } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) {
3836 
3838  retry = FALSE;
3839  logError = FALSE;
3840 
3841  }
3842 
3843  break;
3844  }
3845 
3846  default: {
3847  logError = TRUE;
3848  logStatus = IO_ERR_CONTROLLER_ERROR;
3849  uniqueId = 259;
3851  unhandledError = TRUE;
3852  break;
3853  }
3854 
3855  }
3856 
3857  //
3858  // NTRAID #183546 - if we support GESN subtype NOT_READY events, and
3859  // we know from a previous poll when the device will be ready (ETA)
3860  // we should delay the retry more appropriately than just guessing.
3861  //
3862  /*
3863  if (fdoExtension->MediaChangeDetectionInfo &&
3864  fdoExtension->MediaChangeDetectionInfo->Gesn.Supported &&
3865  TEST_FLAG(fdoExtension->MediaChangeDetectionInfo->Gesn.EventMask,
3866  NOTIFICATION_DEVICE_BUSY_CLASS_MASK)
3867  ) {
3868  // check if Gesn.ReadyTime if greater than current tick count
3869  // if so, delay that long (from 1 to 30 seconds max?)
3870  // else, leave the guess of time alone.
3871  }
3872  */
3873 
3874  }
3875 
3876  if (incrementErrorCount) {
3877 
3878  //
3879  // if any error count occurred, delay the retry of this io by
3880  // at least one second, if caller supports it.
3881  //
3882 
3883  if (retryInterval == 0) {
3884  retryInterval = 1;
3885  }
3886  ClasspPerfIncrementErrorCount(fdoExtension);
3887  }
3888 
3889  //
3890  // If there is a class specific error handler call it.
3891  //
3892 
3893  if (fdoExtension->CommonExtension.DevInfo->ClassError != NULL) {
3894 
3895  fdoExtension->CommonExtension.DevInfo->ClassError(Fdo,
3896  Srb,
3897  Status,
3898  &retry);
3899  }
3900 
3901  //
3902  // If the caller wants to know the suggested retry interval tell them.
3903  //
3904 
3905  if(ARGUMENT_PRESENT(RetryInterval)) {
3906  *RetryInterval = retryInterval;
3907  }
3908 
3909 
3910  /*
3911  * LOG the error:
3912  * Always log the error in our internal log.
3913  * If logError is set, also log the error in the system log.
3914  */
3915  {
3916  ULONG totalSize;
3917  ULONG senseBufferSize = 0;
3918  IO_ERROR_LOG_PACKET staticErrLogEntry = {0};
3919  CLASS_ERROR_LOG_DATA staticErrLogData = { { { 0 } } };
3920 
3921  //
3922  // Calculate the total size of the error log entry.
3923  // add to totalSize in the order that they are used.
3924  // the advantage to calculating all the sizes here is
3925  // that we don't have to do a bunch of extraneous checks
3926  // later on in this code path.
3927  //
3928  totalSize = sizeof(IO_ERROR_LOG_PACKET) // required
3929  - sizeof(ULONG) // struct includes one ULONG
3930  + sizeof(CLASS_ERROR_LOG_DATA);// struct for ease
3931 
3932  //
3933  // also save any available extra sense data, up to the maximum errlog
3934  // packet size . WMI should be used for real-time analysis.
3935  // the event log should only be used for post-mortem debugging.
3936  //
3937  if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
3938  ULONG validSenseBytes;
3939  BOOLEAN validSense;
3940 
3941  //
3942  // make sure we can at least access the AdditionalSenseLength field
3943  //
3944  validSense = RTL_CONTAINS_FIELD(senseBuffer,
3945  Srb->SenseInfoBufferLength,
3946  AdditionalSenseLength);
3947  if (validSense) {
3948 
3949  //
3950  // if extra info exists, copy the maximum amount of available
3951  // sense data that is safe into the the errlog.
3952  //
3953  validSenseBytes = senseBuffer->AdditionalSenseLength
3954  + offsetof(SENSE_DATA, AdditionalSenseLength);
3955 
3956  //
3957  // this is invalid because it causes overflow!
3958  // whoever sent this type of request would cause
3959  // a system crash.
3960  //
3961  ASSERT(validSenseBytes < MAX_ADDITIONAL_SENSE_BYTES);
3962 
3963  //
3964  // set to save the most sense buffer possible
3965  //
3966  senseBufferSize = max(validSenseBytes, sizeof(SENSE_DATA));
3967  senseBufferSize = min(senseBufferSize, Srb->SenseInfoBufferLength);
3968  } else {
3969  //
3970  // it's smaller than required to read the total number of
3971  // valid bytes, so just use the SenseInfoBufferLength field.
3972  //
3973  senseBufferSize = Srb->SenseInfoBufferLength;
3974  }
3975 
3976  /*
3977  * Bump totalSize by the number of extra senseBuffer bytes
3978  * (beyond the default sense buffer within CLASS_ERROR_LOG_DATA).
3979  * Make sure to never allocate more than ERROR_LOG_MAXIMUM_SIZE.
3980  */
3981  if (senseBufferSize > sizeof(SENSE_DATA)){
3982  totalSize += senseBufferSize-sizeof(SENSE_DATA);
3983  if (totalSize > ERROR_LOG_MAXIMUM_SIZE){
3984  senseBufferSize -= totalSize-ERROR_LOG_MAXIMUM_SIZE;
3985  totalSize = ERROR_LOG_MAXIMUM_SIZE;
3986  }
3987  }
3988  }
3989 
3990  //
3991  // If we've used up all of our retry attempts, set the final status to
3992  // reflect the appropriate result.
3993  //
3994  if (retry && RetryCount < MAXIMUM_RETRIES) {
3995  staticErrLogEntry.FinalStatus = STATUS_SUCCESS;
3996  staticErrLogData.ErrorRetried = TRUE;
3997  } else {
3998  staticErrLogEntry.FinalStatus = *Status;
3999  }
4000  if (TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) {
4001  staticErrLogData.ErrorPaging = TRUE;
4002  }
4003  if (unhandledError) {
4004  staticErrLogData.ErrorUnhandled = TRUE;
4005  }
4006 
4007  //
4008  // Calculate the device offset if there is a geometry.
4009  //
4010  staticErrLogEntry.DeviceOffset.QuadPart = (LONGLONG)badSector;
4011  staticErrLogEntry.DeviceOffset.QuadPart *= (LONGLONG)fdoExtension->DiskGeometry.BytesPerSector;
4012  if (logStatus == -1){
4013  staticErrLogEntry.ErrorCode = STATUS_IO_DEVICE_ERROR;
4014  } else {
4015  staticErrLogEntry.ErrorCode = logStatus;
4016  }
4017 
4018  /*
4019  * The dump data follows the IO_ERROR_LOG_PACKET,
4020  * with the first ULONG of dump data inside the packet.
4021  */
4022  staticErrLogEntry.DumpDataSize = (USHORT)totalSize - sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG);
4023 
4024  staticErrLogEntry.SequenceNumber = 0;
4025  staticErrLogEntry.MajorFunctionCode = MajorFunctionCode;
4026  staticErrLogEntry.IoControlCode = IoDeviceCode;
4027  staticErrLogEntry.RetryCount = (UCHAR) RetryCount;
4028  staticErrLogEntry.UniqueErrorValue = uniqueId;
4029 
4030  KeQueryTickCount(&staticErrLogData.TickCount);
4031  staticErrLogData.PortNumber = (ULONG)-1;
4032 
4033  /*
4034  * Save the entire contents of the SRB.
4035  */
4036  staticErrLogData.Srb = *Srb;
4037 
4038  /*
4039  * For our private log, save just the default length of the SENSE_DATA.
4040  */
4041  if (senseBufferSize != 0){
4042  RtlCopyMemory(&staticErrLogData.SenseData, senseBuffer, min(senseBufferSize, sizeof(SENSE_DATA)));
4043  }
4044 
4045  /*
4046  * Save the error log in our context.
4047  * We only save the default sense buffer length.
4048  */
4049  KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
4050  fdoData->ErrorLogs[fdoData->ErrorLogNextIndex] = staticErrLogData;
4051  fdoData->ErrorLogNextIndex++;
4053  KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
4054 
4055  /*
4056  * If logError is set, also save this log in the system's error log.
4057  * But make sure we don't log TUR failures over and over
4058  * (e.g. if an external drive was switched off and we're still sending TUR's to it every second).
4059  */
4060  if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_TEST_UNIT_READY) && logError){
4061  if (fdoData->LoggedTURFailureSinceLastIO){
4062  logError = FALSE;
4063  }
4064  else {
4065  fdoData->LoggedTURFailureSinceLastIO = TRUE;
4066  }
4067  }
4068  if (logError){
4069  PIO_ERROR_LOG_PACKET errorLogEntry;
4070  PCLASS_ERROR_LOG_DATA errlogData;
4071 
4072  errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(Fdo, (UCHAR)totalSize);
4073  if (errorLogEntry){
4074  errlogData = (PCLASS_ERROR_LOG_DATA)errorLogEntry->DumpData;
4075 
4076  *errorLogEntry = staticErrLogEntry;
4077  *errlogData = staticErrLogData;
4078 
4079  /*
4080  * For the system log, copy as much of the sense buffer as possible.
4081  */
4082  if (senseBufferSize != 0) {
4083  RtlCopyMemory(&errlogData->SenseData, senseBuffer, senseBufferSize);
4084  }
4085 
4086  /*
4087  * Write the error log packet to the system error logging thread.
4088  */
4089  IoWriteErrorLogEntry(errorLogEntry);
4090  }
4091  }
4092  }
4093 
4094  return retry;
4095 
4096 } // end ClassInterpretSenseInfo()
4097 
4098 /*++////////////////////////////////////////////////////////////////////////////
4099 
4100 ClassModeSense()
4101 
4102 Routine Description:
4103 
4104  This routine sends a mode sense command to a target ID and returns
4105  when it is complete.
4106 
4107 Arguments:
4108 
4109  Fdo - Supplies the functional device object associated with this request.
4110 
4111  ModeSenseBuffer - Supplies a buffer to store the sense data.
4112 
4113  Length - Supplies the length in bytes of the mode sense buffer.
4114 
4115  PageMode - Supplies the page or pages of mode sense data to be retrieved.
4116 
4117 Return Value:
4118 
4119  Length of the transferred data is returned.
4120 
4121 --*/
4123  IN PCHAR ModeSenseBuffer,
4124  IN ULONG Length,
4125  IN UCHAR PageMode)
4126 {
4127  ULONG lengthTransferred = 0;
4128  PMDL senseBufferMdl;
4129 
4130  PAGED_CODE();
4131 
4132  senseBufferMdl = BuildDeviceInputMdl(ModeSenseBuffer, Length);
4133  if (senseBufferMdl){
4134 
4136  if (pkt){
4137  KEVENT event;
4138  //NTSTATUS pktStatus;
4139  IRP pseudoIrp = {0};
4140 
4141  /*
4142  * Store the number of packets servicing the irp (one)
4143  * inside the original IRP. It will be used to counted down
4144  * to zero when the packet completes.
4145  * Initialize the original IRP's status to success.
4146  * If the packet fails, we will set it to the error status.
4147  */
4148  pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
4149  pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
4150  pseudoIrp.IoStatus.Information = 0;
4151  pseudoIrp.MdlAddress = senseBufferMdl;
4152 
4153  /*
4154  * Set this up as a SYNCHRONOUS transfer, submit it,
4155  * and wait for the packet to complete. The result
4156  * status will be written to the original irp.
4157  */
4158  ASSERT(Length <= 0x0ff);
4160  SetupModeSenseTransferPacket(pkt, &event, ModeSenseBuffer, (UCHAR)Length, PageMode, &pseudoIrp);
4161  SubmitTransferPacket(pkt);
4163 
4164  if (NT_SUCCESS(pseudoIrp.IoStatus.Status)){
4165  lengthTransferred = (ULONG)pseudoIrp.IoStatus.Information;
4166  }
4167  else {
4168  /*
4169  * This request can sometimes fail legitimately
4170  * (e.g. when a SCSI device is attached but turned off)
4171  * so this is not necessarily a device/driver bug.
4172  */
4173  DBGTRACE(ClassDebugWarning, ("ClassModeSense on Fdo %ph failed with status %xh.", Fdo, pseudoIrp.IoStatus.Status));
4174  }
4175  }
4176 
4177  FreeDeviceInputMdl(senseBufferMdl);
4178  }
4179 
4180  return lengthTransferred;
4181 }
4182 
4183 /*++////////////////////////////////////////////////////////////////////////////
4184 
4185 ClassFindModePage()
4186 
4187 Routine Description:
4188 
4189  This routine scans through the mode sense data and finds the requested
4190  mode sense page code.
4191 
4192 Arguments:
4193  ModeSenseBuffer - Supplies a pointer to the mode sense data.
4194 
4195  Length - Indicates the length of valid data.
4196 
4197  PageMode - Supplies the page mode to be searched for.
4198 
4199  Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
4200 
4201 Return Value:
4202 
4203  A pointer to the the requested mode page. If the mode page was not found
4204  then NULL is return.
4205 
4206 --*/
4207 PVOID
4208 NTAPI
4210  IN PCHAR ModeSenseBuffer,
4211  IN ULONG Length,
4212  IN UCHAR PageMode,
4213  IN BOOLEAN Use6Byte
4214  )
4215 {
4216  PCHAR limit;
4217  ULONG parameterHeaderLength;
4218  PVOID result = NULL;
4219 
4220  limit = ModeSenseBuffer + Length;
4221  parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);
4222 
4223  if (Length >= parameterHeaderLength) {
4224 
4225  PMODE_PARAMETER_HEADER10 modeParam10;
4226  ULONG blockDescriptorLength;
4227 
4228  /*
4229  * Skip the mode select header and block descriptors.
4230  */
4231  if (Use6Byte){
4232  blockDescriptorLength = ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength;
4233  }
4234  else {
4235  modeParam10 = (PMODE_PARAMETER_HEADER10) ModeSenseBuffer;
4236  blockDescriptorLength = modeParam10->BlockDescriptorLength[1];
4237  }
4238 
4239  ModeSenseBuffer += parameterHeaderLength + blockDescriptorLength;
4240 
4241  //
4242  // ModeSenseBuffer now points at pages. Walk the pages looking for the
4243  // requested page until the limit is reached.
4244  //
4245 
4246  while (ModeSenseBuffer +
4248 
4249  if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
4250 
4251  /*
4252  * found the mode page. make sure it's safe to touch it all
4253  * before returning the pointer to caller
4254  */
4255 
4256  if (ModeSenseBuffer + ((PMODE_DISCONNECT_PAGE)ModeSenseBuffer)->PageLength > limit) {
4257  /*
4258  * Return NULL since the page is not safe to access in full
4259  */
4260  result = NULL;
4261  }
4262  else {
4263  result = ModeSenseBuffer;
4264  }
4265  break;
4266  }
4267 
4268  //
4269  // Advance to the next page which is 4-byte-aligned offset after this page.
4270  //
4271  ModeSenseBuffer +=
4272  ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength +
4274 
4275  }
4276  }
4277 
4278  return result;
4279 } // end ClassFindModePage()
4280 
4281 /*++////////////////////////////////////////////////////////////////////////////
4282 
4283 ClassSendSrbAsynchronous()
4284 
4285 Routine Description:
4286 
4287  This routine takes a partially built Srb and an Irp and sends it down to
4288  the port driver.
4289 
4290  This routine must be called with the remove lock held for the specified
4291  Irp.
4292 
4293 Arguments:
4294 
4295  Fdo - Supplies the functional device object for the original request.
4296 
4297  Srb - Supplies a partially built ScsiRequestBlock. In particular, the
4298  CDB and the SRB timeout value must be filled in. The SRB must not be
4299  allocated from zone.
4300 
4301  Irp - Supplies the requesting Irp.
4302 
4303  BufferAddress - Supplies a pointer to the buffer to be transfered.
4304 
4305  BufferLength - Supplies the length of data transfer.
4306 
4307  WriteToDevice - Indicates the data transfer will be from system memory to
4308  device.
4309 
4310 Return Value:
4311 
4312  Returns STATUS_PENDING if the request is dispatched (since the
4313  completion routine may change the irp's status value we cannot simply
4314  return the value of the dispatch)
4315 
4316  or returns a status value to indicate why it failed.
4317 
4318 --*/
4319 NTSTATUS
4320 NTAPI
4322  PDEVICE_OBJECT Fdo,
4324  PIRP Irp,
4325  PVOID BufferAddress,
4327  BOOLEAN WriteToDevice
4328  )
4329 {
4330 
4331  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
4332  PIO_STACK_LOCATION irpStack;
4333 
4334  ULONG savedFlags;
4335 
4336  //
4337  // Write length to SRB.
4338  //
4339 
4340  Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
4341 
4342  //
4343  // Set SCSI bus address.
4344  //
4345 
4346  Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4347 
4348  //
4349  // This is a violation of the SCSI spec but it is required for
4350  // some targets.
4351  //
4352 
4353  // Srb->Cdb[1] |= deviceExtension->Lun << 5;
4354 
4355  //
4356  // Indicate auto request sense by specifying buffer and size.
4357  //
4358 
4359  Srb->SenseInfoBuffer = fdoExtension->SenseData;
4360  Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
4361  Srb->DataBuffer = BufferAddress;
4362 
4363  //
4364  // Save the class driver specific flags away.
4365  //
4366 
4367  savedFlags = Srb->SrbFlags & SRB_FLAGS_CLASS_DRIVER_RESERVED;
4368 
4369  //
4370  // Allow the caller to specify that they do not wish
4371  // IoStartNextPacket() to be called in the completion routine.
4372  //
4373 
4374  SET_FLAG(savedFlags, (Srb->SrbFlags & SRB_FLAGS_DONT_START_NEXT_PACKET));
4375 
4376  if (BufferAddress != NULL) {
4377 
4378  //
4379  // Build Mdl if necessary.
4380  //
4381 
4382  if (Irp->MdlAddress == NULL) {
4383 
4384  if (IoAllocateMdl(BufferAddress,
4385  BufferLength,
4386  FALSE,
4387  FALSE,
4388  Irp) == NULL) {
4389 
4390  Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
4391 
4392  //
4393  // ClassIoComplete() would have free'd the srb
4394  //
4395 
4396  if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) {
4397  FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb);
4398  }
4399  ClassFreeOrReuseSrb(fdoExtension, Srb);
4402 
4404  }
4405 
4406  MmBuildMdlForNonPagedPool(Irp->MdlAddress);
4407 
4408  } else {
4409 
4410  //
4411  // Make sure the buffer requested matches the MDL.
4412  //
4413 
4414  ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress));
4415  }
4416 
4417  //
4418  // Set read flag.
4419  //
4420 
4421  Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
4422 
4423  } else {
4424 
4425  //
4426  // Clear flags.
4427  //
4428 
4429  Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
4430  }
4431 
4432  //
4433  // Restore saved flags.
4434  //
4435 
4436  SET_FLAG(Srb->SrbFlags, savedFlags);
4437 
4438  //
4439  // Disable synchronous transfer for these requests.
4440  //
4441 
4443 
4444  //
4445  // Set the transfer length.
4446  //
4447 
4448  Srb->DataTransferLength = BufferLength;
4449 
4450  //
4451  // Zero out status.
4452  //
4453 
4454  Srb->ScsiStatus = Srb->SrbStatus = 0;
4455 
4456  Srb->NextSrb = 0;
4457 
4458  //
4459  // Save a few parameters in the current stack location.
4460  //
4461 
4462  irpStack = IoGetCurrentIrpStackLocation(Irp);
4463 
4464  //
4465  // Save retry count in current Irp stack.
4466  //
4467 
4468  irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
4469 
4470  //
4471  // Set up IoCompletion routine address.
4472  //
4473 
4475 
4476  //
4477  // Get next stack location and
4478  // set major function code.
4479  //
4480 
4481  irpStack = IoGetNextIrpStackLocation(Irp);
4482 
4483  irpStack->MajorFunction = IRP_MJ_SCSI;
4484 
4485  //
4486  // Save SRB address in next stack for port driver.
4487  //
4488 
4489  irpStack->Parameters.Scsi.Srb = Srb;
4490 
4491  //
4492  // Set up Irp Address.
4493  //
4494 
4495  Srb->OriginalRequest = Irp;
4496 
4497  //
4498  // Call the port driver to process the request.
4499  //
4500 
4502 
4503  IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
4504 
4505  return STATUS_PENDING;
4506 
4507 } // end ClassSendSrbAsynchronous()
4508 
4509 /*++////////////////////////////////////////////////////////////////////////////
4510 
4511 ClassDeviceControlDispatch()
4512 
4513 Routine Description:
4514 
4515  The routine is the common class driver device control dispatch entry point.
4516  This routine is invokes the device-specific drivers DeviceControl routine,
4517  (which may call the Class driver's common DeviceControl routine).
4518 
4519 Arguments:
4520 
4521  DeviceObject - Supplies a pointer to the device object for this request.
4522 
4523  Irp - Supplies the Irp making the request.
4524 
4525 Return Value:
4526 
4527  Returns the status returned from the device-specific driver.
4528 
4529 --*/
4530 NTSTATUS
4531 NTAPI
4534  PIRP Irp
4535  )
4536 {
4537 
4539  ULONG isRemoved;
4540 
4541  isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
4542 
4543  if(isRemoved) {
4544 
4546 
4547  Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
4550  }
4551 
4552  //
4553  // Call the class specific driver DeviceControl routine.
4554  // If it doesn't handle it, it will call back into ClassDeviceControl.
4555  //
4556 
4557  ASSERT(commonExtension->DevInfo->ClassDeviceControl);
4558 
4559  return commonExtension->DevInfo->ClassDeviceControl(DeviceObject,Irp);
4560 } // end ClassDeviceControlDispatch()
4561 
4562 /*++////////////////////////////////////////////////////////////////////////////
4563 
4564 ClassDeviceControl()
4565 
4566 Routine Description:
4567 
4568  The routine is the common class driver device control dispatch function.
4569  This routine is called by a class driver when it get an unrecognized
4570  device control request. This routine will perform the correct action for
4571  common requests such as lock media. If the device request is unknown it
4572  passed down to the next level.
4573 
4574  This routine must be called with the remove lock held for the specified
4575  irp.
4576 
4577 Arguments:
4578 
4579  DeviceObject - Supplies a pointer to the device object for this request.
4580 
4581  Irp - Supplies the Irp making the request.
4582 
4583 Return Value:
4584 
4585  Returns back a STATUS_PENDING or a completion status.
4586 
4587 --*/
4588 NTSTATUS
4589 NTAPI
4592  PIRP Irp
4593  )
4594 {
4596 
4598  PIO_STACK_LOCATION nextStack = NULL;
4599 
4600  ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
4601 
4602  PSCSI_REQUEST_BLOCK srb = NULL;
4603  PCDB cdb = NULL;
4604 
4605  NTSTATUS status;
4606  ULONG modifiedIoControlCode;
4607 
4608  //
4609  // If this is a pass through I/O control, set the minor function code
4610  // and device address and pass it to the port driver.
4611  //
4612 
4613  if ((controlCode == IOCTL_SCSI_PASS_THROUGH) ||
4614  (controlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) {
4615 
4616  //PSCSI_PASS_THROUGH scsiPass;
4617 
4618  //
4619  // Validate the user buffer.
4620  //
4621  #if defined (_WIN64)
4622 
4623  if (IoIs32bitProcess(Irp)) {
4624 
4625  if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)){
4626 
4627  Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4628 
4631 
4633  goto SetStatusAndReturn;
4634  }
4635  }
4636  else
4637  #endif
4638  {
4639  if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4640  sizeof(SCSI_PASS_THROUGH)) {
4641 
4642  Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4643 
4646 
4648  goto SetStatusAndReturn;
4649  }
4650  }
4651 
4653 
4654  nextStack = IoGetNextIrpStackLocation(Irp);
4655  nextStack->MinorFunction = 1;
4656 
4658 
4659  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
4660  goto SetStatusAndReturn;
4661  }
4662 
4663  Irp->IoStatus.Information = 0;
4664 
4665  switch (controlCode) {
4666 
4668 
4669  PMOUNTDEV_UNIQUE_ID uniqueId;
4670 
4671  if (!commonExtension->MountedDeviceInterfaceName.Buffer) {
4673  break;
4674  }
4675 
4676  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4677  sizeof(MOUNTDEV_UNIQUE_ID)) {
4678 
4680  Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
4681  break;
4682  }
4683 
4684  uniqueId = Irp->AssociatedIrp.SystemBuffer;
4685  uniqueId->UniqueIdLength =
4686  commonExtension->MountedDeviceInterfaceName.Length;
4687 
4688  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4689  sizeof(USHORT) + uniqueId->UniqueIdLength) {
4690 
4692  Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
4693  break;
4694  }
4695 
4696  RtlCopyMemory(uniqueId->UniqueId,
4697  commonExtension->MountedDeviceInterfaceName.Buffer,
4698  uniqueId->UniqueIdLength);
4699 
4701  Irp->IoStatus.Information = sizeof(USHORT) +
4702  uniqueId->UniqueIdLength;
4703  break;
4704  }
4705 
4707 
4709 
4710  ASSERT(commonExtension->DeviceName.Buffer);
4711 
4712  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4713  sizeof(MOUNTDEV_NAME)) {
4714 
4716  Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
4717  break;
4718  }
4719 
4720  name = Irp->AssociatedIrp.SystemBuffer;
4721  name->NameLength = commonExtension->DeviceName.Length;
4722 
4723  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4724  sizeof(USHORT) + name->NameLength) {
4725 
4727  Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
4728  break;
4729  }
4730 
4731  RtlCopyMemory(name->Name, commonExtension->DeviceName.Buffer,
4732  name->NameLength);
4733 
4735  Irp->IoStatus.Information = sizeof(USHORT) + name->NameLength;
4736  break;
4737  }
4738 
4740 
4741  PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName;
4742  WCHAR driveLetterNameBuffer[10];
4743  RTL_QUERY_REGISTRY_TABLE queryTable[2];
4744  PWSTR valueName;
4745  UNICODE_STRING driveLetterName;
4746 
4747  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4748  sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) {
4749 
4751  Irp->IoStatus.Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
4752  break;
4753  }
4754 
4755  valueName = ExAllocatePoolWithTag(
4756  PagedPool,
4757  commonExtension->DeviceName.Length + sizeof(WCHAR),
4758  '8CcS');
4759 
4760  if (!valueName) {
4762  break;
4763  }
4764 
4765  RtlCopyMemory(valueName, commonExtension->DeviceName.Buffer,
4766  commonExtension->DeviceName.Length);
4767  valueName[commonExtension->DeviceName.Length/sizeof(WCHAR)] = 0;
4768 
4769  driveLetterName.Buffer = driveLetterNameBuffer;
4770  driveLetterName.MaximumLength = 20;
4771  driveLetterName.Length = 0;
4772 
4773  RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
4774  queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED |
4776  queryTable[0].Name = valueName;
4777  queryTable[0].EntryContext = &driveLetterName;
4778 
4780  L"\\Registry\\Machine\\System\\DISK",
4781  queryTable, NULL, NULL);
4782 
4783  if (!NT_SUCCESS(status)) {
4784  ExFreePool(valueName);
4785  break;
4786  }
4787 
4788  if (driveLetterName.Length == 4 &&
4789  driveLetterName.Buffer[0] == '%' &&
4790  driveLetterName.Buffer[1] == ':') {
4791 
4792  driveLetterName.Buffer[0] = 0xFF;
4793 
4794  } else if (driveLetterName.Length != 4 ||
4795  driveLetterName.Buffer[0] < FirstDriveLetter ||
4796  driveLetterName.Buffer[0] > LastDriveLetter ||
4797  driveLetterName.Buffer[1] != ':') {
4798 
4800  ExFreePool(valueName);
4801  break;
4802  }
4803 
4804  suggestedName = Irp->AssociatedIrp.SystemBuffer;
4805  suggestedName->UseOnlyIfThereAreNoOtherLinks = TRUE;
4806  suggestedName->NameLength = 28;
4807 
4808  Irp->IoStatus.Information =
4810 
4811  if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4812  Irp->IoStatus.Information) {
4813 
4814  Irp->IoStatus.Information =
4817  ExFreePool(valueName);
4818  break;
4819  }
4820 
4822  L"\\Registry\\Machine\\System\\DISK",
4823  valueName);
4824 
4825  ExFreePool(valueName);
4826 
4827  RtlCopyMemory(suggestedName->Name, L"\\DosDevices\\", 24);
4828  suggestedName->Name[12] = driveLetterName.Buffer[0];
4829  suggestedName->Name[13] = ':';
4830 
4831  //
4832  // NT_SUCCESS(status) based on RtlQueryRegistryValues
4833  //
4835 
4836  break;
4837  }
4838 
4839  default:
4841  break;
4842  }
4843 
4844  if (status != STATUS_PENDING) {
4846  Irp->IoStatus.Status = status;
4848  return status;
4849  }
4850 
4851  if (commonExtension->IsFdo){
4852 
4853  PULONG_PTR function;
4854 
4856  sizeof(SCSI_REQUEST_BLOCK) +
4857  (sizeof(ULONG_PTR) * 2),
4858  '9CcS');
4859 
4860  if (srb == NULL) {
4861 
4862  Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
4866  goto SetStatusAndReturn;
4867  }
4868 
4869  RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
4870 
4871  cdb = (PCDB)srb->Cdb;
4872 
4873  //
4874  // Save the function code and the device object in the memory after
4875  // the SRB.
4876  //
4877 
4878  function = (PULONG_PTR) ((PSCSI_REQUEST_BLOCK) (srb + 1));
4879  *function = (ULONG_PTR) DeviceObject;
4880  function++;
4881  *function = (ULONG_PTR) controlCode;
4882 
4883  } else {
4884  srb = NULL;
4885  }
4886 
4887  //
4888  // Change the device type to storage for the switch statement, but only
4889  // if from a legacy device type
4890  //
4891 
4892  if (((controlCode & 0xffff0000) == (IOCTL_DISK_BASE << 16)) ||
4893  ((controlCode & 0xffff0000) == (IOCTL_TAPE_BASE << 16)) ||
4894  ((controlCode & 0xffff0000) == (IOCTL_CDROM_BASE << 16))
4895  ) {
4896 
4897  modifiedIoControlCode = (controlCode & ~0xffff0000);
4898  modifiedIoControlCode |= (IOCTL_STORAGE_BASE << 16);
4899 
4900  } else {
4901 
4902  modifiedIoControlCode = controlCode;
4903 
4904  }
4905 
4906  DBGTRACE(ClassDebugTrace, ("> ioctl %xh (%s)", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode)));
4907 
4908  switch (modifiedIoControlCode) {
4909 
4911 
4912  if (srb) {
4913  ExFreePool(srb);
4914  srb = NULL;
4915  }
4916 
4917  if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4918  sizeof(STORAGE_HOTPLUG_INFO)) {
4919 
4920  //
4921  // Indicate unsuccessful status and no data transferred.
4922  //
4923 
4924  Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
4925  Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO);
4926 
4930 
4931  } else if(!commonExtension->IsFdo) {
4932 
4933  //
4934  // Just forward this down and return
4935  //
4936 
4938 
4940  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
4941 
4942  } else {
4943 
4944  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
4946 
4947  fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension;
4948  info = Irp->AssociatedIrp.SystemBuffer;
4949 
4950  *info = fdoExtension->PrivateFdoData->HotplugInfo;
4951  Irp->IoStatus.Status = STATUS_SUCCESS;
4952  Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO);
4956 
4957  }
4958  break;
4959  }
4960 
4962 
4963  if (srb)
4964  {
4965  ExFreePool(srb);
4966  srb = NULL;
4967  }
4968 
4969  if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4970  sizeof(STORAGE_HOTPLUG_INFO)) {
4971 
4972  //
4973  // Indicate unsuccessful status and no data transferred.
4974  //
4975 
4976  Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
4977 
4981  goto SetStatusAndReturn;
4982 
4983  }
4984 
4985  if(!commonExtension->IsFdo) {
4986 
4987  //
4988  // Just forward this down and return
4989  //
4990 
4992 
4994  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
4995 
4996  } else {
4997 
4998  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension;
4999  PSTORAGE_HOTPLUG_INFO info = Irp->AssociatedIrp.SystemBuffer;
5000 
5002 
5003  if (info->Size != fdoExtension->PrivateFdoData->HotplugInfo.Size)
5004  {
5006  }
5007 
5008  if (info->MediaRemovable != fdoExtension->PrivateFdoData->HotplugInfo.MediaRemovable)
5009  {
5011  }
5012 
5013  if (info->MediaHotplug != fdoExtension->PrivateFdoData->HotplugInfo.MediaHotplug)
5014  {
5016  }
5017 
5018  if (info->WriteCacheEnableOverride != fdoExtension->PrivateFdoData->HotplugInfo.WriteCacheEnableOverride)
5019  {
5021  }
5022 
5023  if (NT_SUCCESS(status))
5024  {
5025  fdoExtension->PrivateFdoData->HotplugInfo.DeviceHotplug = info->DeviceHotplug;
5026 
5027  //
5028  // Store the user-defined override in the registry
5029  //
5030 
5031  ClassSetDeviceParameter(fdoExtension,
5035  }
5036 
5037  Irp->IoStatus.Status = status;
5038 
5041  }
5042 
5043  break;
5044  }
5045 
5048 
5049  PIRP irp2 = NULL;
5050  PIO_STACK_LOCATION newStack;
5051 
5052  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
5053 
5054  DebugPrint((1,"DeviceIoControl: Check verify\n"));
5055 
5056  //
5057  // If a buffer for a media change count was provided, make sure it's
5058  // big enough to hold the result
5059  //
5060 
5061  if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
5062 
5063  //
5064  // If the buffer is too small to hold the media change count
5065  // then return an error to the caller
5066  //
5067 
5068  if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
5069  sizeof(ULONG)) {
5070 
5071  DebugPrint((3,"DeviceIoControl: media count "
5072  "buffer too small\n"));
5073 
5074  Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
5075  Irp->IoStatus.Information = sizeof(ULONG);
5076 
5077  if(srb != NULL) {
5078  ExFreePool(srb);
5079  }
5080 
5083 
5085  goto SetStatusAndReturn;
5086 
5087  }
5088  }
5089 
5090  if(!commonExtension->IsFdo) {
5091 
5092  //
5093  // If this is a PDO then we should just forward the request down
5094  //
5095  ASSERT(!srb);
5096 
5098 
5100 
5101  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5102 
5103  goto SetStatusAndReturn;
5104 
5105  } else {
5106 
5107  fdoExtension = DeviceObject->DeviceExtension;
5108 
5109  }
5110 
5111  if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
5112 
5113  //
5114  // The caller has provided a valid buffer. Allocate an additional
5115  // irp and stick the CheckVerify completion routine on it. We will
5116  // then send this down to the port driver instead of the irp the
5117  // caller sent in
5118  //
5119 
5120  DebugPrint((2,"DeviceIoControl: Check verify wants "
5121  "media count\n"));
5122 
5123  //
5124  // Allocate a new irp to send the TestUnitReady to the port driver
5125  //
5126 
5127  irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE);
5128 
5129  if(irp2 == NULL) {
5130  Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
5131  Irp->IoStatus.Information = 0;
5132  ASSERT(srb);
5133  ExFreePool(srb);
5137  goto SetStatusAndReturn;
5138 
5139  break;
5140  }
5141 
5142  //
5143  // Make sure to acquire the lock for the new irp.
5144  //
5145 
5147 
5148  irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
5150 
5151  //
5152  // Set the top stack location and shove the master Irp into the
5153  // top location
5154  //
5155 
5156  newStack = IoGetCurrentIrpStackLocation(irp2);
5157  newStack->Parameters.Others.Argument1 = Irp;
5158  newStack->DeviceObject = DeviceObject;
5159 
5160  //
5161  // Stick the check verify completion routine onto the stack
5162  // and prepare the irp for the port driver
5163  //
5164 
5167  NULL,
5168  TRUE,
5169  TRUE,
5170  TRUE);
5171 
5173  newStack = IoGetCurrentIrpStackLocation(irp2);
5174  newStack->DeviceObject = DeviceObject;
5175  newStack->MajorFunction = irpStack->MajorFunction;
5176  newStack->MinorFunction = irpStack->MinorFunction;
5177 
5178  //
5179  // Mark the master irp as pending - whether the lower level
5180  // driver completes it immediately or not this should allow it
5181  // to go all the way back up.
5182  //
5183 
5185 
5186  Irp = irp2;
5187 
5188  }
5189 
5190  //
5191  // Test Unit Ready
5192  //
5193 
5194  srb->CdbLength = 6;
5195  cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
5196 
5197  //
5198  // Set timeout value.
5199  //
5200 
5201  srb->TimeOutValue = fdoExtension->TimeOutValue;
5202 
5203  //
5204  // If this was a CV2 then mark the request as low-priority so we don't
5205  // spin up the drive just to satisfy it.
5206  //
5207 
5208  if(controlCode == IOCTL_STORAGE_CHECK_VERIFY2) {
5210  }
5211 
5212  //
5213  // Since this routine will always hand the request to the
5214  // port driver if there isn't a data transfer to be done
5215  // we don't have to worry about completing the request here
5216  // on an error
5217  //
5218 
5219  //
5220  // This routine uses a completion routine so we don't want to release
5221  // the remove lock until then.
5222  //
5223 
5225  srb,
5226  Irp,
5227  NULL,
5228  0,
5229  FALSE);
5230 
5231  break;
5232  }
5233 
5236 
5237  PPREVENT_MEDIA_REMOVAL mediaRemoval = Irp->AssociatedIrp.SystemBuffer;
5238 
5239  DebugPrint((3, "DiskIoControl: ejection control\n"));
5240 
5241  if(srb) {
5242  ExFreePool(srb);
5243  }
5244 
5245  if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
5246  sizeof(PREVENT_MEDIA_REMOVAL)) {
5247 
5248  //
5249  // Indicate unsuccessful status and no data transferred.
5250  //
5251 
5252  Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
5253 
5257  goto SetStatusAndReturn;
5258  }
5259 
5260  if(!commonExtension->IsFdo) {
5261 
5262  //
5263  // Just forward this down and return
5264  //
5265 
5267 
5269  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5270  }
5271  else {
5272 
5273  // i don't believe this assertion is valid. this is a request
5274  // from user-mode, so they could request this for any device
5275  // they want? also, we handle it properly.
5276  // ASSERT(TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA));
5278  DeviceObject,
5279  Irp,
5280  ((modifiedIoControlCode ==
5282  SimpleMediaLock),
5283  mediaRemoval->PreventMediaRemoval);
5284 
5285  Irp->IoStatus.Status = status;
5288  }
5289 
5290  break;
5291  }
5292 
5294 
5295  DebugPrint((3, "DiskIoControl: MCN control\n"));
5296 
5297  if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
5298  sizeof(PREVENT_MEDIA_REMOVAL)) {
5299 
5300  //
5301  // Indicate unsuccessful status and no data transferred.
5302  //
5303 
5304  Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
5305  Irp->IoStatus.Information = 0;
5306 
5307  if(srb) {
5308  ExFreePool(srb);
5309  }
5310 
5314  goto SetStatusAndReturn;
5315  }
5316 
5317  if(!commonExtension->IsFdo) {
5318 
5319  //
5320  // Just forward this down and return
5321  //
5322 
5323  if(srb) {
5324  ExFreePool(srb);
5325  }
5326 
5328 
5330  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5331 
5332  } else {
5333 
5334  //
5335  // Call to the FDO - handle the ejection control.
5336  //
5337 
5339  Irp,
5340  srb);
5341  }
5342  goto SetStatusAndReturn;
5343  }
5344 
5345  case IOCTL_STORAGE_RESERVE:
5346  case IOCTL_STORAGE_RELEASE: {
5347 
5348  //
5349  // Reserve logical unit.
5350  //
5351 
5352  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
5353 
5354  if(!commonExtension->IsFdo) {
5355 
5357 
5359  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5360  goto SetStatusAndReturn;
5361  } else {
5362  fdoExtension = DeviceObject->DeviceExtension;
5363  }
5364 
5365  srb->CdbLength = 6;
5366 
5367  if(modifiedIoControlCode == IOCTL_STORAGE_RESERVE) {
5368  cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT;
5369  } else {
5370  cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT;
5371  }
5372 
5373  //
5374  // Set timeout value.
5375  //
5376 
5377  srb->TimeOutValue = fdoExtension->TimeOutValue;
5378 
5380  srb,
5381  Irp,
5382  NULL,
5383  0,
5384  FALSE);
5385 
5386  break;
5387  }
5388 
5392 
5393  //
5394  // Eject media.
5395  //
5396 
5397  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
5398 
5399  if(!commonExtension->IsFdo) {
5400 
5402 
5404 
5405  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5406  goto SetStatusAndReturn;
5407  } else {
5408  fdoExtension = DeviceObject->DeviceExtension;
5409  }
5410 
5411  if(commonExtension->PagingPathCount != 0) {
5412 
5413  DebugPrint((1, "ClassDeviceControl: call to eject paging device - "
5414  "failure\n"));
5415 
5417  Irp->IoStatus.Status = status;
5418 
5419  Irp->IoStatus.Information = 0;
5420 
5421  if(srb) {
5422  ExFreePool(srb);
5423  }
5424 
5427  goto SetStatusAndReturn;
5428  }
5429 
5430  //
5431  // Synchronize with ejection control and ejection cleanup code as
5432  // well as other eject/load requests.
5433  //
5434 
5437  UserRequest,
5438  UserMode,
5439  FALSE,
5440  NULL);
5441 
5442  if(fdoExtension->ProtectedLockCount != 0) {
5443 
5444  DebugPrint((1, "ClassDeviceControl: call to eject protected locked "
5445  "device - failure\n"));
5446 
5448  Irp->IoStatus.Status = status;
5449  Irp->IoStatus.Information = 0;
5450 
5451  if(srb) {
5452  ExFreePool(srb);
5453  }
5454 
5457 
5458  KeSetEvent(&fdoExtension->EjectSynchronizationEvent,
5460  FALSE);
5462 
5463  goto SetStatusAndReturn;
5464  }
5465 
5466  srb->CdbLength = 6;
5467 
5468  cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
5469  cdb->START_STOP.LoadEject = 1;
5470 
5471  if(modifiedIoControlCode == IOCTL_STORAGE_EJECT_MEDIA) {
5472  cdb->START_STOP.Start = 0;
5473  } else {
5474  cdb->START_STOP.Start = 1;
5475  }
5476 
5477  //
5478  // Set timeout value.
5479  //
5480 
5481  srb->TimeOutValue = fdoExtension->TimeOutValue;
5483  srb,
5484  Irp,
5485  NULL,
5486  0,
5487  FALSE);
5488 
5491 
5492  break;
5493  }
5494 
5496 
5497  if(srb) {
5498  ExFreePool(srb);
5499  }
5500 
5501  if(commonExtension->IsFdo) {
5502 
5504  ((PFUNCTIONAL_DEVICE_EXTENSION) commonExtension)->LowerPdo,
5505  BusRelations);
5506 
5508  Irp->IoStatus.Status = status;
5509 
5512  }
5513  else {
5514 
5516 
5518  status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5519  }
5520  break;
5521  }
5522 
5524 
5525  if(srb) {
5526  ExFreePool(srb);
5527  }
5528 
5529  if(irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
5530  sizeof(STORAGE_DEVICE_NUMBER)) {
5531 
5532  PSTORAGE_DEVICE_NUMBER deviceNumber =
5533  Irp->AssociatedIrp.SystemBuffer;
5534  PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
5535  commonExtension->PartitionZeroExtension;
5536 
5537  deviceNumber->DeviceType = fdoExtension->CommonExtension.DeviceObject->DeviceType;
5538  deviceNumber->DeviceNumber = fdoExtension->DeviceNumber;
5539  deviceNumber->PartitionNumber = commonExtension->PartitionNumber;
5540 
5542  Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER);
5543 
5544  } else {
5546  Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER);
5547  }
5548 
5549  Irp->IoStatus.Status = status;
5552 
5553  break;
5554  }
5555 
5556  default: {
5557 
5558  DebugPrint((4,