[LT2013]
[reactos.git] / drivers / storage / classpnp / class.c
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 #define CLASS_INIT_GUID 1
25 #include "classp.h"
26 #include "debug.h"
27
28 #ifdef ALLOC_PRAGMA
29 #pragma alloc_text(INIT, DriverEntry)
30 #pragma alloc_text(PAGE, ClassAddDevice)
31 #pragma alloc_text(PAGE, ClassClaimDevice)
32 #pragma alloc_text(PAGE, ClassCreateDeviceObject)
33 #pragma alloc_text(PAGE, ClassDispatchPnp)
34 #pragma alloc_text(PAGE, ClassGetDescriptor)
35 #pragma alloc_text(PAGE, ClassGetPdoId)
36 #pragma alloc_text(PAGE, ClassInitialize)
37 #pragma alloc_text(PAGE, ClassInitializeEx)
38 #pragma alloc_text(PAGE, ClassInvalidateBusRelations)
39 #pragma alloc_text(PAGE, ClassMarkChildMissing)
40 #pragma alloc_text(PAGE, ClassMarkChildrenMissing)
41 #pragma alloc_text(PAGE, ClassModeSense)
42 #pragma alloc_text(PAGE, ClassPnpQueryFdoRelations)
43 #pragma alloc_text(PAGE, ClassPnpStartDevice)
44 #pragma alloc_text(PAGE, ClassQueryPnpCapabilities)
45 #pragma alloc_text(PAGE, ClassQueryTimeOutRegistryValue)
46 #pragma alloc_text(PAGE, ClassRemoveDevice)
47 #pragma alloc_text(PAGE, ClassRetrieveDeviceRelations)
48 #pragma alloc_text(PAGE, ClassUpdateInformationInRegistry)
49 #pragma alloc_text(PAGE, ClassSendDeviceIoControlSynchronous)
50 #pragma alloc_text(PAGE, ClassUnload)
51 #pragma alloc_text(PAGE, ClasspAllocateReleaseRequest)
52 #pragma alloc_text(PAGE, ClasspFreeReleaseRequest)
53 #pragma alloc_text(PAGE, ClasspInitializeHotplugInfo)
54 #pragma alloc_text(PAGE, ClasspRegisterMountedDeviceInterface)
55 #pragma alloc_text(PAGE, ClasspScanForClassHacks)
56 #pragma alloc_text(PAGE, ClasspScanForSpecialInRegistry)
57 #endif
58
59 ULONG ClassPnpAllowUnload = TRUE;
60
61
62 #define FirstDriveLetter 'C'
63 #define LastDriveLetter 'Z'
64
65
66
67 /*++////////////////////////////////////////////////////////////////////////////
68
69 DriverEntry()
70
71 Routine Description:
72
73 Temporary entry point needed to initialize the class system dll.
74 It doesn't do anything.
75
76 Arguments:
77
78 DriverObject - Pointer to the driver object created by the system.
79
80 Return Value:
81
82 STATUS_SUCCESS
83
84 --*/
85 NTSTATUS
86 NTAPI
87 DriverEntry(
88 IN PDRIVER_OBJECT DriverObject,
89 IN PUNICODE_STRING RegistryPath
90 )
91 {
92 return STATUS_SUCCESS;
93 }
94
95 /*++////////////////////////////////////////////////////////////////////////////
96
97 ClassInitialize()
98
99 Routine Description:
100
101 This routine is called by a class driver during its
102 DriverEntry routine to initialize the driver.
103
104 Arguments:
105
106 Argument1 - Driver Object.
107 Argument2 - Registry Path.
108 InitializationData - Device-specific driver's initialization data.
109
110 Return Value:
111
112 A valid return code for a DriverEntry routine.
113
114 --*/
115 ULONG
116 NTAPI
117 ClassInitialize(
118 IN PVOID Argument1,
119 IN PVOID Argument2,
120 IN PCLASS_INIT_DATA InitializationData
121 )
122 {
123 PDRIVER_OBJECT DriverObject = Argument1;
124 PUNICODE_STRING RegistryPath = Argument2;
125
126 PCLASS_DRIVER_EXTENSION driverExtension;
127
128 NTSTATUS status;
129
130 PAGED_CODE();
131
132 DebugPrint((3,"\n\nSCSI Class Driver\n"));
133
134 ClasspInitializeDebugGlobals();
135
136 //
137 // Validate the length of this structure. This is effectively a
138 // version check.
139 //
140
141 if (InitializationData->InitializationDataSize != sizeof(CLASS_INIT_DATA)) {
142
143 //
144 // This DebugPrint is to help third-party driver writers
145 //
146
147 DebugPrint((0,"ClassInitialize: Class driver wrong version\n"));
148 return (ULONG) STATUS_REVISION_MISMATCH;
149 }
150
151 //
152 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
153 // are not required entry points.
154 //
155
156 if ((!InitializationData->FdoData.ClassDeviceControl) ||
157 (!((InitializationData->FdoData.ClassReadWriteVerification) ||
158 (InitializationData->ClassStartIo))) ||
159 (!InitializationData->ClassAddDevice) ||
160 (!InitializationData->FdoData.ClassStartDevice)) {
161
162 //
163 // This DebugPrint is to help third-party driver writers
164 //
165
166 DebugPrint((0,
167 "ClassInitialize: Class device-specific driver missing required "
168 "FDO entry\n"));
169
170 return (ULONG) STATUS_REVISION_MISMATCH;
171 }
172
173 if ((InitializationData->ClassEnumerateDevice) &&
174 ((!InitializationData->PdoData.ClassDeviceControl) ||
175 (!InitializationData->PdoData.ClassStartDevice) ||
176 (!((InitializationData->PdoData.ClassReadWriteVerification) ||
177 (InitializationData->ClassStartIo))))) {
178
179 //
180 // This DebugPrint is to help third-party driver writers
181 //
182
183 DebugPrint((0, "ClassInitialize: Class device-specific missing "
184 "required PDO entry\n"));
185
186 return (ULONG) STATUS_REVISION_MISMATCH;
187 }
188
189 if((InitializationData->FdoData.ClassStopDevice == NULL) ||
190 ((InitializationData->ClassEnumerateDevice != NULL) &&
191 (InitializationData->PdoData.ClassStopDevice == NULL))) {
192
193 //
194 // This DebugPrint is to help third-party driver writers
195 //
196
197 DebugPrint((0, "ClassInitialize: Class device-specific missing "
198 "required PDO entry\n"));
199 ASSERT(FALSE);
200 return (ULONG) STATUS_REVISION_MISMATCH;
201 }
202
203 //
204 // Setup the default power handlers if the class driver didn't provide
205 // any.
206 //
207
208 if(InitializationData->FdoData.ClassPowerDevice == NULL) {
209 InitializationData->FdoData.ClassPowerDevice = ClassMinimalPowerHandler;
210 }
211
212 if((InitializationData->ClassEnumerateDevice != NULL) &&
213 (InitializationData->PdoData.ClassPowerDevice == NULL)) {
214 InitializationData->PdoData.ClassPowerDevice = ClassMinimalPowerHandler;
215 }
216
217 //
218 // warn that unload is not supported
219 //
220 // ISSUE-2000/02/03-peterwie
221 // We should think about making this a fatal error.
222 //
223
224 if(InitializationData->ClassUnload == NULL) {
225
226 //
227 // This DebugPrint is to help third-party driver writers
228 //
229
230 DebugPrint((0, "ClassInitialize: driver does not support unload %wZ\n",
231 RegistryPath));
232 }
233
234 //
235 // Create an extension for the driver object
236 //
237
238 status = IoAllocateDriverObjectExtension(DriverObject,
239 CLASS_DRIVER_EXTENSION_KEY,
240 sizeof(CLASS_DRIVER_EXTENSION),
241 &driverExtension);
242
243 if(NT_SUCCESS(status)) {
244
245 //
246 // Copy the registry path into the driver extension so we can use it later
247 //
248
249 driverExtension->RegistryPath.Length = RegistryPath->Length;
250 driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
251
252 driverExtension->RegistryPath.Buffer =
253 ExAllocatePoolWithTag(PagedPool,
254 RegistryPath->MaximumLength,
255 '1CcS');
256
257 if(driverExtension->RegistryPath.Buffer == NULL) {
258
259 status = STATUS_INSUFFICIENT_RESOURCES;
260 return status;
261 }
262
263 RtlCopyUnicodeString(
264 &(driverExtension->RegistryPath),
265 RegistryPath);
266
267 //
268 // Copy the initialization data into the driver extension so we can reuse
269 // it during our add device routine
270 //
271
272 RtlCopyMemory(
273 &(driverExtension->InitData),
274 InitializationData,
275 sizeof(CLASS_INIT_DATA));
276
277 driverExtension->DeviceCount = 0;
278
279 } else if (status == STATUS_OBJECT_NAME_COLLISION) {
280
281 //
282 // The extension already exists - get a pointer to it
283 //
284
285 driverExtension = IoGetDriverObjectExtension(DriverObject,
286 CLASS_DRIVER_EXTENSION_KEY);
287
288 ASSERT(driverExtension != NULL);
289
290 } else {
291
292 DebugPrint((1, "ClassInitialize: Class driver extension could not be "
293 "allocated %lx\n", status));
294 return status;
295 }
296
297 //
298 // Update driver object with entry points.
299 //
300
301 DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreateClose;
302 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassCreateClose;
303 DriverObject->MajorFunction[IRP_MJ_READ] = ClassReadWrite;
304 DriverObject->MajorFunction[IRP_MJ_WRITE] = ClassReadWrite;
305 DriverObject->MajorFunction[IRP_MJ_SCSI] = ClassInternalIoControl;
306 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControlDispatch;
307 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ClassShutdownFlush;
308 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ClassShutdownFlush;
309 DriverObject->MajorFunction[IRP_MJ_PNP] = ClassDispatchPnp;
310 DriverObject->MajorFunction[IRP_MJ_POWER] = ClassDispatchPower;
311 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ClassSystemControl;
312
313 if (InitializationData->ClassStartIo) {
314 DriverObject->DriverStartIo = ClasspStartIo;
315 }
316
317 if ((InitializationData->ClassUnload) && (ClassPnpAllowUnload == TRUE)) {
318 DriverObject->DriverUnload = ClassUnload;
319 } else {
320 DriverObject->DriverUnload = NULL;
321 }
322
323 DriverObject->DriverExtension->AddDevice = ClassAddDevice;
324
325 DbgPrint("Driver is ready to go\n");
326 status = STATUS_SUCCESS;
327 return status;
328 } // end ClassInitialize()
329
330 /*++////////////////////////////////////////////////////////////////////////////
331
332 ClassInitializeEx()
333
334 Routine Description:
335
336 This routine is allows the caller to do any extra initialization or
337 setup that is not done in ClassInitialize. The operation is
338 controlled by the GUID that is passed and the contents of the Data
339 parameter is dependent upon the GUID.
340
341 This is the list of supported operations:
342
343 Guid - GUID_CLASSPNP_QUERY_REGINFOEX
344 Data - A PCLASS_QUERY_WMI_REGINFO_EX callback function pointer
345
346 Initialized classpnp to callback a PCLASS_QUERY_WMI_REGINFO_EX
347 callback instead of a PCLASS_QUERY_WMI_REGINFO callback. The
348 former callback allows the driver to specify the name of the
349 mof resource.
350
351 Arguments:
352
353 DriverObject
354 Guid
355 Data
356
357 Return Value:
358
359 Status Code
360
361 --*/
362 ULONG
363 NTAPI
364 ClassInitializeEx(
365 IN PDRIVER_OBJECT DriverObject,
366 IN LPGUID Guid,
367 IN PVOID Data
368 )
369 {
370 PCLASS_DRIVER_EXTENSION driverExtension;
371
372 NTSTATUS status;
373
374 PAGED_CODE();
375
376 driverExtension = IoGetDriverObjectExtension( DriverObject,
377 CLASS_DRIVER_EXTENSION_KEY
378 );
379 if (IsEqualGUID(Guid, &ClassGuidQueryRegInfoEx))
380 {
381 PCLASS_QUERY_WMI_REGINFO_EX_LIST List;
382
383 //
384 // Indicate the device supports PCLASS_QUERY_REGINFO_EX
385 // callback instead of PCLASS_QUERY_REGINFO callback.
386 //
387 List = (PCLASS_QUERY_WMI_REGINFO_EX_LIST)Data;
388
389 if (List->Size == sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST))
390 {
391 driverExtension->ClassFdoQueryWmiRegInfoEx = List->ClassFdoQueryWmiRegInfoEx;
392 driverExtension->ClassPdoQueryWmiRegInfoEx = List->ClassPdoQueryWmiRegInfoEx;
393 status = STATUS_SUCCESS;
394 } else {
395 status = STATUS_INVALID_PARAMETER;
396 }
397 } else {
398 status = STATUS_NOT_SUPPORTED;
399 }
400
401 return(status);
402
403 } // end ClassInitializeEx()
404
405 /*++////////////////////////////////////////////////////////////////////////////
406
407 ClassUnload()
408
409 Routine Description:
410
411 called when there are no more references to the driver. this allows
412 drivers to be updated without rebooting.
413
414 Arguments:
415
416 DriverObject - a pointer to the driver object that is being unloaded
417
418 Status:
419
420 --*/
421 VOID
422 NTAPI
423 ClassUnload(
424 IN PDRIVER_OBJECT DriverObject
425 )
426 {
427 PCLASS_DRIVER_EXTENSION driverExtension;
428 //NTSTATUS status;
429
430 PAGED_CODE();
431
432 ASSERT( DriverObject->DeviceObject == NULL );
433
434 driverExtension = IoGetDriverObjectExtension( DriverObject,
435 CLASS_DRIVER_EXTENSION_KEY
436 );
437
438 ASSERT(driverExtension != NULL);
439 ASSERT(driverExtension->RegistryPath.Buffer != NULL);
440 ASSERT(driverExtension->InitData.ClassUnload != NULL);
441
442 DebugPrint((1, "ClassUnload: driver unloading %wZ\n",
443 &driverExtension->RegistryPath));
444
445 //
446 // attempt to process the driver's unload routine first.
447 //
448
449 driverExtension->InitData.ClassUnload(DriverObject);
450
451 //
452 // free own allocated resources and return
453 //
454
455 ExFreePool( driverExtension->RegistryPath.Buffer );
456 driverExtension->RegistryPath.Buffer = NULL;
457 driverExtension->RegistryPath.Length = 0;
458 driverExtension->RegistryPath.MaximumLength = 0;
459
460 return;
461 } // end ClassUnload()
462
463 /*++////////////////////////////////////////////////////////////////////////////
464
465 ClassAddDevice()
466
467 Routine Description:
468
469 SCSI class driver add device routine. This is called by pnp when a new
470 physical device come into being.
471
472 This routine will call out to the class driver to verify that it should
473 own this device then will create and attach a device object and then hand
474 it to the driver to initialize and create symbolic links
475
476 Arguments:
477
478 DriverObject - a pointer to the driver object that this is being created for
479 PhysicalDeviceObject - a pointer to the physical device object
480
481 Status: STATUS_NO_SUCH_DEVICE if the class driver did not want this device
482 STATUS_SUCCESS if the creation and attachment was successful
483 status of device creation and initialization
484
485 --*/
486 NTSTATUS
487 NTAPI
488 ClassAddDevice(
489 IN PDRIVER_OBJECT DriverObject,
490 IN PDEVICE_OBJECT PhysicalDeviceObject
491 )
492 {
493 PCLASS_DRIVER_EXTENSION driverExtension =
494 IoGetDriverObjectExtension(DriverObject,
495 CLASS_DRIVER_EXTENSION_KEY);
496
497 NTSTATUS status;
498
499 PAGED_CODE();
500
501 DbgPrint("got a device\n");
502 status = driverExtension->InitData.ClassAddDevice(DriverObject,
503 PhysicalDeviceObject);
504 return status;
505 } // end ClassAddDevice()
506
507 /*++////////////////////////////////////////////////////////////////////////////
508
509 ClassDispatchPnp()
510
511 Routine Description:
512
513 Storage class driver pnp routine. This is called by the io system when
514 a PNP request is sent to the device.
515
516 Arguments:
517
518 DeviceObject - pointer to the device object
519
520 Irp - pointer to the io request packet
521
522 Return Value:
523
524 status
525
526 --*/
527 NTSTATUS
528 NTAPI
529 ClassDispatchPnp(
530 IN PDEVICE_OBJECT DeviceObject,
531 IN PIRP Irp
532 )
533 {
534 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
535 BOOLEAN isFdo = commonExtension->IsFdo;
536
537 PCLASS_DRIVER_EXTENSION driverExtension;
538 PCLASS_INIT_DATA initData;
539 PCLASS_DEV_INFO devInfo;
540
541 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
542 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
543
544 NTSTATUS status = Irp->IoStatus.Status;
545 BOOLEAN completeRequest = TRUE;
546 BOOLEAN lockReleased = FALSE;
547
548 ULONG isRemoved;
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,
558 CLASS_DRIVER_EXTENSION_KEY);
559 if (driverExtension){
560
561 initData = &(driverExtension->InitData);
562
563 if(isFdo) {
564 devInfo = &(initData->FdoData);
565 } else {
566 devInfo = &(initData->PdoData);
567 }
568
569 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
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 {
594 status = STATUS_SUCCESS;
595 }
596
597 if (NT_SUCCESS(status)){
598 status = Irp->IoStatus.Status = ClassPnpStartDevice(DeviceObject);
599 }
600
601 break;
602 }
603
604
605 case IRP_MN_QUERY_DEVICE_RELATIONS: {
606
607 DEVICE_RELATION_TYPE type =
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
620 status = STATUS_INSUFFICIENT_RESOURCES;
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
637 status = STATUS_SUCCESS;
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
672 status = ClassPnpQueryFdoRelations(DeviceObject, Irp);
673
674 if(!NT_SUCCESS(status)) {
675 completeRequest = TRUE;
676 break;
677 }
678 }
679 }
680
681 IoCopyCurrentIrpStackLocationToNext(Irp);
682 ClassReleaseRemoveLock(DeviceObject, Irp);
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
701 IoCopyCurrentIrpStackLocationToNext(Irp);
702 ClassReleaseRemoveLock(DeviceObject, Irp);
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
715 status = ClassGetPdoId(DeviceObject,
716 idType,
717 &unicodeString);
718
719 if(status == STATUS_NOT_IMPLEMENTED) {
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
736 case IRP_MN_QUERY_STOP_DEVICE:
737 case IRP_MN_QUERY_REMOVE_DEVICE: {
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));
754 status = STATUS_DEVICE_BUSY;
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) {
764 status = devInfo->ClassStopDevice(DeviceObject,
765 irpStack->MinorFunction);
766 } else {
767 status = devInfo->ClassRemoveDevice(DeviceObject,
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 severly 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
795 case IRP_MN_CANCEL_STOP_DEVICE:
796 case IRP_MN_CANCEL_REMOVE_DEVICE: {
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) {
804 status = devInfo->ClassStopDevice(DeviceObject,
805 irpStack->MinorFunction);
806 ASSERTMSG("ClassDispatchPnp !! CANCEL_STOP_DEVICE should "
807 "never be failed\n", NT_SUCCESS(status));
808 } else {
809 status = devInfo->ClassRemoveDevice(DeviceObject,
810 irpStack->MinorFunction);
811 ASSERTMSG("ClassDispatchPnp !! CANCEL_REMOVE_DEVICE should "
812 "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) {
837 IoCopyCurrentIrpStackLocationToNext(Irp);
838 ClassReleaseRemoveLock(DeviceObject, Irp);
839 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
840 completeRequest = FALSE;
841 } else {
842 status = STATUS_SUCCESS;
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) {
874 IoStopTimer(DeviceObject);
875 }
876
877 status = devInfo->ClassStopDevice(DeviceObject, IRP_MN_STOP_DEVICE);
878
879 ASSERTMSG("ClassDispatchPnp !! STOP_DEVICE should "
880 "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
894 case IRP_MN_REMOVE_DEVICE:
895 case IRP_MN_SURPRISE_REMOVAL: {
896
897 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
898 UCHAR removeType = irpStack->MinorFunction;
899
900 if (commonExtension->PagingPathCount != 0) {
901 DBGTRACE(ClassDebugWarning, ("ClassDispatchPnp (%p,%p): paging device is getting removed!", DeviceObject, Irp));
902 }
903
904 //
905 // Release the lock for this IRP before calling in.
906 //
907 ClassReleaseRemoveLock(DeviceObject, Irp);
908 lockReleased = TRUE;
909
910 /*
911 * If a timer was started on the device, stop it.
912 */
913 if (DeviceObject->Timer) {
914 IoStopTimer(DeviceObject);
915 }
916
917 /*
918 * "Fire-and-forget" the remove irp to the lower stack.
919 * Don't touch the irp (or the irp stack!) after this.
920 */
921 if (isFdo) {
922 IoCopyCurrentIrpStackLocationToNext(Irp);
923 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
924 ASSERT(NT_SUCCESS(status));
925 completeRequest = FALSE;
926 }
927 else {
928 status = STATUS_SUCCESS;
929 }
930
931 /*
932 * Do our own cleanup and call the class driver's remove
933 * cleanup routine.
934 * For IRP_MN_REMOVE_DEVICE, this also deletes our device object,
935 * so don't touch the extension after this.
936 */
937 commonExtension->PreviousState = commonExtension->CurrentState;
938 commonExtension->CurrentState = removeType;
939 ClassRemoveDevice(DeviceObject, removeType);
940
941 break;
942 }
943
944 case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
945
946 switch(irpStack->Parameters.UsageNotification.Type) {
947
948 case DeviceUsageTypePaging: {
949
950 BOOLEAN setPagable;
951
952 if((irpStack->Parameters.UsageNotification.InPath) &&
953 (commonExtension->CurrentState != IRP_MN_START_DEVICE)) {
954
955 //
956 // Device isn't started. Don't allow adding a
957 // paging file, but allow a removal of one.
958 //
959
960 status = STATUS_DEVICE_NOT_READY;
961 break;
962 }
963
964 ASSERT(commonExtension->IsInitialized);
965
966 //
967 // need to synchronize this now...
968 //
969
970 KeEnterCriticalRegion();
971 status = KeWaitForSingleObject(&commonExtension->PathCountEvent,
972 Executive, KernelMode,
973 FALSE, NULL);
974 ASSERT(NT_SUCCESS(status));
975 status = STATUS_SUCCESS;
976
977 //
978 // If the volume is removable we should try to lock it in
979 // place or unlock it once per paging path count
980 //
981
982 if (commonExtension->IsFdo){
983 status = ClasspEjectionControl(
984 DeviceObject,
985 Irp,
986 InternalMediaLock,
987 (BOOLEAN)irpStack->Parameters.UsageNotification.InPath);
988 }
989
990 if (!NT_SUCCESS(status)){
991 KeSetEvent(&commonExtension->PathCountEvent, IO_NO_INCREMENT, FALSE);
992 KeLeaveCriticalRegion();
993 break;
994 }
995
996 //
997 // if removing last paging device, need to set DO_POWER_PAGABLE
998 // bit here, and possible re-set it below on failure.
999 //
1000
1001 setPagable = FALSE;
1002
1003 if (!irpStack->Parameters.UsageNotification.InPath &&
1004 commonExtension->PagingPathCount == 1
1005 ) {
1006
1007 //
1008 // removing last paging file
1009 // must have DO_POWER_PAGABLE bits set, but only
1010 // if noone set the DO_POWER_INRUSH bit
1011 //
1012
1013
1014 if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) {
1015 DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
1016 "paging file removed, but "
1017 "DO_POWER_INRUSH was set, so NOT "
1018 "setting DO_POWER_PAGABLE\n",
1019 DeviceObject, Irp));
1020 } else {
1021 DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
1022 "paging file removed, "
1023 "setting DO_POWER_PAGABLE\n",
1024 DeviceObject, Irp));
1025 SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
1026 setPagable = TRUE;
1027 }
1028
1029 }
1030
1031 //
1032 // forward the irp before finishing handling the
1033 // special cases
1034 //
1035
1036 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1037
1038 //
1039 // now deal with the failure and success cases.
1040 // note that we are not allowed to fail the irp
1041 // once it is sent to the lower drivers.
1042 //
1043
1044 if (NT_SUCCESS(status)) {
1045
1046 IoAdjustPagingPathCount(
1047 &commonExtension->PagingPathCount,
1048 irpStack->Parameters.UsageNotification.InPath);
1049
1050 if (irpStack->Parameters.UsageNotification.InPath) {
1051 if (commonExtension->PagingPathCount == 1) {
1052 DebugPrint((2, "ClassDispatchPnp (%p,%p): "
1053 "Clearing PAGABLE bit\n",
1054 DeviceObject, Irp));
1055 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
1056 }
1057 }
1058
1059 } else {
1060
1061 //
1062 // cleanup the changes done above
1063 //
1064
1065 if (setPagable == TRUE) {
1066 DebugPrint((2, "ClassDispatchPnp (%p,%p): Unsetting "
1067 "PAGABLE bit due to irp failure\n",
1068 DeviceObject, Irp));
1069 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
1070 setPagable = FALSE;
1071 }
1072
1073 //
1074 // relock or unlock the media if needed.
1075 //
1076
1077 if (commonExtension->IsFdo) {
1078
1079 ClasspEjectionControl(
1080 DeviceObject,
1081 Irp,
1082 InternalMediaLock,
1083 (BOOLEAN)!irpStack->Parameters.UsageNotification.InPath);
1084 }
1085 }
1086
1087 //
1088 // set the event so the next one can occur.
1089 //
1090
1091 KeSetEvent(&commonExtension->PathCountEvent,
1092 IO_NO_INCREMENT, FALSE);
1093 KeLeaveCriticalRegion();
1094 break;
1095 }
1096
1097 case DeviceUsageTypeHibernation: {
1098
1099 IoAdjustPagingPathCount(
1100 &commonExtension->HibernationPathCount,
1101 irpStack->Parameters.UsageNotification.InPath
1102 );
1103 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1104 if (!NT_SUCCESS(status)) {
1105 IoAdjustPagingPathCount(
1106 &commonExtension->HibernationPathCount,
1107 !irpStack->Parameters.UsageNotification.InPath
1108 );
1109 }
1110
1111 break;
1112 }
1113
1114 case DeviceUsageTypeDumpFile: {
1115 IoAdjustPagingPathCount(
1116 &commonExtension->DumpPathCount,
1117 irpStack->Parameters.UsageNotification.InPath
1118 );
1119 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1120 if (!NT_SUCCESS(status)) {
1121 IoAdjustPagingPathCount(
1122 &commonExtension->DumpPathCount,
1123 !irpStack->Parameters.UsageNotification.InPath
1124 );
1125 }
1126
1127 break;
1128 }
1129
1130 default: {
1131 status = STATUS_INVALID_PARAMETER;
1132 break;
1133 }
1134 }
1135 break;
1136 }
1137
1138 case IRP_MN_QUERY_CAPABILITIES: {
1139
1140 DebugPrint((2, "ClassDispatchPnp (%p,%p): QueryCapabilities\n",
1141 DeviceObject, Irp));
1142
1143 if(!isFdo) {
1144
1145 status = ClassQueryPnpCapabilities(
1146 DeviceObject,
1147 irpStack->Parameters.DeviceCapabilities.Capabilities
1148 );
1149
1150 break;
1151
1152 } else {
1153
1154 PDEVICE_CAPABILITIES deviceCapabilities;
1155 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
1156 PCLASS_PRIVATE_FDO_DATA fdoData;
1157
1158 fdoExtension = DeviceObject->DeviceExtension;
1159 fdoData = fdoExtension->PrivateFdoData;
1160 deviceCapabilities =
1161 irpStack->Parameters.DeviceCapabilities.Capabilities;
1162
1163 //
1164 // forward the irp before handling the special cases
1165 //
1166
1167 status = ClassForwardIrpSynchronous(commonExtension, Irp);
1168 if (!NT_SUCCESS(status)) {
1169 break;
1170 }
1171
1172 //
1173 // we generally want to remove the device from the hotplug
1174 // applet, which requires the SR-OK bit to be set.
1175 // only when the user specifies that they are capable of
1176 // safely removing things do we want to clear this bit
1177 // (saved in WriteCacheEnableOverride)
1178 //
1179 // setting of this bit is done either above, or by the
1180 // lower driver.
1181 //
1182 // note: may not be started, so check we have FDO data first.
1183 //
1184
1185 if (fdoData &&
1186 fdoData->HotplugInfo.WriteCacheEnableOverride) {
1187 if (deviceCapabilities->SurpriseRemovalOK) {
1188 DebugPrint((1, "Classpnp: Clearing SR-OK bit in "
1189 "device capabilities due to hotplug "
1190 "device or media\n"));
1191 }
1192 deviceCapabilities->SurpriseRemovalOK = FALSE;
1193 }
1194 break;
1195
1196 } // end QUERY_CAPABILITIES for FDOs
1197
1198 ASSERT(FALSE);
1199 break;
1200
1201
1202 } // end QUERY_CAPABILITIES
1203
1204 default: {
1205
1206 if (isFdo){
1207 IoCopyCurrentIrpStackLocationToNext(Irp);
1208
1209 ClassReleaseRemoveLock(DeviceObject, Irp);
1210 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
1211
1212 completeRequest = FALSE;
1213 }
1214
1215 break;
1216 }
1217 }
1218 }
1219 else {
1220 ASSERT(driverExtension);
1221 status = STATUS_INTERNAL_ERROR;
1222 }
1223
1224 if (completeRequest){
1225 Irp->IoStatus.Status = status;
1226
1227 if (!lockReleased){
1228 ClassReleaseRemoveLock(DeviceObject, Irp);
1229 }
1230
1231 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1232
1233 DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving with previous %#x, current %#x.", DeviceObject, Irp, commonExtension->PreviousState, commonExtension->CurrentState));
1234 }
1235 else {
1236 /*
1237 * The irp is already completed so don't touch it.
1238 * This may be a remove so don't touch the device extension.
1239 */
1240 DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving.", DeviceObject, Irp));
1241 }
1242
1243 return status;
1244 } // end ClassDispatchPnp()
1245
1246 /*++////////////////////////////////////////////////////////////////////////////
1247
1248 ClassPnpStartDevice()
1249
1250 Routine Description:
1251
1252 Storage class driver routine for IRP_MN_START_DEVICE requests.
1253 This routine kicks off any device specific initialization
1254
1255 Arguments:
1256
1257 DeviceObject - a pointer to the device object
1258
1259 Irp - a pointer to the io request packet
1260
1261 Return Value:
1262
1263 none
1264
1265 --*/
1266 NTSTATUS NTAPI ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject)
1267 {
1268 PCLASS_DRIVER_EXTENSION driverExtension;
1269 PCLASS_INIT_DATA initData;
1270
1271 PCLASS_DEV_INFO devInfo;
1272
1273 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1274 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1275 BOOLEAN isFdo = commonExtension->IsFdo;
1276
1277 BOOLEAN isMountedDevice = TRUE;
1278 //UNICODE_STRING interfaceName;
1279
1280 BOOLEAN timerStarted;
1281
1282 NTSTATUS status = STATUS_SUCCESS;
1283
1284 PAGED_CODE();
1285
1286 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
1287 CLASS_DRIVER_EXTENSION_KEY);
1288
1289 initData = &(driverExtension->InitData);
1290 if(isFdo) {
1291 devInfo = &(initData->FdoData);
1292 } else {
1293 devInfo = &(initData->PdoData);
1294 }
1295
1296 ASSERT(devInfo->ClassInitDevice != NULL);
1297 ASSERT(devInfo->ClassStartDevice != NULL);
1298
1299 if (!commonExtension->IsInitialized){
1300
1301 //
1302 // perform FDO/PDO specific initialization
1303 //
1304
1305 if (isFdo){
1306 STORAGE_PROPERTY_ID propertyId;
1307
1308 //
1309 // allocate a private extension for class data
1310 //
1311
1312 if (fdoExtension->PrivateFdoData == NULL) {
1313 fdoExtension->PrivateFdoData =
1314 ExAllocatePoolWithTag(NonPagedPool,
1315 sizeof(CLASS_PRIVATE_FDO_DATA),
1316 CLASS_TAG_PRIVATE_DATA
1317 );
1318 }
1319
1320 if (fdoExtension->PrivateFdoData == NULL) {
1321 DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for "
1322 "private fdo data\n"));
1323 return STATUS_INSUFFICIENT_RESOURCES;
1324 }
1325
1326 //
1327 // initialize the struct's various fields.
1328 //
1329
1330 RtlZeroMemory(fdoExtension->PrivateFdoData,
1331 sizeof(CLASS_PRIVATE_FDO_DATA)
1332 );
1333 KeInitializeTimer(&fdoExtension->PrivateFdoData->Retry.Timer);
1334 KeInitializeDpc(&fdoExtension->PrivateFdoData->Retry.Dpc,
1335 ClasspRetryRequestDpc,
1336 DeviceObject);
1337 KeInitializeSpinLock(&fdoExtension->PrivateFdoData->Retry.Lock);
1338 fdoExtension->PrivateFdoData->Retry.Granularity =
1339 KeQueryTimeIncrement();
1340 commonExtension->Reserved4 = (ULONG_PTR)(' GPH'); // debug aid
1341
1342 //
1343 // NOTE: the old interface allowed the class driver to allocate
1344 // this. this was unsafe for low-memory conditions. allocate one
1345 // unconditionally now, and modify our internal functions to use
1346 // our own exclusively as it is the only safe way to do this.
1347 //
1348
1349 status = ClasspAllocateReleaseQueueIrp(fdoExtension);
1350 if (!NT_SUCCESS(status)) {
1351 DebugPrint((0, "ClassPnpStartDevice: Cannot allocate the "
1352 "private release queue irp\n"));
1353 return status;
1354 }
1355
1356 //
1357 // Call port driver to get adapter capabilities.
1358 //
1359
1360 propertyId = StorageAdapterProperty;
1361
1362 status = ClassGetDescriptor(
1363 commonExtension->LowerDeviceObject,
1364 &propertyId,
1365 &fdoExtension->AdapterDescriptor);
1366
1367 if(!NT_SUCCESS(status)) {
1368
1369 //
1370 // This DebugPrint is to help third-party driver writers
1371 //
1372
1373 DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor "
1374 "[ADAPTER] failed %lx\n", status));
1375 return status;
1376 }
1377
1378 //
1379 // Call port driver to get device descriptor.
1380 //
1381
1382 propertyId = StorageDeviceProperty;
1383
1384 status = ClassGetDescriptor(
1385 commonExtension->LowerDeviceObject,
1386 &propertyId,
1387 &fdoExtension->DeviceDescriptor);
1388
1389 if(!NT_SUCCESS(status)) {
1390
1391 //
1392 // This DebugPrint is to help third-party driver writers
1393 //
1394
1395 DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor "
1396 "[DEVICE] failed %lx\n", status));
1397 return status;
1398 }
1399
1400 ClasspScanForSpecialInRegistry(fdoExtension);
1401 ClassScanForSpecial(fdoExtension,
1402 ClassBadItems,
1403 ClasspScanForClassHacks);
1404
1405 //
1406 // allow perf to be re-enabled after a given number of failed IOs
1407 // require this number to be at least CLASS_PERF_RESTORE_MINIMUM
1408 //
1409
1410 {
1411 ULONG t = 0;
1412 ClassGetDeviceParameter(fdoExtension,
1413 CLASSP_REG_SUBKEY_NAME,
1414 CLASSP_REG_PERF_RESTORE_VALUE_NAME,
1415 &t);
1416 if (t >= CLASS_PERF_RESTORE_MINIMUM) {
1417 fdoExtension->PrivateFdoData->Perf.ReEnableThreshhold = t;
1418 }
1419 }
1420
1421
1422 //
1423 // compatibility comes first. writable cd media will not
1424 // get a SYNCH_CACHE on power down.
1425 //
1426
1427 if (fdoExtension->DeviceObject->DeviceType != FILE_DEVICE_DISK) {
1428 SET_FLAG(fdoExtension->PrivateFdoData->HackFlags,
1429 FDO_HACK_NO_SYNC_CACHE);
1430 }
1431
1432 //
1433 // initialize the hotplug information only after the ScanForSpecial
1434 // routines, as it relies upon the hack flags.
1435 //
1436
1437 status = ClasspInitializeHotplugInfo(fdoExtension);
1438
1439 if (!NT_SUCCESS(status)) {
1440 DebugPrint((1, "ClassPnpStartDevice: Could not initialize "
1441 "hotplug information %lx\n", status));
1442 return status;
1443 }
1444
1445 /*
1446 * Allocate/initialize TRANSFER_PACKETs and related resources.
1447 */
1448 status = InitializeTransferPackets(DeviceObject);
1449 }
1450
1451 //
1452 // ISSUE - drivers need to disable write caching on the media
1453 // if hotplug and !useroverride. perhaps we should
1454 // allow registration of a callback to enable/disable
1455 // write cache instead.
1456 //
1457
1458 if (NT_SUCCESS(status)){
1459 status = devInfo->ClassInitDevice(DeviceObject);
1460 }
1461
1462 }
1463
1464 if (!NT_SUCCESS(status)){
1465
1466 //
1467 // Just bail out - the remove that comes down will clean up the
1468 // initialized scraps.
1469 //
1470
1471 return status;
1472 } else {
1473 commonExtension->IsInitialized = TRUE;
1474
1475 if (commonExtension->IsFdo) {
1476 fdoExtension->PrivateFdoData->Perf.OriginalSrbFlags = fdoExtension->SrbFlags;
1477 }
1478
1479 }
1480
1481 //
1482 // If device requests autorun functionality or a once a second callback
1483 // then enable the once per second timer.
1484 //
1485 // NOTE: This assumes that ClassInitializeMediaChangeDetection is always
1486 // called in the context of the ClassInitDevice callback. If called
1487 // after then this check will have already been made and the
1488 // once a second timer will not have been enabled.
1489 //
1490 if ((isFdo) &&
1491 ((initData->ClassTick != NULL) ||
1492 (fdoExtension->MediaChangeDetectionInfo != NULL) ||
1493 ((fdoExtension->FailurePredictionInfo != NULL) &&
1494 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone))))
1495 {
1496 ClasspEnableTimer(DeviceObject);
1497 timerStarted = TRUE;
1498 } else {
1499 timerStarted = FALSE;
1500 }
1501
1502 //
1503 // NOTE: the timer looks at commonExtension->CurrentState now
1504 // to prevent Media Change Notification code from running
1505 // until the device is started, but allows the device
1506 // specific tick handler to run. therefore it is imperative
1507 // that commonExtension->CurrentState not be updated until
1508 // the device specific startdevice handler has finished.
1509 //
1510
1511 status = devInfo->ClassStartDevice(DeviceObject);
1512
1513 if(NT_SUCCESS(status)) {
1514 commonExtension->CurrentState = IRP_MN_START_DEVICE;
1515
1516 if((isFdo) && (initData->ClassEnumerateDevice != NULL)) {
1517 isMountedDevice = FALSE;
1518 }
1519
1520 if((DeviceObject->DeviceType != FILE_DEVICE_DISK) &&
1521 (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)) {
1522
1523 isMountedDevice = FALSE;
1524 }
1525
1526
1527 if(isMountedDevice) {
1528 ClasspRegisterMountedDeviceInterface(DeviceObject);
1529 }
1530
1531 if((commonExtension->IsFdo) &&
1532 (devInfo->ClassWmiInfo.GuidRegInfo != NULL)) {
1533
1534 IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_REGISTER);
1535 }
1536 } else {
1537
1538 if (timerStarted) {
1539 ClasspDisableTimer(DeviceObject);
1540 }
1541 }
1542
1543 return status;
1544 }
1545
1546
1547 /*++////////////////////////////////////////////////////////////////////////////
1548
1549 ClassReadWrite()
1550
1551 Routine Description:
1552
1553 This is the system entry point for read and write requests. The
1554 device-specific handler is invoked to perform any validation necessary.
1555
1556 If the device object is a PDO (partition object) then the request will
1557 simply be adjusted for Partition0 and issued to the lower device driver.
1558
1559 IF the device object is an FDO (paritition 0 object), the number of bytes
1560 in the request are checked against the maximum byte counts that the adapter
1561 supports and requests are broken up into
1562 smaller sizes if necessary.
1563
1564 Arguments:
1565
1566 DeviceObject - a pointer to the device object for this request
1567
1568 Irp - IO request
1569
1570 Return Value:
1571
1572 NT Status
1573
1574 --*/
1575 NTSTATUS NTAPI ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
1576 {
1577 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
1578 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
1579 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1580 //LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
1581 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1582 ULONG isRemoved;
1583 NTSTATUS status;
1584
1585 /*
1586 * Grab the remove lock. If we can't acquire it, bail out.
1587 */
1588 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
1589 if (isRemoved) {
1590 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
1591 ClassReleaseRemoveLock(DeviceObject, Irp);
1592 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1593 status = STATUS_DEVICE_DOES_NOT_EXIST;
1594 }
1595 else if (TEST_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME) &&
1596 (currentIrpStack->MinorFunction != CLASSP_VOLUME_VERIFY_CHECKED) &&
1597 !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)){
1598
1599 /*
1600 * DO_VERIFY_VOLUME is set for the device object,
1601 * but this request is not itself a verify request.
1602 * So fail this request.
1603 */
1604 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1605 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1606 Irp->IoStatus.Information = 0;
1607 ClassReleaseRemoveLock(DeviceObject, Irp);
1608 ClassCompleteRequest(DeviceObject, Irp, 0);
1609 status = STATUS_VERIFY_REQUIRED;
1610 }
1611 else {
1612
1613 /*
1614 * Since we've bypassed the verify-required tests we don't need to repeat
1615 * them with this IRP - in particular we don't want to worry about
1616 * hitting them at the partition 0 level if the request has come through
1617 * a non-zero partition.
1618 */
1619 currentIrpStack->MinorFunction = CLASSP_VOLUME_VERIFY_CHECKED;
1620
1621 /*
1622 * Call the miniport driver's pre-pass filter to check if we
1623 * should continue with this transfer.
1624 */
1625 ASSERT(commonExtension->DevInfo->ClassReadWriteVerification);
1626 status = commonExtension->DevInfo->ClassReadWriteVerification(DeviceObject, Irp);
1627 if (!NT_SUCCESS(status)){
1628 ASSERT(Irp->IoStatus.Status == status);
1629 ClassReleaseRemoveLock(DeviceObject, Irp);
1630 ClassCompleteRequest (DeviceObject, Irp, IO_NO_INCREMENT);
1631 }
1632 else if (status == STATUS_PENDING){
1633 /*
1634 * ClassReadWriteVerification queued this request.
1635 * So don't touch the irp anymore.
1636 */
1637 }
1638 else {
1639
1640 if (transferByteCount == 0) {
1641 /*
1642 * Several parts of the code turn 0 into 0xffffffff,
1643 * so don't process a zero-length request any further.
1644 */
1645 Irp->IoStatus.Status = STATUS_SUCCESS;
1646 Irp->IoStatus.Information = 0;
1647 ClassReleaseRemoveLock(DeviceObject, Irp);
1648 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
1649 status = STATUS_SUCCESS;
1650 }
1651 else {
1652 /*
1653 * If the driver has its own StartIo routine, call it.
1654 */
1655 if (commonExtension->DriverExtension->InitData.ClassStartIo) {
1656 IoMarkIrpPending(Irp);
1657 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1658 status = STATUS_PENDING;
1659 }
1660 else {
1661 /*
1662 * The driver does not have its own StartIo routine.
1663 * So process this request ourselves.
1664 */
1665
1666 /*
1667 * Add partition byte offset to make starting byte relative to
1668 * beginning of disk.
1669 */
1670 currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
1671 commonExtension->StartingOffset.QuadPart;
1672
1673 if (commonExtension->IsFdo){
1674
1675 /*
1676 * Add in any skew for the disk manager software.
1677 */
1678 currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
1679 commonExtension->PartitionZeroExtension->DMByteSkew;
1680
1681 /*
1682 * Perform the actual transfer(s) on the hardware
1683 * to service this request.
1684 */
1685 ServiceTransferRequest(DeviceObject, Irp);
1686 status = STATUS_PENDING;
1687 }
1688 else {
1689 /*
1690 * This is a child PDO enumerated for our FDO by e.g. disk.sys
1691 * and owned by e.g. partmgr. Send it down to the next device
1692 * and the same irp will come back to us for the FDO.
1693 */
1694 IoCopyCurrentIrpStackLocationToNext(Irp);
1695 ClassReleaseRemoveLock(DeviceObject, Irp);
1696 status = IoCallDriver(lowerDeviceObject, Irp);
1697 }
1698 }
1699 }
1700 }
1701 }
1702
1703 return status;
1704 }
1705
1706
1707 /*++////////////////////////////////////////////////////////////////////////////
1708
1709 ClassReadDriveCapacity()
1710
1711 Routine Description:
1712
1713 This routine sends a READ CAPACITY to the requested device, updates
1714 the geometry information in the device object and returns
1715 when it is complete. This routine is synchronous.
1716
1717 This routine must be called with the remove lock held or some other
1718 assurance that the Fdo will not be removed while processing.
1719
1720 Arguments:
1721
1722 DeviceObject - Supplies a pointer to the device object that represents
1723 the device whose capacity is to be read.
1724
1725 Return Value:
1726
1727 Status is returned.
1728
1729 --*/
1730 NTSTATUS NTAPI ClassReadDriveCapacity(IN PDEVICE_OBJECT Fdo)
1731 {
1732 READ_CAPACITY_DATA readCapacityBuffer = {0};
1733 NTSTATUS status;
1734 PMDL driveCapMdl;
1735
1736 driveCapMdl = BuildDeviceInputMdl(&readCapacityBuffer, sizeof(READ_CAPACITY_DATA));
1737 if (driveCapMdl){
1738
1739 TRANSFER_PACKET *pkt = DequeueFreeTransferPacket(Fdo, TRUE);
1740 if (pkt){
1741 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
1742 KEVENT event;
1743 //NTSTATUS pktStatus;
1744 IRP pseudoIrp = {0};
1745
1746 /*
1747 * Our engine needs an "original irp" to write the status back to
1748 * and to count down packets (one in this case).
1749 * Just use a pretend irp for this.
1750 */
1751 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
1752 pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
1753 pseudoIrp.IoStatus.Information = 0;
1754 pseudoIrp.MdlAddress = driveCapMdl;
1755
1756 /*
1757 * Set this up as a SYNCHRONOUS transfer, submit it,
1758 * and wait for the packet to complete. The result
1759 * status will be written to the original irp.
1760 */
1761 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
1762 SetupDriveCapacityTransferPacket( pkt,
1763 &readCapacityBuffer,
1764 sizeof(READ_CAPACITY_DATA),
1765 &event,
1766 &pseudoIrp);
1767 SubmitTransferPacket(pkt);
1768 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
1769
1770 status = pseudoIrp.IoStatus.Status;
1771
1772 /*
1773 * If we got an UNDERRUN, retry exactly once.
1774 * (The transfer_packet engine didn't retry because the result
1775 * status was success).
1776 */
1777 if (NT_SUCCESS(status) &&
1778 (pseudoIrp.IoStatus.Information < sizeof(READ_CAPACITY_DATA))){
1779 DBGERR(("ClassReadDriveCapacity: read len (%xh) < %xh, retrying ...", (ULONG)pseudoIrp.IoStatus.Information, sizeof(READ_CAPACITY_DATA)));
1780
1781 pkt = DequeueFreeTransferPacket(Fdo, TRUE);
1782 if (pkt){
1783 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
1784 pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
1785 pseudoIrp.IoStatus.Information = 0;
1786 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
1787 SetupDriveCapacityTransferPacket( pkt,
1788 &readCapacityBuffer,
1789 sizeof(READ_CAPACITY_DATA),
1790 &event,
1791 &pseudoIrp);
1792 SubmitTransferPacket(pkt);
1793 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
1794 status = pseudoIrp.IoStatus.Status;
1795 if (pseudoIrp.IoStatus.Information < sizeof(READ_CAPACITY_DATA)){
1796 status = STATUS_DEVICE_BUSY;
1797 }
1798 }
1799 else {
1800 status = STATUS_INSUFFICIENT_RESOURCES;
1801 }
1802 }
1803
1804
1805 if (NT_SUCCESS(status)){
1806 /*
1807 * The request succeeded.
1808 * Read out and store the drive information.
1809 */
1810 ULONG cylinderSize;
1811 ULONG bytesPerSector;
1812 ULONG tmp;
1813 ULONG lastSector;
1814
1815 /*
1816 * Read the bytesPerSector value,
1817 * which is big-endian in the returned buffer.
1818 * Default to the standard 512 bytes.
1819 */
1820 tmp = readCapacityBuffer.BytesPerBlock;
1821 ((PFOUR_BYTE)&bytesPerSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
1822 ((PFOUR_BYTE)&bytesPerSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
1823 ((PFOUR_BYTE)&bytesPerSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
1824 ((PFOUR_BYTE)&bytesPerSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
1825 if (bytesPerSector == 0) {
1826 bytesPerSector = 512;
1827 }
1828 else {
1829 /*
1830 * Clear all but the highest set bit.
1831 * That will give us a bytesPerSector value that is a power of 2.
1832 */
1833 while (bytesPerSector & (bytesPerSector-1)) {
1834 bytesPerSector &= bytesPerSector-1;
1835 }
1836 }
1837 fdoExt->DiskGeometry.BytesPerSector = bytesPerSector;
1838
1839 //
1840 // Copy last sector in reverse byte order.
1841 //
1842
1843 tmp = readCapacityBuffer.LogicalBlockAddress;
1844 ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
1845 ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
1846 ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
1847 ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
1848
1849 //
1850 // Calculate sector to byte shift.
1851 //
1852
1853 WHICH_BIT(fdoExt->DiskGeometry.BytesPerSector, fdoExt->SectorShift);
1854
1855 DebugPrint((2,"SCSI ClassReadDriveCapacity: Sector size is %d\n",
1856 fdoExt->DiskGeometry.BytesPerSector));
1857
1858 DebugPrint((2,"SCSI ClassReadDriveCapacity: Number of Sectors is %d\n",
1859 lastSector + 1));
1860
1861 if (fdoExt->DMActive){
1862 DebugPrint((1, "SCSI ClassReadDriveCapacity: reducing number of sectors by %d\n",
1863 fdoExt->DMSkew));
1864 lastSector -= fdoExt->DMSkew;
1865 }
1866
1867 /*
1868 * Check to see if we have a geometry we should be using already.
1869 */
1870 cylinderSize = (fdoExt->DiskGeometry.TracksPerCylinder *
1871 fdoExt->DiskGeometry.SectorsPerTrack);
1872 if (cylinderSize == 0){
1873 DebugPrint((1, "ClassReadDriveCapacity: resetting H & S geometry "
1874 "values from %#x/%#x to %#x/%#x\n",
1875 fdoExt->DiskGeometry.TracksPerCylinder,
1876 fdoExt->DiskGeometry.SectorsPerTrack,
1877 0xff,
1878 0x3f));
1879
1880 fdoExt->DiskGeometry.TracksPerCylinder = 0xff;
1881 fdoExt->DiskGeometry.SectorsPerTrack = 0x3f;
1882
1883
1884 cylinderSize = (fdoExt->DiskGeometry.TracksPerCylinder *
1885 fdoExt->DiskGeometry.SectorsPerTrack);
1886 }
1887
1888 //
1889 // Calculate number of cylinders.
1890 //
1891
1892 fdoExt->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/cylinderSize);
1893
1894 //
1895 // if there are zero cylinders, then the device lied AND it's
1896 // smaller than 0xff*0x3f (about 16k sectors, usually 8 meg)
1897 // this can fit into a single LONGLONG, so create another usable
1898 // geometry, even if it's unusual looking. This allows small,
1899 // non-standard devices, such as Sony's Memory Stick, to show
1900 // up as having a partition.
1901 //
1902
1903 if (fdoExt->DiskGeometry.Cylinders.QuadPart == (LONGLONG)0) {
1904 fdoExt->DiskGeometry.SectorsPerTrack = 1;
1905 fdoExt->DiskGeometry.TracksPerCylinder = 1;
1906 fdoExt->DiskGeometry.Cylinders.QuadPart = lastSector;
1907 }
1908
1909
1910 //
1911 // Calculate media capacity in bytes.
1912 //
1913
1914 fdoExt->CommonExtension.PartitionLength.QuadPart =
1915 ((LONGLONG)(lastSector + 1)) << fdoExt->SectorShift;
1916
1917 /*
1918 * Is this removable or fixed media
1919 */
1920 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
1921 fdoExt->DiskGeometry.MediaType = RemovableMedia;
1922 }
1923 else {
1924 fdoExt->DiskGeometry.MediaType = FixedMedia;
1925 }
1926 }
1927 else {
1928 /*
1929 * The request failed.
1930 */
1931
1932 //
1933 // ISSUE - 2000/02/04 - henrygab - non-512-byte sector sizes and failed geometry update
1934 // what happens when the disk's sector size is bigger than
1935 // 512 bytes and we hit this code path? this is untested.
1936 //
1937 // If the read capacity fails, set the geometry to reasonable parameter
1938 // so things don't fail at unexpected places. Zero the geometry
1939 // except for the bytes per sector and sector shift.
1940 //
1941
1942 /*
1943 * This request can sometimes fail legitimately
1944 * (e.g. when a SCSI device is attached but turned off)
1945 * so this is not necessarily a device/driver bug.
1946 */
1947 DBGTRACE(ClassDebugWarning, ("ClassReadDriveCapacity on Fdo %xh failed with status %xh.", Fdo, status));
1948
1949 /*
1950 * Write in a default disk geometry which we HOPE is right (??).
1951 * BUGBUG !!
1952 */
1953 RtlZeroMemory(&fdoExt->DiskGeometry, sizeof(DISK_GEOMETRY));
1954 fdoExt->DiskGeometry.BytesPerSector = 512;
1955 fdoExt->SectorShift = 9;
1956 fdoExt->CommonExtension.PartitionLength.QuadPart = (LONGLONG) 0;
1957
1958 /*
1959 * Is this removable or fixed media
1960 */
1961 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
1962 fdoExt->DiskGeometry.MediaType = RemovableMedia;
1963 }
1964 else {
1965 fdoExt->DiskGeometry.MediaType = FixedMedia;
1966 }
1967 }
1968
1969 }
1970 else {
1971 status = STATUS_INSUFFICIENT_RESOURCES;
1972 }
1973
1974 FreeDeviceInputMdl(driveCapMdl);
1975 }
1976 else {
1977 status = STATUS_INSUFFICIENT_RESOURCES;
1978 }
1979
1980 return status;
1981 }
1982
1983
1984 /*++////////////////////////////////////////////////////////////////////////////
1985
1986 ClassSendStartUnit()
1987
1988 Routine Description:
1989
1990 Send command to SCSI unit to start or power up.
1991 Because this command is issued asynchronounsly, that is, without
1992 waiting on it to complete, the IMMEDIATE flag is not set. This
1993 means that the CDB will not return until the drive has powered up.
1994 This should keep subsequent requests from being submitted to the
1995 device before it has completely spun up.
1996
1997 This routine is called from the InterpretSense routine, when a
1998 request sense returns data indicating that a drive must be
1999 powered up.
2000
2001 This routine may also be called from a class driver's error handler,
2002 or anytime a non-critical start device should be sent to the device.
2003
2004 Arguments:
2005
2006 Fdo - The functional device object for the stopped device.
2007
2008 Return Value:
2009
2010 None.
2011
2012 --*/
2013 VOID
2014 NTAPI
2015 ClassSendStartUnit(
2016 IN PDEVICE_OBJECT Fdo
2017 )
2018 {
2019 PIO_STACK_LOCATION irpStack;
2020 PIRP irp;
2021 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2022 PSCSI_REQUEST_BLOCK srb;
2023 PCOMPLETION_CONTEXT context;
2024 PCDB cdb;
2025
2026 //
2027 // Allocate Srb from nonpaged pool.
2028 //
2029
2030 context = ExAllocatePoolWithTag(NonPagedPool,
2031 sizeof(COMPLETION_CONTEXT),
2032 '6CcS');
2033
2034 if(context == NULL) {
2035
2036 //
2037 // ISSUE-2000/02/03-peterwie
2038 // This code path was inheritted from the NT 4.0 class2.sys driver.
2039 // It needs to be changed to survive low-memory conditions.
2040 //
2041
2042 KeBugCheck(SCSI_DISK_DRIVER_INTERNAL);
2043 }
2044
2045 //
2046 // Save the device object in the context for use by the completion
2047 // routine.
2048 //
2049
2050 context->DeviceObject = Fdo;
2051 srb = &context->Srb;
2052
2053 //
2054 // Zero out srb.
2055 //
2056
2057 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
2058
2059 //
2060 // Write length to SRB.
2061 //
2062
2063 srb->Length = sizeof(SCSI_REQUEST_BLOCK);
2064
2065 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2066
2067 //
2068 // Set timeout value large enough for drive to spin up.
2069 //
2070
2071 srb->TimeOutValue = START_UNIT_TIMEOUT;
2072
2073 //
2074 // Set the transfer length.
2075 //
2076
2077 srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
2078 SRB_FLAGS_DISABLE_AUTOSENSE |
2079 SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2080
2081 //
2082 // Build the start unit CDB.
2083 //
2084
2085 srb->CdbLength = 6;
2086 cdb = (PCDB)srb->Cdb;
2087
2088 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
2089 cdb->START_STOP.Start = 1;
2090 cdb->START_STOP.Immediate = 0;
2091 cdb->START_STOP.LogicalUnitNumber = srb->Lun;
2092
2093 //
2094 // Build the asynchronous request to be sent to the port driver.
2095 // Since this routine is called from a DPC the IRP should always be
2096 // available.
2097 //
2098
2099 irp = IoAllocateIrp(Fdo->StackSize, FALSE);
2100
2101 if(irp == NULL) {
2102
2103 //
2104 // ISSUE-2000/02/03-peterwie
2105 // This code path was inheritted from the NT 4.0 class2.sys driver.
2106 // It needs to be changed to survive low-memory conditions.
2107 //
2108
2109 KeBugCheck(SCSI_DISK_DRIVER_INTERNAL);
2110
2111 }
2112
2113 ClassAcquireRemoveLock(Fdo, irp);
2114
2115 IoSetCompletionRoutine(irp,
2116 (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
2117 context,
2118 TRUE,
2119 TRUE,
2120 TRUE);
2121
2122 irpStack = IoGetNextIrpStackLocation(irp);
2123 irpStack->MajorFunction = IRP_MJ_SCSI;
2124 srb->OriginalRequest = irp;
2125
2126 //
2127 // Store the SRB address in next stack for port driver.
2128 //
2129
2130 irpStack->Parameters.Scsi.Srb = srb;
2131
2132 //
2133 // Call the port driver with the IRP.
2134 //
2135
2136 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
2137
2138 return;
2139
2140 } // end StartUnit()
2141
2142 /*++////////////////////////////////////////////////////////////////////////////
2143
2144 ClassAsynchronousCompletion() ISSUE-2000/02/18-henrygab - why public?!
2145
2146 Routine Description:
2147
2148 This routine is called when an asynchronous I/O request
2149 which was issused by the class driver completes. Examples of such requests
2150 are release queue or START UNIT. This routine releases the queue if
2151 necessary. It then frees the context and the IRP.
2152
2153 Arguments:
2154
2155 DeviceObject - The device object for the logical unit; however since this
2156 is the top stack location the value is NULL.
2157
2158 Irp - Supplies a pointer to the Irp to be processed.
2159
2160 Context - Supplies the context to be used to process this request.
2161
2162 Return Value:
2163
2164 None.
2165
2166 --*/
2167 NTSTATUS
2168 NTAPI
2169 ClassAsynchronousCompletion(
2170 PDEVICE_OBJECT DeviceObject,
2171 PIRP Irp,
2172 PVOID Context
2173 )
2174 {
2175 PCOMPLETION_CONTEXT context = Context;
2176 PSCSI_REQUEST_BLOCK srb;
2177
2178 if(DeviceObject == NULL) {
2179
2180 DeviceObject = context->DeviceObject;
2181 }
2182
2183 srb = &context->Srb;
2184
2185 //
2186 // If this is an execute srb, then check the return status and make sure.
2187 // the queue is not frozen.
2188 //
2189
2190 if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
2191
2192 //
2193 // Check for a frozen queue.
2194 //
2195
2196 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2197
2198 //
2199 // Unfreeze the queue getting the device object from the context.
2200 //
2201
2202 ClassReleaseQueue(context->DeviceObject);
2203 }
2204 }
2205
2206 { // free port-allocated sense buffer if we can detect
2207
2208 if (((PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension))->IsFdo) {
2209
2210 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
2211 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
2212 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
2213 }
2214
2215 } else {
2216
2217 ASSERT(!TEST_FLAG(srb->SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
2218
2219 }
2220 }
2221
2222
2223 //
2224 // Free the context and the Irp.
2225 //
2226
2227 if (Irp->MdlAddress != NULL) {
2228 MmUnlockPages(Irp->MdlAddress);
2229 IoFreeMdl(Irp->MdlAddress);
2230
2231 Irp->MdlAddress = NULL;
2232 }
2233
2234 ClassReleaseRemoveLock(DeviceObject, Irp);
2235
2236 ExFreePool(context);
2237 IoFreeIrp(Irp);
2238
2239 //
2240 // Indicate the I/O system should stop processing the Irp completion.
2241 //
2242
2243 return STATUS_MORE_PROCESSING_REQUIRED;
2244
2245 } // end ClassAsynchronousCompletion()
2246
2247 VOID NTAPI ServiceTransferRequest(PDEVICE_OBJECT Fdo, PIRP Irp)
2248 {
2249 //PCOMMON_DEVICE_EXTENSION commonExt = Fdo->DeviceExtension;
2250 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
2251 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
2252 //PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExt->PartitionZeroExtension->AdapterDescriptor;
2253 PIO_STACK_LOCATION currentSp = IoGetCurrentIrpStackLocation(Irp);
2254 ULONG entireXferLen = currentSp->Parameters.Read.Length;
2255 PUCHAR bufPtr = MmGetMdlVirtualAddress(Irp->MdlAddress);
2256 LARGE_INTEGER targetLocation = currentSp->Parameters.Read.ByteOffset;
2257 PTRANSFER_PACKET pkt;
2258 SINGLE_LIST_ENTRY pktList;
2259 PSINGLE_LIST_ENTRY slistEntry;
2260 ULONG numPackets;
2261 //KIRQL oldIrql;
2262 ULONG i;
2263
2264 /*
2265 * Compute the number of hw xfers we'll have to do.
2266 * Calculate this without allowing for an overflow condition.
2267 */
2268 ASSERT(fdoData->HwMaxXferLen >= PAGE_SIZE);
2269 numPackets = entireXferLen/fdoData->HwMaxXferLen;
2270 if (entireXferLen % fdoData->HwMaxXferLen){
2271 numPackets++;
2272 }
2273
2274 /*
2275 * First get all the TRANSFER_PACKETs that we'll need at once.
2276 * Use our 'simple' slist functions since we don't need interlocked.
2277 */
2278 SimpleInitSlistHdr(&pktList);
2279 for (i = 0; i < numPackets; i++){
2280 pkt = DequeueFreeTransferPacket(Fdo, TRUE);
2281 if (pkt){
2282 SimplePushSlist(&pktList, &pkt->SlistEntry);
2283 }
2284 else {
2285 break;
2286 }
2287 }
2288
2289 if (i == numPackets){
2290 /*
2291 * Initialize the original IRP's status to success.
2292 * If any of the packets fail, they will set it to an error status.
2293 * The IoStatus.Information field will be incremented to the
2294 * transfer length as the pieces complete.
2295 */
2296 Irp->IoStatus.Status = STATUS_SUCCESS;
2297 Irp->IoStatus.Information = 0;
2298
2299 /*
2300 * Store the number of transfer pieces inside the original IRP.
2301 * It will be used to count down the pieces as they complete.
2302 */
2303 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(numPackets);
2304
2305 /*
2306 * We are proceeding with the transfer.
2307 * Mark the client IRP pending since it may complete on a different thread.
2308 */
2309 IoMarkIrpPending(Irp);
2310
2311 /*
2312 * Transmit the pieces of the transfer.
2313 */
2314 while (entireXferLen > 0){
2315 ULONG thisPieceLen = MIN(fdoData->HwMaxXferLen, entireXferLen);
2316
2317 /*
2318 * Set up a TRANSFER_PACKET for this piece and send it.
2319 */
2320 slistEntry = SimplePopSlist(&pktList);
2321 ASSERT(slistEntry);
2322 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
2323 SetupReadWriteTransferPacket( pkt,
2324 bufPtr,
2325 thisPieceLen,
2326 targetLocation,
2327 Irp);
2328 SubmitTransferPacket(pkt);
2329
2330 entireXferLen -= thisPieceLen;
2331 bufPtr += thisPieceLen;
2332 targetLocation.QuadPart += thisPieceLen;
2333 }
2334 ASSERT(SimpleIsSlistEmpty(&pktList));
2335 }
2336 else if (i >= 1){
2337 /*
2338 * We were unable to get all the TRANSFER_PACKETs we need,
2339 * but we did get at least one.
2340 * That means that we are in extreme low-memory stress.
2341 * We'll try doing this transfer using a single packet.
2342 * The port driver is certainly also in stress, so use one-page
2343 * transfers.
2344 */
2345
2346 /*
2347 * Free all but one of the TRANSFER_PACKETs.
2348 */
2349 while (i-- > 1){
2350 slistEntry = SimplePopSlist(&pktList);
2351 ASSERT(slistEntry);
2352 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
2353 EnqueueFreeTransferPacket(Fdo, pkt);
2354 }
2355
2356 /*
2357 * Get the single TRANSFER_PACKET that we'll be using.
2358 */
2359 slistEntry = SimplePopSlist(&pktList);
2360 ASSERT(slistEntry);
2361 ASSERT(SimpleIsSlistEmpty(&pktList));
2362 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
2363 DBGWARN(("Insufficient packets available in ServiceTransferRequest - entering lowMemRetry with pkt=%xh.", pkt));
2364
2365 /*
2366 * Set default status and the number of transfer packets (one)
2367 * inside the original irp.
2368 */
2369 Irp->IoStatus.Status = STATUS_SUCCESS;
2370 Irp->IoStatus.Information = 0;
2371 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1);
2372
2373 /*
2374 * Mark the client irp pending since it may complete on
2375 * another thread.
2376 */
2377 IoMarkIrpPending(Irp);
2378
2379 /*
2380 * Set up the TRANSFER_PACKET for a lowMem transfer and launch.
2381 */
2382 SetupReadWriteTransferPacket( pkt,
2383 bufPtr,
2384 entireXferLen,
2385 targetLocation,
2386 Irp);
2387 InitLowMemRetry(pkt, bufPtr, entireXferLen, targetLocation);
2388 StepLowMemRetry(pkt);
2389 }
2390 else {
2391 /*
2392 * We were unable to get ANY TRANSFER_PACKETs.
2393 * Defer this client irp until some TRANSFER_PACKETs free up.
2394 */
2395 DBGWARN(("No packets available in ServiceTransferRequest - deferring transfer (Irp=%xh)...", Irp));
2396 IoMarkIrpPending(Irp);
2397 EnqueueDeferredClientIrp(fdoData, Irp);
2398 }
2399
2400 }
2401
2402 /*++////////////////////////////////////////////////////////////////////////////
2403
2404 ClassIoComplete()
2405
2406 Routine Description:
2407
2408 This routine executes when the port driver has completed a request.
2409 It looks at the SRB status in the completing SRB and if not success
2410 it checks for valid request sense buffer information. If valid, the
2411 info is used to update status with more precise message of type of
2412 error. This routine deallocates the SRB.
2413
2414 This routine should only be placed on the stack location for a class
2415 driver FDO.
2416
2417 Arguments:
2418
2419 Fdo - Supplies the device object which represents the logical
2420 unit.
2421
2422 Irp - Supplies the Irp which has completed.
2423
2424 Context - Supplies a pointer to the SRB.
2425
2426 Return Value:
2427
2428 NT status
2429
2430 --*/
2431 NTSTATUS
2432 NTAPI
2433 ClassIoComplete(
2434 IN PDEVICE_OBJECT Fdo,
2435 IN PIRP Irp,
2436 IN PVOID Context
2437 )
2438 {
2439 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
2440 PSCSI_REQUEST_BLOCK srb = Context;
2441 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2442 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
2443 NTSTATUS status;
2444 BOOLEAN retry;
2445 BOOLEAN callStartNextPacket;
2446
2447 ASSERT(fdoExtension->CommonExtension.IsFdo);
2448
2449 //
2450 // Check SRB status for success of completing request.
2451 //
2452
2453 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2454 ULONG retryInterval;
2455
2456 DebugPrint((2, "ClassIoComplete: IRP %p, SRB %p\n", Irp, srb));
2457
2458 //
2459 // Release the queue if it is frozen.
2460 //
2461
2462 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2463 ClassReleaseQueue(Fdo);
2464 }
2465
2466 retry = ClassInterpretSenseInfo(
2467 Fdo,
2468 srb,
2469 irpStack->MajorFunction,
2470 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ?
2471 irpStack->Parameters.DeviceIoControl.IoControlCode :
2472 0,
2473 MAXIMUM_RETRIES -
2474 ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
2475 &status,
2476 &retryInterval);
2477
2478 //
2479 // If the status is verified required and the this request
2480 // should bypass verify required then retry the request.
2481 //
2482
2483 if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
2484 status == STATUS_VERIFY_REQUIRED) {
2485
2486 status = STATUS_IO_DEVICE_ERROR;
2487 retry = TRUE;
2488 }
2489
2490 if (retry && ((*(PCHAR*)&irpStack->Parameters.Others.Argument4)--)) {
2491
2492 //
2493 // Retry request.
2494 //
2495
2496 DebugPrint((1, "Retry request %p\n", Irp));
2497
2498 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
2499 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
2500 }
2501
2502 RetryRequest(Fdo, Irp, srb, FALSE, retryInterval);
2503 return STATUS_MORE_PROCESSING_REQUIRED;
2504 }
2505
2506 } else {
2507
2508 //
2509 // Set status for successful request
2510 //
2511 fdoData->LoggedTURFailureSinceLastIO = FALSE;
2512 ClasspPerfIncrementSuccessfulIo(fdoExtension);
2513 status = STATUS_SUCCESS;
2514 } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)
2515
2516
2517 //
2518 // ensure we have returned some info, and it matches what the
2519 // original request wanted for PAGING operations only
2520 //
2521
2522 if ((NT_SUCCESS(status)) && TEST_FLAG(Irp->Flags, IRP_PAGING_IO)) {
2523 ASSERT(Irp->IoStatus.Information != 0);
2524 ASSERT(irpStack->Parameters.Read.Length == Irp->IoStatus.Information);
2525 }
2526
2527 //
2528 // remember if the caller wanted to skip calling IoStartNextPacket.
2529 // for legacy reasons, we cannot call IoStartNextPacket for IoDeviceControl
2530 // calls. this setting only affects device objects with StartIo routines.
2531 //
2532
2533 callStartNextPacket = !TEST_FLAG(srb->SrbFlags, SRB_FLAGS_DONT_START_NEXT_PACKET);
2534 if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
2535 callStartNextPacket = FALSE;
2536 }
2537
2538 //
2539 // Free the srb
2540 //
2541
2542 if(!TEST_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT)) {
2543
2544 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
2545 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
2546 }
2547
2548 if (fdoExtension->CommonExtension.IsSrbLookasideListInitialized){
2549 ClassFreeOrReuseSrb(fdoExtension, srb);
2550 }
2551 else {
2552 DBGWARN(("ClassIoComplete is freeing an SRB (possibly) on behalf of another driver."));
2553 ExFreePool(srb);
2554 }
2555
2556 } else {
2557
2558 DebugPrint((2, "ClassIoComplete: Not Freeing srb @ %p because "
2559 "SRB_CLASS_FLAGS_PERSISTANT set\n", srb));
2560 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
2561 DebugPrint((2, "ClassIoComplete: Not Freeing sensebuffer @ %p "
2562 " because SRB_CLASS_FLAGS_PERSISTANT set\n",
2563 srb->SenseInfoBuffer));
2564 }
2565
2566 }
2567
2568 //
2569 // Set status in completing IRP.
2570 //
2571
2572 Irp->IoStatus.Status = status;
2573
2574 //
2575 // Set the hard error if necessary.
2576 //
2577
2578 if (!NT_SUCCESS(status) &&
2579 IoIsErrorUserInduced(status) &&
2580 (Irp->Tail.Overlay.Thread != NULL)
2581 ) {
2582
2583 //
2584 // Store DeviceObject for filesystem, and clear
2585 // in IoStatus.Information field.
2586 //
2587
2588 IoSetHardErrorOrVerifyDevice(Irp, Fdo);
2589 Irp->IoStatus.Information = 0;
2590 }
2591
2592 //
2593 // If pending has be returned for this irp then mark the current stack as
2594 // pending.
2595 //
2596
2597 if (Irp->PendingReturned) {
2598 IoMarkIrpPending(Irp);
2599 }
2600
2601 if (fdoExtension->CommonExtension.DriverExtension->InitData.ClassStartIo) {
2602 if (callStartNextPacket) {
2603 KIRQL oldIrql;
2604 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
2605 IoStartNextPacket(Fdo, FALSE);
2606 KeLowerIrql(oldIrql);
2607 }
2608 }
2609
2610 ClassReleaseRemoveLock(Fdo, Irp);
2611
2612 return status;
2613
2614 } // end ClassIoComplete()
2615
2616 /*++////////////////////////////////////////////////////////////////////////////
2617
2618 ClassSendSrbSynchronous()
2619
2620 Routine Description:
2621
2622 This routine is called by SCSI device controls to complete an
2623 SRB and send it to the port driver synchronously (ie wait for
2624 completion). The CDB is already completed along with the SRB CDB
2625 size and request timeout value.
2626
2627 Arguments:
2628
2629 Fdo - Supplies the functional device object which represents the target.
2630
2631 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
2632
2633 BufferAddress - Supplies the address of the buffer.
2634
2635 BufferLength - Supplies the length in bytes of the buffer.
2636
2637 WriteToDevice - Indicates the data should be transfer to the device.
2638
2639 Return Value:
2640
2641 NTSTATUS indicating the final results of the operation.
2642
2643 If NT_SUCCESS(), then the amount of usable data is contained in the field
2644 Srb->DataTransferLength
2645
2646 --*/
2647 NTSTATUS
2648 NTAPI
2649 ClassSendSrbSynchronous(
2650 PDEVICE_OBJECT Fdo,
2651 PSCSI_REQUEST_BLOCK Srb,
2652 PVOID BufferAddress,
2653 ULONG BufferLength,
2654 BOOLEAN WriteToDevice
2655 )
2656 {
2657
2658 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
2659 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
2660 IO_STATUS_BLOCK ioStatus;
2661 //ULONG controlType;
2662 PIRP irp;
2663 PIO_STACK_LOCATION irpStack;
2664 KEVENT event;
2665 PUCHAR senseInfoBuffer;
2666 ULONG retryCount = MAXIMUM_RETRIES;
2667 NTSTATUS status;
2668 BOOLEAN retry;
2669
2670 //
2671 // NOTE: This code is only pagable because we are not freezing
2672 // the queue. Allowing the queue to be frozen from a pagable
2673 // routine could leave the queue frozen as we try to page in
2674 // the code to unfreeze the queue. The result would be a nice
2675 // case of deadlock. Therefore, since we are unfreezing the
2676 // queue regardless of the result, just set the NO_FREEZE_QUEUE
2677 // flag in the SRB.
2678 //
2679
2680 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
2681 ASSERT(fdoExtension->CommonExtension.IsFdo);
2682
2683 //
2684 // Write length to SRB.
2685 //
2686
2687 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
2688
2689 //
2690 // Set SCSI bus address.
2691 //
2692
2693 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2694
2695 //
2696 // Enable auto request sense.
2697 //
2698
2699 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
2700
2701 //
2702 // Sense buffer is in aligned nonpaged pool.
2703 //
2704 //
2705 senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
2706 SENSE_BUFFER_SIZE,
2707 '7CcS');
2708
2709 if (senseInfoBuffer == NULL) {
2710
2711 DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate request sense "
2712 "buffer\n"));
2713 return(STATUS_INSUFFICIENT_RESOURCES);
2714 }
2715
2716 Srb->SenseInfoBuffer = senseInfoBuffer;
2717 Srb->DataBuffer = BufferAddress;
2718
2719 //
2720 // Start retries here.
2721 //
2722
2723 retry:
2724
2725 //
2726 // use fdoextension's flags by default.
2727 // do not move out of loop, as the flag may change due to errors
2728 // sending this command.
2729 //
2730
2731 Srb->SrbFlags = fdoExtension->SrbFlags;
2732
2733 if(BufferAddress != NULL) {
2734 if(WriteToDevice) {
2735 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT);
2736 } else {
2737 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
2738 }
2739 }
2740
2741 //
2742 // Initialize the QueueAction field.
2743 //
2744
2745 Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
2746
2747 //
2748 // Disable synchronous transfer for these requests.
2749 // Disable freezing the queue, since all we do is unfreeze it anyways.
2750 //
2751
2752 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
2753 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
2754
2755 //
2756 // Set the event object to the unsignaled state.
2757 // It will be used to signal request completion.
2758 //
2759
2760 KeInitializeEvent(&event, NotificationEvent, FALSE);
2761
2762 //
2763 // Build device I/O control request with METHOD_NEITHER data transfer.
2764 // We'll queue a completion routine to cleanup the MDL's and such ourself.
2765 //
2766
2767 irp = IoAllocateIrp(
2768 (CCHAR) (fdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1),
2769 FALSE);
2770
2771 if(irp == NULL) {
2772 ExFreePool(senseInfoBuffer);
2773 DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate Irp\n"));
2774 return(STATUS_INSUFFICIENT_RESOURCES);
2775 }
2776
2777 //
2778 // Get next stack location.
2779 //
2780
2781 irpStack = IoGetNextIrpStackLocation(irp);
2782
2783 //
2784 // Set up SRB for execute scsi request. Save SRB address in next stack
2785 // for the port driver.
2786 //
2787
2788 irpStack->MajorFunction = IRP_MJ_SCSI;
2789 irpStack->Parameters.Scsi.Srb = Srb;
2790
2791 IoSetCompletionRoutine(irp,
2792 ClasspSendSynchronousCompletion,
2793 Srb,
2794 TRUE,
2795 TRUE,
2796 TRUE);
2797
2798 irp->UserIosb = &ioStatus;
2799 irp->UserEvent = &event;
2800
2801 if(BufferAddress) {
2802 //
2803 // Build an MDL for the data buffer and stick it into the irp. The
2804 // completion routine will unlock the pages and free the MDL.
2805 //
2806
2807 irp->MdlAddress = IoAllocateMdl( BufferAddress,
2808 BufferLength,
2809 FALSE,
2810 FALSE,
2811 irp );
2812 if (irp->MdlAddress == NULL) {
2813 ExFreePool(senseInfoBuffer);
2814 Srb->SenseInfoBuffer = NULL;
2815 IoFreeIrp( irp );
2816 DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate MDL\n"));
2817 return STATUS_INSUFFICIENT_RESOURCES;
2818 }
2819
2820 _SEH2_TRY {
2821
2822 //
2823 // the io manager unlocks these pages upon completion
2824 //
2825
2826 MmProbeAndLockPages( irp->MdlAddress,
2827 KernelMode,
2828 (WriteToDevice ? IoReadAccess :
2829 IoWriteAccess));
2830
2831 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2832 status = _SEH2_GetExceptionCode();
2833
2834 ExFreePool(senseInfoBuffer);
2835 Srb->SenseInfoBuffer = NULL;
2836 IoFreeMdl(irp->MdlAddress);
2837 IoFreeIrp(irp);
2838
2839 DebugPrint((1, "ClassSendSrbSynchronous: Exception %lx "
2840 "locking buffer\n", status));
2841 return status;
2842 } _SEH2_END;
2843 }
2844
2845 //
2846 // Set the transfer length.
2847 //
2848
2849 Srb->DataTransferLength = BufferLength;
2850
2851 //
2852 // Zero out status.
2853 //
2854
2855 Srb->ScsiStatus = Srb->SrbStatus = 0;
2856 Srb->NextSrb = 0;
2857
2858 //
2859 // Set up IRP Address.
2860 //
2861
2862 Srb->OriginalRequest = irp;
2863
2864 //
2865 // Call the port driver with the request and wait for it to complete.
2866 //
2867
2868 status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
2869
2870 if (status == STATUS_PENDING) {
2871 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
2872 status = ioStatus.Status;
2873 }
2874
2875 //
2876 // Check that request completed without error.
2877 //
2878
2879 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2880
2881 ULONG retryInterval;
2882
2883 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)));
2884
2885 //
2886 // assert that the queue is not frozen
2887 //
2888
2889 ASSERT(!TEST_FLAG(Srb->SrbStatus, SRB_STATUS_QUEUE_FROZEN));
2890
2891 //
2892 // Update status and determine if request should be retried.
2893 //
2894
2895 retry = ClassInterpretSenseInfo(Fdo,
2896 Srb,
2897 IRP_MJ_SCSI,
2898 0,
2899 MAXIMUM_RETRIES - retryCount,
2900 &status,
2901 &retryInterval);
2902
2903
2904 if (retry) {
2905
2906 if ((status == STATUS_DEVICE_NOT_READY &&
2907 ((PSENSE_DATA) senseInfoBuffer)->AdditionalSenseCode ==
2908 SCSI_ADSENSE_LUN_NOT_READY) ||
2909 (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) {
2910
2911 LARGE_INTEGER delay;
2912
2913 //
2914 // Delay for at least 2 seconds.
2915 //
2916
2917 if(retryInterval < 2) {
2918 retryInterval = 2;
2919 }
2920
2921 delay.QuadPart = (LONGLONG)( - 10 * 1000 * (LONGLONG)1000 * retryInterval);
2922
2923 //
2924 // Stall for a while to let the device become ready
2925 //
2926
2927 KeDelayExecutionThread(KernelMode, FALSE, &delay);
2928
2929 }
2930
2931 //
2932 // If retries are not exhausted then retry this operation.
2933 //
2934
2935 if (retryCount--) {
2936
2937 if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) {
2938 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb);
2939 }
2940
2941 goto retry;
2942 }
2943 }
2944
2945 } else {
2946 fdoData->LoggedTURFailureSinceLastIO = FALSE;
2947 status = STATUS_SUCCESS;
2948 }
2949
2950 //
2951 // required even though we allocated our own, since the port driver may
2952 // have allocated one also
2953 //
2954
2955 if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) {
2956 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb);
2957 }
2958
2959 Srb->SenseInfoBuffer = NULL;
2960 ExFreePool(senseInfoBuffer);
2961
2962 return status;
2963 }
2964
2965 /*++////////////////////////////////////////////////////////////////////////////
2966
2967 ClassInterpretSenseInfo()
2968
2969 Routine Description:
2970
2971 This routine interprets the data returned from the SCSI
2972 request sense. It determines the status to return in the
2973 IRP and whether this request can be retried.
2974
2975 Arguments:
2976
2977 DeviceObject - Supplies the device object associated with this request.
2978
2979 Srb - Supplies the scsi request block which failed.
2980
2981 MajorFunctionCode - Supplies the function code to be used for logging.
2982
2983 IoDeviceCode - Supplies the device code to be used for logging.
2984
2985 Status - Returns the status for the request.
2986
2987 Return Value:
2988
2989 BOOLEAN TRUE: Drivers should retry this request.
2990 FALSE: Drivers should not retry this request.
2991
2992 --*/
2993 BOOLEAN
2994 NTAPI
2995 ClassInterpretSenseInfo(
2996 IN PDEVICE_OBJECT Fdo,
2997 IN PSCSI_REQUEST_BLOCK Srb,
2998 IN UCHAR MajorFunctionCode,
2999 IN ULONG IoDeviceCode,
3000 IN ULONG RetryCount,
3001 OUT NTSTATUS *Status,
3002 OUT OPTIONAL ULONG *RetryInterval
3003 )
3004 {
3005 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
3006 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
3007 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
3008
3009 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
3010
3011 BOOLEAN retry = TRUE;
3012 BOOLEAN logError = FALSE;
3013 BOOLEAN unhandledError = FALSE;
3014 BOOLEAN incrementErrorCount = FALSE;
3015
3016 ULONG badSector = 0;
3017 ULONG uniqueId = 0;
3018
3019 NTSTATUS logStatus;
3020
3021 ULONG readSector;
3022 ULONG index;
3023
3024 ULONG retryInterval = 0;
3025 KIRQL oldIrql;
3026
3027
3028 logStatus = -1;
3029
3030 if(TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) {
3031
3032 //
3033 // Log anything remotely incorrect about paging i/o
3034 //
3035
3036 logError = TRUE;
3037 uniqueId = 301;
3038 logStatus = IO_WARNING_PAGING_FAILURE;
3039 }
3040
3041 //
3042 // Check that request sense buffer is valid.
3043 //
3044
3045 ASSERT(fdoExtension->CommonExtension.IsFdo);
3046
3047
3048 //
3049 // must handle the SRB_STATUS_INTERNAL_ERROR case first,
3050 // as it has all the flags set.
3051 //
3052
3053 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR) {
3054
3055 DebugPrint((ClassDebugSenseInfo,
3056 "ClassInterpretSenseInfo: Internal Error code is %x\n",
3057 Srb->InternalStatus));
3058
3059 retry = FALSE;
3060 *Status = Srb->InternalStatus;
3061
3062 } else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
3063 (Srb->SenseInfoBufferLength >=
3064 offsetof(SENSE_DATA, CommandSpecificInformation))) {
3065
3066 //
3067 // Zero the additional sense code and additional sense code qualifier
3068 // if they were not returned by the device.
3069 //
3070
3071 readSector = senseBuffer->AdditionalSenseLength +
3072 offsetof(SENSE_DATA, AdditionalSenseLength);
3073
3074 if (readSector > Srb->SenseInfoBufferLength) {
3075 readSector = Srb->SenseInfoBufferLength;
3076 }
3077
3078 if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCode)) {
3079 senseBuffer->AdditionalSenseCode = 0;
3080 }
3081
3082 if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCodeQualifier)) {
3083 senseBuffer->AdditionalSenseCodeQualifier = 0;
3084 }
3085
3086 DebugPrint((ClassDebugSenseInfo,
3087 "ClassInterpretSenseInfo: Error code is %x\n",
3088 senseBuffer->ErrorCode));
3089 DebugPrint((ClassDebugSenseInfo,
3090 "ClassInterpretSenseInfo: Sense key is %x\n",
3091 senseBuffer->SenseKey));
3092 DebugPrint((ClassDebugSenseInfo,
3093 "ClassInterpretSenseInfo: Additional sense code is %x\n",
3094 senseBuffer->AdditionalSenseCode));
3095 DebugPrint((ClassDebugSenseInfo,
3096 "ClassInterpretSenseInfo: Additional sense code qualifier "
3097 "is %x\n",
3098 senseBuffer->AdditionalSenseCodeQualifier));
3099
3100
3101 switch (senseBuffer->SenseKey & 0xf) {
3102
3103 case SCSI_SENSE_NOT_READY: {
3104
3105 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3106 "Device not ready\n"));
3107 *Status = STATUS_DEVICE_NOT_READY;
3108
3109 switch (senseBuffer->AdditionalSenseCode) {
3110
3111 case SCSI_ADSENSE_LUN_NOT_READY: {
3112
3113 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3114 "Lun not ready\n"));
3115
3116 switch (senseBuffer->AdditionalSenseCodeQualifier) {
3117
3118 case SCSI_SENSEQ_OPERATION_IN_PROGRESS: {
3119 DEVICE_EVENT_BECOMING_READY notReady;
3120
3121 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3122 "Operation In Progress\n"));
3123 retryInterval = NOT_READY_RETRY_INTERVAL;
3124
3125 RtlZeroMemory(&notReady, sizeof(DEVICE_EVENT_BECOMING_READY));
3126 notReady.Version = 1;
3127 notReady.Reason = 2;
3128 notReady.Estimated100msToReady = retryInterval * 10;
3129 ClasspSendNotification(fdoExtension,
3130 &GUID_IO_DEVICE_BECOMING_READY,
3131 sizeof(DEVICE_EVENT_BECOMING_READY),
3132 &notReady);
3133
3134 break;
3135 }
3136
3137 case SCSI_SENSEQ_BECOMING_READY: {
3138 DEVICE_EVENT_BECOMING_READY notReady;
3139
3140 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3141 "In process of becoming ready\n"));
3142 retryInterval = NOT_READY_RETRY_INTERVAL;
3143
3144 RtlZeroMemory(&notReady, sizeof(DEVICE_EVENT_BECOMING_READY));
3145 notReady.Version = 1;
3146 notReady.Reason = 1;
3147 notReady.Estimated100msToReady = retryInterval * 10;
3148 ClasspSendNotification(fdoExtension,
3149 &GUID_IO_DEVICE_BECOMING_READY,
3150 sizeof(DEVICE_EVENT_BECOMING_READY),
3151 &notReady);
3152 break;
3153 }
3154
3155 case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: {
3156 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3157 "Long write in progress\n"));
3158 retry = FALSE;
3159 break;
3160 }
3161
3162 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: {
3163 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3164 "Manual intervention required\n"));
3165 *Status = STATUS_NO_MEDIA_IN_DEVICE;
3166 retry = FALSE;
3167 break;
3168 }
3169
3170 case SCSI_SENSEQ_FORMAT_IN_PROGRESS: {
3171 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3172 "Format in progress\n"));
3173 retry = FALSE;
3174 break;
3175 }
3176
3177 case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: {
3178
3179 if(!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
3180 CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK)) {
3181
3182 DebugPrint((ClassDebugSenseInfo,
3183 "ClassInterpretSenseInfo: "
3184 "not ready, cause unknown\n"));
3185 /*
3186 Many non-WHQL certified drives (mostly CD-RW) return
3187 this when they have no media instead of the obvious
3188 choice of:
3189
3190 SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
3191
3192 These drives should not pass WHQL certification due
3193 to this discrepency.
3194
3195 */
3196 retry = FALSE;
3197 break;
3198
3199 } else {
3200
3201 //
3202 // Treat this as init command required and fall through.
3203 //
3204 }
3205 }
3206
3207 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
3208 default: {
3209 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3210 "Initializing command required\n"));
3211
3212 //
3213 // This sense code/additional sense code
3214 // combination may indicate that the device
3215 // needs to be started. Send an start unit if this
3216 // is a disk device.
3217 //
3218
3219 if(TEST_FLAG(fdoExtension->DeviceFlags,
3220 DEV_SAFE_START_UNIT) &&
3221 !TEST_FLAG(Srb->SrbFlags,
3222 SRB_CLASS_FLAGS_LOW_PRIORITY)) {
3223 ClassSendStartUnit(Fdo);
3224 }
3225 break;
3226 }
3227
3228
3229 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
3230 break;
3231 }
3232
3233 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: {
3234 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3235 "No Media in device.\n"));
3236 *Status = STATUS_NO_MEDIA_IN_DEVICE;
3237 retry = FALSE;
3238
3239 //
3240 // signal MCN that there isn't any media in the device
3241 //
3242 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
3243 DebugPrint((ClassDebugError, "ClassInterpretSenseInfo: "
3244 "No Media in a non-removable device %p\n",
3245 Fdo));
3246 }
3247 ClassSetMediaChangeState(fdoExtension, MediaNotPresent, FALSE);
3248
3249 break;
3250 }
3251 } // end switch (senseBuffer->AdditionalSenseCode)
3252
3253 break;
3254 } // end SCSI_SENSE_NOT_READY
3255
3256 case SCSI_SENSE_DATA_PROTECT: {
3257 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3258 "Media write protected\n"));
3259 *Status = STATUS_MEDIA_WRITE_PROTECTED;
3260 retry = FALSE;
3261 break;
3262 } // end SCSI_SENSE_DATA_PROTECT
3263
3264 case SCSI_SENSE_MEDIUM_ERROR: {
3265 DebugPrint((ClassDebugSenseInfo,"ClassInterpretSenseInfo: "
3266 "Medium Error (bad block)\n"));
3267 *Status = STATUS_DEVICE_DATA_ERROR;
3268
3269 retry = FALSE;
3270 logError = TRUE;
3271 uniqueId = 256;
3272 logStatus = IO_ERR_BAD_BLOCK;
3273
3274 //
3275 // Check if this error is due to unknown format
3276 //
3277 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_INVALID_MEDIA){
3278
3279 switch (senseBuffer->AdditionalSenseCodeQualifier) {
3280
3281 case SCSI_SENSEQ_UNKNOWN_FORMAT: {
3282
3283 *Status = STATUS_UNRECOGNIZED_MEDIA;
3284
3285 //
3286 // Log error only if this is a paging request
3287 //
3288 if(!TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) {
3289 logError = FALSE;
3290 }
3291 break;
3292 }
3293
3294 case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED: {
3295
3296 *Status = STATUS_CLEANER_CARTRIDGE_INSTALLED;
3297 logError = FALSE;
3298 break;
3299
3300 }
3301 default: {
3302 break;
3303 }
3304 } // end switch AdditionalSenseCodeQualifier
3305
3306 } // end SCSI_ADSENSE_INVALID_MEDIA
3307
3308 break;
3309
3310 } // end SCSI_SENSE_MEDIUM_ERROR
3311
3312 case SCSI_SENSE_HARDWARE_ERROR: {
3313 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3314 "Hardware error\n"));
3315 *Status = STATUS_IO_DEVICE_ERROR;
3316 logError = TRUE;
3317 uniqueId = 257;
3318 logStatus = IO_ERR_CONTROLLER_ERROR;
3319 break;
3320 } // end SCSI_SENSE_HARDWARE_ERROR
3321
3322 case SCSI_SENSE_ILLEGAL_REQUEST: {
3323
3324 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3325 "Illegal SCSI request\n"));
3326 *Status = STATUS_INVALID_DEVICE_REQUEST;
3327 retry = FALSE;
3328
3329 switch (senseBuffer->AdditionalSenseCode) {
3330
3331 case SCSI_ADSENSE_ILLEGAL_COMMAND: {
3332 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3333 "Illegal command\n"));
3334 break;
3335 }
3336
3337 case SCSI_ADSENSE_ILLEGAL_BLOCK: {
3338 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3339 "Illegal block address\n"));
3340 *Status = STATUS_NONEXISTENT_SECTOR;
3341 break;
3342 }
3343
3344 case SCSI_ADSENSE_INVALID_LUN: {
3345 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3346 "Invalid LUN\n"));
3347 *Status = STATUS_NO_SUCH_DEVICE;
3348 break;
3349 }
3350
3351 case SCSI_ADSENSE_MUSIC_AREA: {
3352 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3353 "Music area\n"));
3354 break;
3355 }
3356
3357 case SCSI_ADSENSE_DATA_AREA: {
3358 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3359 "Data area\n"));
3360 break;
3361 }
3362
3363 case SCSI_ADSENSE_VOLUME_OVERFLOW: {
3364 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3365 "Volume overflow\n"));
3366 break;
3367 }
3368
3369 case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: {
3370 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3371 "Copy protection failure\n"));
3372
3373 *Status = STATUS_COPY_PROTECTION_FAILURE;
3374
3375 switch (senseBuffer->AdditionalSenseCodeQualifier) {
3376 case SCSI_SENSEQ_AUTHENTICATION_FAILURE:
3377 DebugPrint((ClassDebugSenseInfo,
3378 "ClassInterpretSenseInfo: "
3379 "Authentication failure\n"));
3380 *Status = STATUS_CSS_AUTHENTICATION_FAILURE;
3381 break;
3382 case SCSI_SENSEQ_KEY_NOT_PRESENT:
3383 DebugPrint((ClassDebugSenseInfo,
3384 "ClassInterpretSenseInfo: "
3385 "Key not present\n"));
3386 *Status = STATUS_CSS_KEY_NOT_PRESENT;
3387 break;
3388 case SCSI_SENSEQ_KEY_NOT_ESTABLISHED:
3389 DebugPrint((ClassDebugSenseInfo,
3390 "ClassInterpretSenseInfo: "
3391 "Key not established\n"));
3392 *Status = STATUS_CSS_KEY_NOT_ESTABLISHED;
3393 break;
3394 case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION:
3395 DebugPrint((ClassDebugSenseInfo,
3396 "ClassInterpretSenseInfo: "
3397 "Read of scrambled sector w/o "
3398 "authentication\n"));
3399 *Status = STATUS_CSS_SCRAMBLED_SECTOR;
3400 break;
3401 case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT:
3402 DebugPrint((ClassDebugSenseInfo,
3403 "ClassInterpretSenseInfo: "
3404 "Media region does not logical unit "
3405 "region\n"));
3406 *Status = STATUS_CSS_REGION_MISMATCH;
3407 break;
3408 case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR:
3409 DebugPrint((ClassDebugSenseInfo,
3410 "ClassInterpretSenseInfo: "
3411 "Region set error -- region may "
3412 "be permanent\n"));
3413 *Status = STATUS_CSS_RESETS_EXHAUSTED;
3414 break;
3415 } // end switch of ASCQ for COPY_PROTECTION_FAILURE
3416
3417 break;
3418 }
3419
3420
3421 case SCSI_ADSENSE_INVALID_CDB: {
3422 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3423 "Invalid CDB\n"));
3424
3425 //
3426 // Note: the retry interval is not typically used.
3427 // it is set here only because a ClassErrorHandler
3428 // cannot set the retryInterval, and the error may
3429 // require a few commands to be sent to clear whatever
3430 // caused this condition (i.e. disk clears the write
3431 // cache, requiring at least two commands)
3432 //
3433 // hopefully, this shortcoming can be changed for
3434 // blackcomb.
3435 //
3436
3437 retryInterval = 3;
3438 break;
3439 }
3440
3441 } // end switch (senseBuffer->AdditionalSenseCode)
3442
3443 break;
3444 } // end SCSI_SENSE_ILLEGAL_REQUEST
3445
3446 case SCSI_SENSE_UNIT_ATTENTION: {
3447
3448 //PVPB vpb;
3449 ULONG count;
3450
3451 //
3452 // A media change may have occured so increment the change
3453 // count for the physical device
3454 //
3455
3456 count = InterlockedIncrement(&fdoExtension->MediaChangeCount);
3457 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3458 "Media change count for device %d incremented to %#lx\n",
3459 fdoExtension->DeviceNumber, count));
3460
3461
3462 switch (senseBuffer->AdditionalSenseCode) {
3463 case SCSI_ADSENSE_MEDIUM_CHANGED: {
3464 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3465 "Media changed\n"));
3466
3467 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
3468 DebugPrint((ClassDebugError, "ClassInterpretSenseInfo: "
3469 "Media Changed on non-removable device %p\n",
3470 Fdo));
3471 }
3472 ClassSetMediaChangeState(fdoExtension, MediaPresent, FALSE);
3473 break;
3474 }
3475
3476 case SCSI_ADSENSE_BUS_RESET: {
3477 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3478 "Bus reset\n"));
3479 break;
3480 }
3481
3482 case SCSI_ADSENSE_OPERATOR_REQUEST: {
3483 switch (senseBuffer->AdditionalSenseCodeQualifier) {
3484
3485 case SCSI_SENSEQ_MEDIUM_REMOVAL: {
3486 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3487 "Ejection request received!\n"));
3488 ClassSendEjectionNotification(fdoExtension);
3489 break;
3490 }
3491
3492 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: {
3493 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3494 "Operator selected write permit?! "
3495 "(unsupported!)\n"));
3496 break;
3497 }
3498
3499 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE: {
3500 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3501 "Operator selected write protect?! "
3502 "(unsupported!)\n"));
3503 break;
3504 }
3505
3506 }
3507 break;
3508 }
3509
3510 default: {
3511 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3512 "Unit attention\n"));
3513 break;
3514 }
3515
3516 } // end switch (senseBuffer->AdditionalSenseCode)
3517
3518 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA))
3519 {
3520 //
3521 // TODO : Is the media lockable?
3522 //
3523
3524 if ((ClassGetVpb(Fdo) != NULL) && (ClassGetVpb(Fdo)->Flags & VPB_MOUNTED))
3525 {
3526 //
3527 // Set bit to indicate that media may have changed
3528 // and volume needs verification.
3529 //
3530
3531 SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME);
3532
3533 *Status = STATUS_VERIFY_REQUIRED;
3534 retry = FALSE;
3535 }
3536 }
3537 else
3538 {
3539 *Status = STATUS_IO_DEVICE_ERROR;
3540 }
3541
3542 break;
3543
3544 } // end SCSI_SENSE_UNIT_ATTENTION
3545
3546 case SCSI_SENSE_ABORTED_COMMAND: {
3547 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3548 "Command aborted\n"));
3549 *Status = STATUS_IO_DEVICE_ERROR;
3550 retryInterval = 1;
3551 break;
3552 } // end SCSI_SENSE_ABORTED_COMMAND
3553
3554 case SCSI_SENSE_BLANK_CHECK: {
3555 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3556 "Media blank check\n"));
3557 retry = FALSE;
3558 *Status = STATUS_NO_DATA_DETECTED;
3559 break;
3560 } // end SCSI_SENSE_BLANK_CHECK
3561
3562 case SCSI_SENSE_RECOVERED_ERROR: {
3563
3564 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3565 "Recovered error\n"));
3566 *Status = STATUS_SUCCESS;
3567 retry = FALSE;
3568 logError = TRUE;
3569 uniqueId = 258;
3570
3571 switch(senseBuffer->AdditionalSenseCode) {
3572 case SCSI_ADSENSE_SEEK_ERROR:
3573 case SCSI_ADSENSE_TRACK_ERROR: {
3574 logStatus = IO_ERR_SEEK_ERROR;
3575 break;
3576 }
3577
3578 case SCSI_ADSENSE_REC_DATA_NOECC:
3579 case SCSI_ADSENSE_REC_DATA_ECC: {
3580 logStatus = IO_RECOVERED_VIA_ECC;
3581 break;
3582 }
3583
3584 case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED: {
3585 UCHAR wmiEventData[5];
3586
3587 *((PULONG)wmiEventData) = sizeof(UCHAR);
3588 wmiEventData[sizeof(ULONG)] = senseBuffer->AdditionalSenseCodeQualifier;
3589
3590 //
3591 // Don't log another eventlog if we have already logged once
3592 // NOTE: this should have been interlocked, but the structure
3593 // was publicly defined to use a BOOLEAN (char). Since
3594 // media only reports these errors once per X minutes,
3595 // the potential race condition is nearly non-existant.
3596 // the worst case is duplicate log entries, so ignore.
3597 //
3598
3599 if (fdoExtension->FailurePredicted == 0) {
3600 logError = TRUE;
3601 }
3602 fdoExtension->FailurePredicted = TRUE;
3603 fdoExtension->FailureReason = senseBuffer->AdditionalSenseCodeQualifier;
3604 logStatus = IO_WRN_FAILURE_PREDICTED;
3605
3606 ClassNotifyFailurePredicted(fdoExtension,
3607 (PUCHAR)&wmiEventData,
3608 sizeof(wmiEventData),
3609 0,
3610 4,
3611 Srb->PathId,
3612 Srb->TargetId,
3613 Srb->Lun);
3614 break;
3615 }
3616
3617 default: {
3618 logStatus = IO_ERR_CONTROLLER_ERROR;
3619 break;
3620 }
3621
3622 } // end switch(senseBuffer->AdditionalSenseCode)
3623
3624 if (senseBuffer->IncorrectLength) {
3625
3626 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3627 "Incorrect length detected.\n"));
3628 *Status = STATUS_INVALID_BLOCK_LENGTH ;
3629 }
3630
3631 break;
3632 } // end SCSI_SENSE_RECOVERED_ERROR
3633
3634 case SCSI_SENSE_NO_SENSE: {
3635
3636 //
3637 // Check other indicators.
3638 //
3639
3640 if (senseBuffer->IncorrectLength) {
3641
3642 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3643 "Incorrect length detected.\n"));
3644 *Status = STATUS_INVALID_BLOCK_LENGTH ;
3645 retry = FALSE;
3646
3647 } else {
3648
3649 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3650 "No specific sense key\n"));
3651 *Status = STATUS_IO_DEVICE_ERROR;
3652 retry = TRUE;
3653 }
3654
3655 break;
3656 } // end SCSI_SENSE_NO_SENSE
3657
3658 default: {
3659 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3660 "Unrecognized sense code\n"));
3661 *Status = STATUS_IO_DEVICE_ERROR;
3662 break;
3663 }
3664
3665 } // end switch (senseBuffer->SenseKey & 0xf)
3666
3667 //
3668 // Try to determine the bad sector from the inquiry data.
3669 //
3670
3671 if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ ||
3672 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY ||
3673 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) {
3674
3675 for (index = 0; index < 4; index++) {
3676 badSector = (badSector << 8) | senseBuffer->Information[index];
3677 }
3678
3679 readSector = 0;
3680 for (index = 0; index < 4; index++) {
3681 readSector = (readSector << 8) | Srb->Cdb[index+2];
3682 }
3683
3684 index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) |
3685 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
3686
3687 //
3688 // Make sure the bad sector is within the read sectors.
3689 //
3690
3691 if (!(badSector >= readSector && badSector < readSector + index)) {
3692 badSector = readSector;
3693 }
3694 }
3695
3696 } else {
3697
3698 //
3699 // Request sense buffer not valid. No sense information
3700 // to pinpoint the error. Return general request fail.
3701 //
3702
3703 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
3704 "Request sense info not valid. SrbStatus %2x\n",
3705 SRB_STATUS(Srb->SrbStatus)));
3706 retry = TRUE;
3707
3708 switch (SRB_STATUS(Srb->SrbStatus)) {
3709 case SRB_STATUS_INVALID_LUN:
3710 case SRB_STATUS_INVALID_TARGET_ID:
3711 case SRB_STATUS_NO_DEVICE:
3712 case SRB_STATUS_NO_HBA:
3713 case SRB_STATUS_INVALID_PATH_ID: {
3714 *Status = STATUS_NO_SUCH_DEVICE;
3715 retry = FALSE;
3716 break;
3717 }
3718
3719 case SRB_STATUS_COMMAND_TIMEOUT:
3720 case SRB_STATUS_TIMEOUT: {
3721
3722 //
3723 // Update the error count for the device.
3724 //
3725
3726 incrementErrorCount = TRUE;
3727 *Status = STATUS_IO_TIMEOUT;
3728 break;
3729 }
3730
3731 case SRB_STATUS_ABORTED: {
3732
3733 //
3734 // Update the error count for the device.
3735 //
3736
3737 incrementErrorCount = TRUE;
3738 *Status = STATUS_IO_TIMEOUT;
3739 retryInterval = 1;
3740 break;
3741 }
3742
3743
3744 case SRB_STATUS_SELECTION_TIMEOUT: {
3745 logError = TRUE;
3746 logStatus = IO_ERR_NOT_READY;
3747 uniqueId = 260;
3748 *Status = STATUS_DEVICE_NOT_CONNECTED;
3749 retry = FALSE;
3750 break;
3751 }
3752
3753 case SRB_STATUS_DATA_OVERRUN: {
3754 *Status = STATUS_DATA_OVERRUN;
3755 retry = FALSE;
3756 break;
3757 }
3758
3759 case SRB_STATUS_PHASE_SEQUENCE_FAILURE: {
3760
3761 //
3762 // Update the error count for the device.
3763 //
3764
3765 incrementErrorCount = TRUE;
3766 *Status = STATUS_IO_DEVICE_ERROR;
3767
3768 //
3769 // If there was phase sequence error then limit the number of
3770 // retries.
3771 //
3772
3773 if (RetryCount > 1 ) {
3774 retry = FALSE;
3775 }
3776
3777 break;
3778 }
3779
3780 case SRB_STATUS_REQUEST_FLUSHED: {
3781
3782 //
3783 // If the status needs verification bit is set. Then set
3784 // the status to need verification and no retry; otherwise,
3785 // just retry the request.
3786 //
3787
3788 if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME)) {
3789
3790 *Status = STATUS_VERIFY_REQUIRED;
3791 retry = FALSE;
3792
3793 } else {
3794 *Status = STATUS_IO_DEVICE_ERROR;
3795 }
3796
3797 break;
3798 }
3799
3800 case SRB_STATUS_INVALID_REQUEST: {
3801 *Status = STATUS_INVALID_DEVICE_REQUEST;
3802 retry = FALSE;
3803 break;
3804 }
3805
3806 case SRB_STATUS_UNEXPECTED_BUS_FREE:
3807 case SRB_STATUS_PARITY_ERROR:
3808
3809 //
3810 // Update the error count for the device
3811 // and fall through to below
3812 //
3813
3814 incrementErrorCount = TRUE;
3815
3816 case SRB_STATUS_BUS_RESET: {
3817 *Status = STATUS_IO_DEVICE_ERROR;
3818 break;
3819 }
3820
3821 case SRB_STATUS_ERROR: {
3822
3823 *Status = STATUS_IO_DEVICE_ERROR;
3824 if (Srb->ScsiStatus == 0) {
3825
3826 //
3827 // This is some strange return code. Update the error
3828 // count for the device.
3829 //
3830
3831 incrementErrorCount = TRUE;
3832
3833 } if (Srb->ScsiStatus == SCSISTAT_BUSY) {
3834
3835 *Status = STATUS_DEVICE_NOT_READY;
3836
3837 } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) {
3838
3839 *Status = STATUS_DEVICE_BUSY;
3840 retry = FALSE;
3841 logError = FALSE;
3842
3843 }
3844
3845 break;
3846 }
3847
3848 default: {
3849 logError = TRUE;
3850 logStatus = IO_ERR_CONTROLLER_ERROR;
3851 uniqueId = 259;
3852 *Status = STATUS_IO_DEVICE_ERROR;
3853 unhandledError = TRUE;
3854 break;
3855 }
3856
3857 }
3858
3859 //
3860 // NTRAID #183546 - if we support GESN subtype NOT_READY events, and
3861 // we know from a previous poll when the device will be ready (ETA)
3862 // we should delay the retry more appropriately than just guessing.
3863 //
3864 /*
3865 if (fdoExtension->MediaChangeDetectionInfo &&
3866 fdoExtension->MediaChangeDetectionInfo->Gesn.Supported &&
3867 TEST_FLAG(fdoExtension->MediaChangeDetectionInfo->Gesn.EventMask,
3868 NOTIFICATION_DEVICE_BUSY_CLASS_MASK)
3869 ) {
3870 // check if Gesn.ReadyTime if greater than current tick count
3871 // if so, delay that long (from 1 to 30 seconds max?)
3872 // else, leave the guess of time alone.
3873 }
3874 */
3875
3876 }
3877
3878 if (incrementErrorCount) {
3879
3880 //
3881 // if any error count occurred, delay the retry of this io by
3882 // at least one second, if caller supports it.
3883 //
3884
3885 if (retryInterval == 0) {
3886 retryInterval = 1;
3887 }
3888 ClasspPerfIncrementErrorCount(fdoExtension);
3889 }
3890
3891 //
3892 // If there is a class specific error handler call it.
3893 //
3894
3895 if (fdoExtension->CommonExtension.DevInfo->ClassError != NULL) {
3896
3897 fdoExtension->CommonExtension.DevInfo->ClassError(Fdo,
3898 Srb,
3899 Status,
3900 &retry);
3901 }
3902
3903 //
3904 // If the caller wants to know the suggested retry interval tell them.
3905 //
3906
3907 if(ARGUMENT_PRESENT(RetryInterval)) {
3908 *RetryInterval = retryInterval;
3909 }
3910
3911
3912 /*
3913 * LOG the error:
3914 * Always log the error in our internal log.
3915 * If logError is set, also log the error in the system log.
3916 */
3917 {
3918 ULONG totalSize;
3919 ULONG senseBufferSize = 0;
3920 IO_ERROR_LOG_PACKET staticErrLogEntry = {0};
3921 CLASS_ERROR_LOG_DATA staticErrLogData = {0};
3922
3923 //
3924 // Calculate the total size of the error log entry.
3925 // add to totalSize in the order that they are used.
3926 // the advantage to calculating all the sizes here is
3927 // that we don't have to do a bunch of extraneous checks
3928 // later on in this code path.
3929 //
3930 totalSize = sizeof(IO_ERROR_LOG_PACKET) // required
3931 - sizeof(ULONG) // struct includes one ULONG
3932 + sizeof(CLASS_ERROR_LOG_DATA);// struct for ease
3933
3934 //
3935 // also save any available extra sense data, up to the maximum errlog
3936 // packet size . WMI should be used for real-time analysis.
3937 // the event log should only be used for post-mortem debugging.
3938 //
3939 if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
3940 ULONG validSenseBytes;
3941 BOOLEAN validSense;
3942
3943 //
3944 // make sure we can at least access the AdditionalSenseLength field
3945 //
3946 validSense = RTL_CONTAINS_FIELD(senseBuffer,
3947 Srb->SenseInfoBufferLength,
3948 AdditionalSenseLength);
3949 if (validSense) {
3950
3951 //
3952 // if extra info exists, copy the maximum amount of available
3953 // sense data that is safe into the the errlog.
3954 //
3955 validSenseBytes = senseBuffer->AdditionalSenseLength
3956 + offsetof(SENSE_DATA, AdditionalSenseLength);
3957
3958 //
3959 // this is invalid because it causes overflow!
3960 // whoever sent this type of request would cause
3961 // a system crash.
3962 //
3963 ASSERT(validSenseBytes < MAX_ADDITIONAL_SENSE_BYTES);
3964
3965 //
3966 // set to save the most sense buffer possible
3967 //
3968 senseBufferSize = max(validSenseBytes, sizeof(SENSE_DATA));
3969 senseBufferSize = min(senseBufferSize, Srb->SenseInfoBufferLength);
3970 } else {
3971 //
3972 // it's smaller than required to read the total number of
3973 // valid bytes, so just use the SenseInfoBufferLength field.
3974 //
3975 senseBufferSize = Srb->SenseInfoBufferLength;
3976 }
3977
3978 /*
3979 * Bump totalSize by the number of extra senseBuffer bytes
3980 * (beyond the default sense buffer within CLASS_ERROR_LOG_DATA).
3981 * Make sure to never allocate more than ERROR_LOG_MAXIMUM_SIZE.
3982 */
3983 if (senseBufferSize > sizeof(SENSE_DATA)){
3984 totalSize += senseBufferSize-sizeof(SENSE_DATA);
3985 if (totalSize > ERROR_LOG_MAXIMUM_SIZE){
3986 senseBufferSize -= totalSize-ERROR_LOG_MAXIMUM_SIZE;
3987 totalSize = ERROR_LOG_MAXIMUM_SIZE;
3988 }
3989 }
3990 }
3991
3992 //
3993 // If we've used up all of our retry attempts, set the final status to
3994 // reflect the appropriate result.
3995 //
3996 if (retry && RetryCount < MAXIMUM_RETRIES) {
3997 staticErrLogEntry.FinalStatus = STATUS_SUCCESS;
3998 staticErrLogData.ErrorRetried = TRUE;
3999 } else {
4000 staticErrLogEntry.FinalStatus = *Status;
4001 }
4002 if (TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) {
4003 staticErrLogData.ErrorPaging = TRUE;
4004 }
4005 if (unhandledError) {
4006 staticErrLogData.ErrorUnhandled = TRUE;
4007 }
4008
4009 //
4010 // Calculate the device offset if there is a geometry.
4011 //
4012 staticErrLogEntry.DeviceOffset.QuadPart = (LONGLONG)badSector;
4013 staticErrLogEntry.DeviceOffset.QuadPart *= (LONGLONG)fdoExtension->DiskGeometry.BytesPerSector;
4014 if (logStatus == -1){
4015 staticErrLogEntry.ErrorCode = STATUS_IO_DEVICE_ERROR;
4016 } else {
4017 staticErrLogEntry.ErrorCode = logStatus;
4018 }
4019
4020 /*
4021 * The dump data follows the IO_ERROR_LOG_PACKET,
4022 * with the first ULONG of dump data inside the packet.
4023 */
4024 staticErrLogEntry.DumpDataSize = (USHORT)totalSize - sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG);
4025
4026 staticErrLogEntry.SequenceNumber = 0;
4027 staticErrLogEntry.MajorFunctionCode = MajorFunctionCode;
4028 staticErrLogEntry.IoControlCode = IoDeviceCode;
4029 staticErrLogEntry.RetryCount = (UCHAR) RetryCount;
4030 staticErrLogEntry.UniqueErrorValue = uniqueId;
4031
4032 KeQueryTickCount(&staticErrLogData.TickCount);
4033 staticErrLogData.PortNumber = (ULONG)-1;
4034
4035 /*
4036 * Save the entire contents of the SRB.
4037 */
4038 staticErrLogData.Srb = *Srb;
4039
4040 /*
4041 * For our private log, save just the default length of the SENSE_DATA.
4042 */
4043 if (senseBufferSize != 0){
4044 RtlCopyMemory(&staticErrLogData.SenseData, senseBuffer, min(senseBufferSize, sizeof(SENSE_DATA)));
4045 }
4046
4047 /*
4048 * Save the error log in our context.
4049 * We only save the default sense buffer length.
4050 */
4051 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
4052 fdoData->ErrorLogs[fdoData->ErrorLogNextIndex] = staticErrLogData;
4053 fdoData->ErrorLogNextIndex++;
4054 fdoData->ErrorLogNextIndex %= NUM_ERROR_LOG_ENTRIES;
4055 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
4056
4057 /*
4058 * If logError is set, also save this log in the system's error log.
4059 * But make sure we don't log TUR failures over and over
4060 * (e.g. if an external drive was switched off and we're still sending TUR's to it every second).
4061 */
4062 if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_TEST_UNIT_READY) && logError){
4063 if (fdoData->LoggedTURFailureSinceLastIO){
4064 logError = FALSE;
4065 }
4066 else {
4067 fdoData->LoggedTURFailureSinceLastIO = TRUE;
4068 }
4069 }
4070 if (logError){
4071 PIO_ERROR_LOG_PACKET errorLogEntry;
4072 PCLASS_ERROR_LOG_DATA errlogData;
4073
4074 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(Fdo, (UCHAR)totalSize);
4075 if (errorLogEntry){
4076 errlogData = (PCLASS_ERROR_LOG_DATA)errorLogEntry->DumpData;
4077
4078 *errorLogEntry = staticErrLogEntry;
4079 *errlogData = staticErrLogData;
4080
4081 /*
4082 * For the system log, copy as much of the sense buffer as possible.
4083 */
4084 if (senseBufferSize != 0) {
4085 RtlCopyMemory(&errlogData->SenseData, senseBuffer, senseBufferSize);
4086 }
4087
4088 /*
4089 * Write the error log packet to the system error logging thread.
4090 */
4091 IoWriteErrorLogEntry(errorLogEntry);
4092 }
4093 }
4094 }
4095
4096 return retry;
4097
4098 } // end ClassInterpretSenseInfo()
4099
4100 /*++////////////////////////////////////////////////////////////////////////////
4101
4102 ClassModeSense()
4103
4104 Routine Description:
4105
4106 This routine sends a mode sense command to a target ID and returns
4107 when it is complete.
4108
4109 Arguments:
4110
4111 Fdo - Supplies the functional device object associated with this request.
4112
4113 ModeSenseBuffer - Supplies a buffer to store the sense data.
4114
4115 Length - Supplies the length in bytes of the mode sense buffer.
4116
4117 PageMode - Supplies the page or pages of mode sense data to be retrived.
4118
4119 Return Value:
4120
4121 Length of the transferred data is returned.
4122
4123 --*/
4124 ULONG NTAPI ClassModeSense( IN PDEVICE_OBJECT Fdo,
4125 IN PCHAR ModeSenseBuffer,
4126 IN ULONG Length,
4127 IN UCHAR PageMode)
4128 {
4129 ULONG lengthTransferred = 0;
4130 PMDL senseBufferMdl;
4131
4132 PAGED_CODE();
4133
4134 senseBufferMdl = BuildDeviceInputMdl(ModeSenseBuffer, Length);
4135 if (senseBufferMdl){
4136
4137 TRANSFER_PACKET *pkt = DequeueFreeTransferPacket(Fdo, TRUE);
4138 if (pkt){
4139 KEVENT event;
4140 //NTSTATUS pktStatus;
4141 IRP pseudoIrp = {0};
4142
4143 /*
4144 * Store the number of packets servicing the irp (one)
4145 * inside the original IRP. It will be used to counted down
4146 * to zero when the packet completes.
4147 * Initialize the original IRP's status to success.
4148 * If the packet fails, we will set it to the error status.
4149 */
4150 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
4151 pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
4152 pseudoIrp.IoStatus.Information = 0;
4153 pseudoIrp.MdlAddress = senseBufferMdl;
4154
4155 /*
4156 * Set this up as a SYNCHRONOUS transfer, submit it,
4157 * and wait for the packet to complete. The result
4158 * status will be written to the original irp.
4159 */
4160 ASSERT(Length <= 0x0ff);
4161 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
4162 SetupModeSenseTransferPacket(pkt, &event, ModeSenseBuffer, (UCHAR)Length, PageMode, &pseudoIrp);
4163 SubmitTransferPacket(pkt);
4164 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
4165
4166 if (NT_SUCCESS(pseudoIrp.IoStatus.Status)){
4167 lengthTransferred = (ULONG)pseudoIrp.IoStatus.Information;
4168 }
4169 else {
4170 /*
4171 * This request can sometimes fail legitimately
4172 * (e.g. when a SCSI device is attached but turned off)
4173 * so this is not necessarily a device/driver bug.
4174 */
4175 DBGTRACE(ClassDebugWarning, ("ClassModeSense on Fdo %ph failed with status %xh.", Fdo, pseudoIrp.IoStatus.Status));
4176 }
4177 }
4178
4179 FreeDeviceInputMdl(senseBufferMdl);
4180 }
4181
4182 return lengthTransferred;
4183 }
4184
4185 /*++////////////////////////////////////////////////////////////////////////////
4186
4187 ClassFindModePage()
4188
4189 Routine Description:
4190
4191 This routine scans through the mode sense data and finds the requested
4192 mode sense page code.
4193
4194 Arguments:
4195 ModeSenseBuffer - Supplies a pointer to the mode sense data.
4196
4197 Length - Indicates the length of valid data.
4198
4199 PageMode - Supplies the page mode to be searched for.
4200
4201 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
4202
4203 Return Value:
4204
4205 A pointer to the the requested mode page. If the mode page was not found
4206 then NULL is return.
4207
4208 --*/
4209 PVOID
4210 NTAPI
4211 ClassFindModePage(
4212 IN PCHAR ModeSenseBuffer,
4213 IN ULONG Length,
4214 IN UCHAR PageMode,
4215 IN BOOLEAN Use6Byte
4216 )
4217 {
4218 PUCHAR limit;
4219 ULONG parameterHeaderLength;
4220 PVOID result = NULL;
4221
4222 limit = ModeSenseBuffer + Length;
4223 parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);
4224
4225 if (Length >= parameterHeaderLength) {
4226
4227 PMODE_PARAMETER_HEADER10 modeParam10;
4228 ULONG blockDescriptorLength;
4229
4230 /*
4231 * Skip the mode select header and block descriptors.
4232 */
4233 if (Use6Byte){
4234 blockDescriptorLength = ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength;
4235 }
4236 else {
4237 modeParam10 = (PMODE_PARAMETER_HEADER10) ModeSenseBuffer;
4238 blockDescriptorLength = modeParam10->BlockDescriptorLength[1];
4239 }
4240
4241 ModeSenseBuffer += parameterHeaderLength + blockDescriptorLength;
4242
4243 //
4244 // ModeSenseBuffer now points at pages. Walk the pages looking for the
4245 // requested page until the limit is reached.
4246 //
4247
4248 while (ModeSenseBuffer +
4249 RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength) < limit) {
4250
4251 if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
4252
4253 /*
4254 * found the mode page. make sure it's safe to touch it all
4255 * before returning the pointer to caller
4256 */
4257
4258 if (ModeSenseBuffer + ((PMODE_DISCONNECT_PAGE)ModeSenseBuffer)->PageLength > limit) {
4259 /*
4260 * Return NULL since the page is not safe to access in full
4261 */
4262 result = NULL;
4263 }
4264 else {
4265 result = ModeSenseBuffer;
4266 }
4267 break;
4268 }
4269
4270 //
4271 // Advance to the next page which is 4-byte-aligned offset after this page.
4272 //
4273 ModeSenseBuffer +=
4274 ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength +
4275 RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength);
4276
4277 }
4278 }
4279
4280 return result;
4281 } // end ClassFindModePage()
4282
4283 /*++////////////////////////////////////////////////////////////////////////////
4284
4285 ClassSendSrbAsynchronous()
4286
4287 Routine Description:
4288
4289 This routine takes a partially built Srb and an Irp and sends it down to
4290 the port driver.
4291
4292 This routine must be called with the remove lock held for the specified
4293 Irp.
4294
4295 Arguments:
4296
4297 Fdo - Supplies the functional device object for the orginal request.
4298
4299 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
4300 CDB and the SRB timeout value must be filled in. The SRB must not be
4301 allocated from zone.
4302
4303 Irp - Supplies the requesting Irp.
4304
4305 BufferAddress - Supplies a pointer to the buffer to be transfered.
4306
4307 BufferLength - Supplies the length of data transfer.
4308
4309 WriteToDevice - Indicates the data transfer will be from system memory to
4310 device.
4311
4312 Return Value:
4313
4314 Returns STATUS_PENDING if the request is dispatched (since the
4315 completion routine may change the irp's status value we cannot simply
4316 return the value of the dispatch)
4317
4318 or returns a status value to indicate why it failed.
4319
4320 --*/
4321 NTSTATUS
4322 NTAPI
4323 ClassSendSrbAsynchronous(
4324 PDEVICE_OBJECT Fdo,
4325 PSCSI_REQUEST_BLOCK Srb,
4326 PIRP Irp,
4327 PVOID BufferAddress,
4328 ULONG BufferLength,
4329 BOOLEAN WriteToDevice
4330 )
4331 {
4332
4333 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
4334 PIO_STACK_LOCATION irpStack;
4335
4336 ULONG savedFlags;
4337
4338 //
4339 // Write length to SRB.
4340 //
4341
4342 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
4343
4344 //
4345 // Set SCSI bus address.
4346 //
4347
4348 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4349
4350 //
4351 // This is a violation of the SCSI spec but it is required for
4352 // some targets.
4353 //
4354
4355 // Srb->Cdb[1] |= deviceExtension->Lun << 5;
4356
4357 //
4358 // Indicate auto request sense by specifying buffer and size.
4359 //
4360
4361 Srb->SenseInfoBuffer = fdoExtension->SenseData;
4362 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
4363 Srb->DataBuffer = BufferAddress;
4364
4365 //
4366 // Save the class driver specific flags away.
4367 //
4368
4369 savedFlags = Srb->SrbFlags & SRB_FLAGS_CLASS_DRIVER_RESERVED;
4370
4371 //
4372 // Allow the caller to specify that they do not wish
4373 // IoStartNextPacket() to be called in the completion routine.
4374 //
4375
4376 SET_FLAG(savedFlags, (Srb->SrbFlags & SRB_FLAGS_DONT_START_NEXT_PACKET));
4377
4378 if (BufferAddress != NULL) {
4379
4380 //
4381 // Build Mdl if necessary.
4382 //
4383
4384 if (Irp->MdlAddress == NULL) {
4385
4386 if (IoAllocateMdl(BufferAddress,
4387 BufferLength,
4388 FALSE,
4389 FALSE,
4390 Irp) == NULL) {
4391
4392 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
4393
4394 //
4395 // ClassIoComplete() would have free'd the srb
4396 //
4397
4398 if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) {
4399 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb);
4400 }
4401 ClassFreeOrReuseSrb(fdoExtension, Srb);
4402 ClassReleaseRemoveLock(Fdo, Irp);
4403 ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT);
4404
4405 return STATUS_INSUFFICIENT_RESOURCES;
4406 }
4407
4408 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
4409
4410 } else {
4411
4412 //
4413 // Make sure the buffer requested matches the MDL.
4414 //
4415
4416 ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress));
4417 }
4418
4419 //
4420 // Set read flag.
4421 //
4422
4423 Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
4424
4425 } else {
4426
4427 //
4428 // Clear flags.
4429 //
4430
4431 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
4432 }
4433
4434 //
4435 // Restore saved flags.
4436 //
4437
4438 SET_FLAG(Srb->SrbFlags, savedFlags);
4439
4440 //
4441 // Disable synchronous transfer for these requests.
4442 //
4443
4444 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
4445
4446 //
4447 // Set the transfer length.
4448 //
4449
4450 Srb->DataTransferLength = BufferLength;
4451
4452 //
4453 // Zero out status.
4454 //
4455
4456 Srb->ScsiStatus = Srb->SrbStatus = 0;
4457
4458 Srb->NextSrb = 0;
4459
4460 //
4461 // Save a few parameters in the current stack location.
4462 //
4463
4464 irpStack = IoGetCurrentIrpStackLocation(Irp);
4465
4466 //
4467 // Save retry count in current Irp stack.
4468 //
4469
4470 irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
4471
4472 //
4473 // Set up IoCompletion routine address.
4474 //
4475
4476 IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE);
4477
4478 //
4479 // Get next stack location and
4480 // set major function code.
4481 //
4482
4483 irpStack = IoGetNextIrpStackLocation(Irp);
4484
4485 irpStack->MajorFunction = IRP_MJ_SCSI;
4486
4487 //
4488 // Save SRB address in next stack for port driver.
4489 //
4490
4491 irpStack->Parameters.Scsi.Srb = Srb;
4492
4493 //
4494 // Set up Irp Address.
4495 //
4496
4497 Srb->OriginalRequest = Irp;
4498
4499 //
4500 // Call the port driver to process the request.
4501 //
4502
4503 IoMarkIrpPending(Irp);
4504
4505 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
4506
4507 return STATUS_PENDING;
4508
4509 } // end ClassSendSrbAsynchronous()
4510
4511 /*++////////////////////////////////////////////////////////////////////////////
4512
4513 ClassDeviceControlDispatch()
4514
4515 Routine Description:
4516
4517 The routine is the common class driver device control dispatch entry point.
4518 This routine is invokes the device-specific drivers DeviceControl routine,
4519 (which may call the Class driver's common DeviceControl routine).
4520
4521 Arguments:
4522
4523 DeviceObject - Supplies a pointer to the device object for this request.
4524
4525 Irp - Supplies the Irp making the request.
4526
4527 Return Value:
4528
4529 Returns the status returned from the device-specific driver.
4530
4531 --*/
4532 NTSTATUS
4533 NTAPI
4534 ClassDeviceControlDispatch(
4535 PDEVICE_OBJECT DeviceObject,
4536 PIRP Irp
4537 )
4538 {
4539
4540 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4541 ULONG isRemoved;
4542
4543 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
4544
4545 if(isRemoved) {
4546
4547 ClassReleaseRemoveLock(DeviceObject, Irp);
4548
4549 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
4550 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
4551 return STATUS_DEVICE_DOES_NOT_EXIST;
4552 }
4553
4554 //
4555 // Call the class specific driver DeviceControl routine.
4556 // If it doesn't handle it, it will call back into ClassDeviceControl.
4557 //
4558
4559 ASSERT(commonExtension->DevInfo->ClassDeviceControl);
4560
4561 return commonExtension->DevInfo->ClassDeviceControl(DeviceObject,Irp);
4562 } // end ClassDeviceControlDispatch()
4563
4564 /*++////////////////////////////////////////////////////////////////////////////
4565
4566 ClassDeviceControl()
4567
4568 Routine Description:
4569
4570 The routine is the common class driver device control dispatch function.
4571 This routine is called by a class driver when it get an unrecognized
4572 device control request. This routine will perform the correct action for
4573 common requests such as lock media. If the device request is unknown it
4574 passed down to the next level.
4575
4576 This routine must be called with the remove lock held for the specified
4577 irp.
4578
4579 Arguments:
4580
4581 DeviceObject - Supplies a pointer to the device object for this request.
4582
4583 Irp - Supplies the Irp making the request.
4584
4585 Return Value:
4586
4587 Returns back a STATUS_PENDING or a completion status.
4588
4589 --*/
4590 NTSTATUS
4591 NTAPI
4592 ClassDeviceControl(
4593 PDEVICE_OBJECT DeviceObject,
4594 PIRP Irp
4595 )
4596 {
4597 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
4598
4599 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
4600 PIO_STACK_LOCATION nextStack = NULL;
4601
4602 ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
4603
4604 PSCSI_REQUEST_BLOCK srb = NULL;
4605 PCDB cdb = NULL;
4606
4607 NTSTATUS status;
4608 ULONG modifiedIoControlCode;
4609
4610 //
4611 // If this is a pass through I/O control, set the minor function code
4612 // and device address and pass it to the port driver.
4613 //
4614
4615 if ((controlCode == IOCTL_SCSI_PASS_THROUGH) ||
4616 (controlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) {
4617
4618 //PSCSI_PASS_THROUGH scsiPass;
4619
4620 //
4621 // Validiate the user buffer.
4622 //
4623 #if defined (_WIN64)
4624
4625 if (IoIs32bitProcess(Irp)) {
4626
4627 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)){
4628
4629 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4630
4631 ClassReleaseRemoveLock(DeviceObject, Irp);
4632 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
4633
4634 status = STATUS_INVALID_PARAMETER;
4635 goto SetStatusAndReturn;
4636 }
4637 }
4638 else
4639 #endif
4640 {
4641 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4642 sizeof(SCSI_PASS_THROUGH)) {
4643
4644 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4645
4646 ClassReleaseRemoveLock(DeviceObject, Irp);
4647 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
4648
4649 status = STATUS_INVALID_PARAMETER;
4650 goto SetStatusAndReturn;
4651 }
4652 }
4653
4654 IoCopyCurrentIrpStackLocationToNext(Irp);
4655
4656 nextStack = IoGetNextIrpStackLocation(Irp);
4657 nextStack->MinorFunction = 1;
4658
4659 ClassReleaseRemoveLock(DeviceObject, Irp);
4660
4661 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
4662 goto SetStatusAndReturn;
4663 }
4664
4665 Irp->IoStatus.Information = 0;
4666
4667 switch (controlCode) {
4668
4669 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: {
4670
4671 PMOUNTDEV_UNIQUE_ID uniqueId;
4672
4673 if (!commonExtension->MountedDeviceInterfaceName.Buffer) {
4674 status = STATUS_INVALID_PARAMETER;
4675 break;
4676 }
4677
4678 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4679 sizeof(MOUNTDEV_UNIQUE_ID)) {
4680
4681 status = STATUS_BUFFER_TOO_SMALL;
4682 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
4683 break;
4684 }
4685
4686 uniqueId = Irp->AssociatedIrp.SystemBuffer;
4687 uniqueId->UniqueIdLength =
4688 commonExtension->MountedDeviceInterfaceName.Length;
4689
4690 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4691 sizeof(USHORT) + uniqueId->UniqueIdLength) {
4692
4693 status = STATUS_BUFFER_OVERFLOW;
4694 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
4695 break;
4696 }
4697
4698 RtlCopyMemory(uniqueId->UniqueId,
4699 commonExtension->MountedDeviceInterfaceName.Buffer,
4700 uniqueId->UniqueIdLength);
4701
4702 status = STATUS_SUCCESS;
4703 Irp->IoStatus.Information = sizeof(USHORT) +
4704 uniqueId->UniqueIdLength;
4705 break;
4706 }
4707
4708 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: {
4709
4710 PMOUNTDEV_NAME name;
4711
4712 ASSERT(commonExtension->DeviceName.Buffer);
4713
4714 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4715 sizeof(MOUNTDEV_NAME)) {
4716
4717 status = STATUS_BUFFER_TOO_SMALL;
4718 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
4719 break;
4720 }
4721
4722 name = Irp->AssociatedIrp.SystemBuffer;
4723 name->NameLength = commonExtension->DeviceName.Length;
4724
4725 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4726 sizeof(USHORT) + name->NameLength) {
4727
4728 status = STATUS_BUFFER_OVERFLOW;
4729 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
4730 break;
4731 }
4732
4733 RtlCopyMemory(name->Name, commonExtension->DeviceName.Buffer,
4734 name->NameLength);
4735
4736 status = STATUS_SUCCESS;
4737 Irp->IoStatus.Information = sizeof(USHORT) + name->NameLength;
4738 break;
4739 }
4740
4741 case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: {
4742
4743 PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName;
4744 WCHAR driveLetterNameBuffer[10];
4745 RTL_QUERY_REGISTRY_TABLE queryTable[2];
4746 PWSTR valueName;
4747 UNICODE_STRING driveLetterName;
4748
4749 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4750 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) {
4751
4752 status = STATUS_BUFFER_TOO_SMALL;
4753 Irp->IoStatus.Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
4754 break;
4755 }
4756
4757 valueName = ExAllocatePoolWithTag(
4758 PagedPool,
4759 commonExtension->DeviceName.Length + sizeof(WCHAR),
4760 '8CcS');
4761
4762 if (!valueName) {
4763 status = STATUS_INSUFFICIENT_RESOURCES;
4764 break;
4765 }
4766
4767 RtlCopyMemory(valueName, commonExtension->DeviceName.Buffer,
4768 commonExtension->DeviceName.Length);
4769 valueName[commonExtension->DeviceName.Length/sizeof(WCHAR)] = 0;
4770
4771 driveLetterName.Buffer = driveLetterNameBuffer;
4772 driveLetterName.MaximumLength = 20;
4773 driveLetterName.Length = 0;
4774
4775 RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
4776 queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED |
4777 RTL_QUERY_REGISTRY_DIRECT;
4778 queryTable[0].Name = valueName;
4779 queryTable[0].EntryContext = &driveLetterName;
4780
4781 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
4782 L"\\Registry\\Machine\\System\\DISK",
4783 queryTable, NULL, NULL);
4784
4785 if (!NT_SUCCESS(status)) {
4786 ExFreePool(valueName);
4787 break;
4788 }
4789
4790 if (driveLetterName.Length == 4 &&
4791 driveLetterName.Buffer[0] == '%' &&
4792 driveLetterName.Buffer[1] == ':') {
4793
4794 driveLetterName.Buffer[0] = 0xFF;
4795
4796 } else if (driveLetterName.Length != 4 ||
4797 driveLetterName.Buffer[0] < FirstDriveLetter ||
4798 driveLetterName.Buffer[0] > LastDriveLetter ||
4799 driveLetterName.Buffer[1] != ':') {
4800
4801 status = STATUS_NOT_FOUND;
4802 ExFreePool(valueName);
4803 break;
4804 }
4805
4806 suggestedName = Irp->AssociatedIrp.SystemBuffer;
4807 suggestedName->UseOnlyIfThereAreNoOtherLinks = TRUE;
4808 suggestedName->NameLength = 28;
4809
4810 Irp->IoStatus.Information =
4811 FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name) + 28;
4812
4813 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4814 Irp->IoStatus.Information) {
4815
4816 Irp->IoStatus.Information =
4817 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
4818 status = STATUS_BUFFER_OVERFLOW;
4819 ExFreePool(valueName);
4820 break;
4821 }
4822
4823 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE,
4824 L"\\Registry\\Machine\\System\\DISK",
4825 valueName);
4826
4827 ExFreePool(valueName);
4828
4829 RtlCopyMemory(suggestedName->Name, L"\\DosDevices\\", 24);
4830 suggestedName->Name[12] = driveLetterName.Buffer[0];
4831 suggestedName->Name[13] = ':';
4832
4833 //
4834 // NT_SUCCESS(status) based on RtlQueryRegistryValues
4835 //
4836 status = STATUS_SUCCESS;
4837
4838 break;
4839 }
4840
4841 default:
4842 status = STATUS_PENDING;
4843 break;
4844 }
4845
4846 if (status != STATUS_PENDING) {
4847 ClassReleaseRemoveLock(DeviceObject, Irp);
4848 Irp->IoStatus.Status = status;
4849 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4850 return status;
4851 }
4852
4853 if (commonExtension->IsFdo){
4854
4855 PULONG_PTR function;
4856
4857 srb = ExAllocatePoolWithTag(NonPagedPool,
4858 sizeof(SCSI_REQUEST_BLOCK) +
4859 (sizeof(ULONG_PTR) * 2),
4860 '9CcS');
4861
4862 if (srb == NULL) {
4863
4864 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
4865 ClassReleaseRemoveLock(DeviceObject, Irp);
4866 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
4867 status = STATUS_INSUFFICIENT_RESOURCES;
4868 goto SetStatusAndReturn;
4869 }
4870
4871 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
4872
4873 cdb = (PCDB)srb->Cdb;
4874
4875 //
4876 // Save the function code and the device object in the memory after
4877 // the SRB.
4878 //
4879
4880 function = (PULONG_PTR) ((PSCSI_REQUEST_BLOCK) (srb + 1));
4881 *function = (ULONG_PTR) DeviceObject;
4882 function++;
4883 *function = (ULONG_PTR) controlCode;
4884
4885 } else {
4886 srb = NULL;
4887 }
4888
4889 //
4890 // Change the device type to storage for the switch statement, but only
4891 // if from a legacy device type
4892 //
4893
4894 if (((controlCode & 0xffff0000) == (IOCTL_DISK_BASE << 16)) ||
4895 ((controlCode & 0xffff0000) == (IOCTL_TAPE_BASE << 16)) ||
4896 ((controlCode & 0xffff0000) == (IOCTL_CDROM_BASE << 16))
4897 ) {
4898
4899 modifiedIoControlCode = (controlCode & ~0xffff0000);
4900 modifiedIoControlCode |= (IOCTL_STORAGE_BASE << 16);
4901
4902 } else {
4903
4904 modifiedIoControlCode = controlCode;
4905
4906 }
4907
4908 DBGTRACE(ClassDebugTrace, ("> ioctl %xh (%s)", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode)));
4909
4910 switch (modifiedIoControlCode) {
4911
4912 case IOCTL_STORAGE_GET_HOTPLUG_INFO: {
4913
4914 if (srb) {
4915 ExFreePool(srb);
4916 srb = NULL;
4917 }
4918
4919 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4920 sizeof(STORAGE_HOTPLUG_INFO)) {
4921
4922 //
4923 // Indicate unsuccessful status and no data transferred.
4924 //
4925
4926 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
4927 Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO);
4928
4929 ClassReleaseRemoveLock(DeviceObject, Irp);
4930 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
4931 status = STATUS_BUFFER_TOO_SMALL;
4932
4933 } else if(!commonExtension->IsFdo) {
4934
4935 //
4936 // Just forward this down and return
4937 //
4938
4939 IoCopyCurrentIrpStackLocationToNext(Irp);
4940
4941 ClassReleaseRemoveLock(DeviceObject, Irp);
4942 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
4943
4944 } else {
4945
4946 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
4947 PSTORAGE_HOTPLUG_INFO info;
4948
4949 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension;
4950 info = Irp->AssociatedIrp.SystemBuffer;
4951
4952 *info = fdoExtension->PrivateFdoData->HotplugInfo;
4953 Irp->IoStatus.Status = STATUS_SUCCESS;
4954 Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO);
4955 ClassReleaseRemoveLock(DeviceObject, Irp);
4956 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
4957 status = STATUS_SUCCESS;
4958
4959 }
4960 break;
4961 }
4962
4963 case IOCTL_STORAGE_SET_HOTPLUG_INFO: {
4964
4965 if (srb)
4966 {
4967 ExFreePool(srb);
4968 srb = NULL;
4969 }
4970
4971 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4972 sizeof(STORAGE_HOTPLUG_INFO)) {
4973
4974 //
4975 // Indicate unsuccessful status and no data transferred.
4976 //
4977
4978 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
4979
4980 ClassReleaseRemoveLock(DeviceObject, Irp);
4981 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
4982 status = STATUS_INFO_LENGTH_MISMATCH;
4983 goto SetStatusAndReturn;
4984
4985 }
4986
4987 if(!commonExtension->IsFdo) {
4988
4989 //
4990 // Just forward this down and return
4991 //
4992
4993 IoCopyCurrentIrpStackLocationToNext(Irp);
4994
4995 ClassReleaseRemoveLock(DeviceObject, Irp);
4996 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
4997
4998 } else {
4999
5000 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension;
5001 PSTORAGE_HOTPLUG_INFO info = Irp->AssociatedIrp.SystemBuffer;
5002
5003 status = STATUS_SUCCESS;
5004
5005 if (info->Size != fdoExtension->PrivateFdoData->HotplugInfo.Size)
5006 {
5007 status = STATUS_INVALID_PARAMETER_1;
5008 }
5009
5010 if (info->MediaRemovable != fdoExtension->PrivateFdoData->HotplugInfo.MediaRemovable)
5011 {
5012 status = STATUS_INVALID_PARAMETER_2;
5013 }
5014
5015 if (info->MediaHotplug != fdoExtension->PrivateFdoData->HotplugInfo.MediaHotplug)
5016 {
5017 status = STATUS_INVALID_PARAMETER_3;
5018 }
5019
5020 if (info->WriteCacheEnableOverride != fdoExtension->PrivateFdoData->HotplugInfo.WriteCacheEnableOverride)
5021 {
5022 status = STATUS_INVALID_PARAMETER_5;
5023 }
5024
5025 if (NT_SUCCESS(status))
5026 {
5027 fdoExtension->PrivateFdoData->HotplugInfo.DeviceHotplug = info->DeviceHotplug;
5028
5029 //
5030 // Store the user-defined override in the registry
5031 //
5032
5033 ClassSetDeviceParameter(fdoExtension,
5034 CLASSP_REG_SUBKEY_NAME,
5035 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME,
5036 (info->DeviceHotplug) ? RemovalPolicyExpectSurpriseRemoval : RemovalPolicyExpectOrderlyRemoval);
5037 }
5038
5039 Irp->IoStatus.Status = status;
5040
5041 ClassReleaseRemoveLock(DeviceObject, Irp);
5042 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5043 }
5044
5045 break;
5046 }
5047
5048 case IOCTL_STORAGE_CHECK_VERIFY:
5049 case IOCTL_STORAGE_CHECK_VERIFY2: {
5050
5051 PIRP irp2 = NULL;
5052 PIO_STACK_LOCATION newStack;
5053
5054 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
5055
5056 DebugPrint((1,"DeviceIoControl: Check verify\n"));
5057
5058 //
5059 // If a buffer for a media change count was provided, make sure it's
5060 // big enough to hold the result
5061 //
5062
5063 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
5064
5065 //
5066 // If the buffer is too small to hold the media change count
5067 // then return an error to the caller
5068 //
5069
5070 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
5071 sizeof(ULONG)) {
5072
5073 DebugPrint((3,"DeviceIoControl: media count "
5074 "buffer too small\n"));
5075
5076 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
5077 Irp->IoStatus.Information = sizeof(ULONG);
5078
5079 if(srb != NULL) {
5080 ExFreePool(srb);
5081 }
5082
5083 ClassReleaseRemoveLock(DeviceObject, Irp);
5084 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5085
5086 status = STATUS_BUFFER_TOO_SMALL;
5087 goto SetStatusAndReturn;
5088
5089 }
5090 }
5091
5092 if(!commonExtension->IsFdo) {
5093
5094 //
5095 // If this is a PDO then we should just forward the request down
5096 //
5097 ASSERT(!srb);
5098
5099 IoCopyCurrentIrpStackLocationToNext(Irp);
5100
5101 ClassReleaseRemoveLock(DeviceObject, Irp);
5102
5103 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5104
5105 goto SetStatusAndReturn;
5106
5107 } else {
5108
5109 fdoExtension = DeviceObject->DeviceExtension;
5110
5111 }
5112
5113 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
5114
5115 //
5116 // The caller has provided a valid buffer. Allocate an additional
5117 // irp and stick the CheckVerify completion routine on it. We will
5118 // then send this down to the port driver instead of the irp the
5119 // caller sent in
5120 //
5121
5122 DebugPrint((2,"DeviceIoControl: Check verify wants "
5123 "media count\n"));
5124
5125 //
5126 // Allocate a new irp to send the TestUnitReady to the port driver
5127 //
5128
5129 irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE);
5130
5131 if(irp2 == NULL) {
5132 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
5133 Irp->IoStatus.Information = 0;
5134 ASSERT(srb);
5135 ExFreePool(srb);
5136 ClassReleaseRemoveLock(DeviceObject, Irp);
5137 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5138 status = STATUS_INSUFFICIENT_RESOURCES;
5139 goto SetStatusAndReturn;
5140
5141 break;
5142 }
5143
5144 //
5145 // Make sure to acquire the lock for the new irp.
5146 //
5147
5148 ClassAcquireRemoveLock(DeviceObject, irp2);
5149
5150 irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
5151 IoSetNextIrpStackLocation(irp2);
5152
5153 //
5154 // Set the top stack location and shove the master Irp into the
5155 // top location
5156 //
5157
5158 newStack = IoGetCurrentIrpStackLocation(irp2);
5159 newStack->Parameters.Others.Argument1 = Irp;
5160 newStack->DeviceObject = DeviceObject;
5161
5162 //
5163 // Stick the check verify completion routine onto the stack
5164 // and prepare the irp for the port driver
5165 //
5166
5167 IoSetCompletionRoutine(irp2,
5168 ClassCheckVerifyComplete,
5169 NULL,
5170 TRUE,
5171 TRUE,
5172 TRUE);
5173
5174 IoSetNextIrpStackLocation(irp2);
5175 newStack = IoGetCurrentIrpStackLocation(irp2);
5176 newStack->DeviceObject = DeviceObject;
5177 newStack->MajorFunction = irpStack->MajorFunction;
5178 newStack->MinorFunction = irpStack->MinorFunction;
5179
5180 //
5181 // Mark the master irp as pending - whether the lower level
5182 // driver completes it immediately or not this should allow it
5183 // to go all the way back up.
5184 //
5185
5186 IoMarkIrpPending(Irp);
5187
5188 Irp = irp2;
5189
5190 }
5191
5192 //
5193 // Test Unit Ready
5194 //
5195
5196 srb->CdbLength = 6;
5197 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
5198
5199 //
5200 // Set timeout value.
5201 //
5202
5203 srb->TimeOutValue = fdoExtension->TimeOutValue;
5204
5205 //
5206 // If this was a CV2 then mark the request as low-priority so we don't
5207 // spin up the drive just to satisfy it.
5208 //
5209
5210 if(controlCode == IOCTL_STORAGE_CHECK_VERIFY2) {
5211 SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY);
5212 }
5213
5214 //
5215 // Since this routine will always hand the request to the
5216 // port driver if there isn't a data transfer to be done
5217 // we don't have to worry about completing the request here
5218 // on an error
5219 //
5220
5221 //
5222 // This routine uses a completion routine so we don't want to release
5223 // the remove lock until then.
5224 //
5225
5226 status = ClassSendSrbAsynchronous(DeviceObject,
5227 srb,
5228 Irp,
5229 NULL,
5230 0,
5231 FALSE);
5232
5233 break;
5234 }
5235
5236 case IOCTL_STORAGE_MEDIA_REMOVAL:
5237 case IOCTL_STORAGE_EJECTION_CONTROL: {
5238
5239 PPREVENT_MEDIA_REMOVAL mediaRemoval = Irp->AssociatedIrp.SystemBuffer;
5240
5241 DebugPrint((3, "DiskIoControl: ejection control\n"));
5242
5243 if(srb) {
5244 ExFreePool(srb);
5245 }
5246
5247 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
5248 sizeof(PREVENT_MEDIA_REMOVAL)) {
5249
5250 //
5251 // Indicate unsuccessful status and no data transferred.
5252 //
5253
5254 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
5255
5256 ClassReleaseRemoveLock(DeviceObject, Irp);
5257 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5258 status = STATUS_INFO_LENGTH_MISMATCH;
5259 goto SetStatusAndReturn;
5260 }
5261
5262 if(!commonExtension->IsFdo) {
5263
5264 //
5265 // Just forward this down and return
5266 //
5267
5268 IoCopyCurrentIrpStackLocationToNext(Irp);
5269
5270 ClassReleaseRemoveLock(DeviceObject, Irp);
5271 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5272 }
5273 else {
5274
5275 // i don't believe this assertion is valid. this is a request
5276 // from user-mode, so they could request this for any device
5277 // they want? also, we handle it properly.
5278 // ASSERT(TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA));
5279 status = ClasspEjectionControl(
5280 DeviceObject,
5281 Irp,
5282 ((modifiedIoControlCode ==
5283 IOCTL_STORAGE_EJECTION_CONTROL) ? SecureMediaLock :
5284 SimpleMediaLock),
5285 mediaRemoval->PreventMediaRemoval);
5286
5287 Irp->IoStatus.Status = status;
5288 ClassReleaseRemoveLock(DeviceObject, Irp);
5289 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5290 }
5291
5292 break;
5293 }
5294
5295 case IOCTL_STORAGE_MCN_CONTROL: {
5296
5297 DebugPrint((3, "DiskIoControl: MCN control\n"));
5298
5299 if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
5300 sizeof(PREVENT_MEDIA_REMOVAL)) {
5301
5302 //
5303 // Indicate unsuccessful status and no data transferred.
5304 //
5305
5306 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
5307 Irp->IoStatus.Information = 0;
5308
5309 if(srb) {
5310 ExFreePool(srb);
5311 }
5312
5313 ClassReleaseRemoveLock(DeviceObject, Irp);
5314 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5315 status = STATUS_INFO_LENGTH_MISMATCH;
5316 goto SetStatusAndReturn;
5317 }
5318
5319 if(!commonExtension->IsFdo) {
5320
5321 //
5322 // Just forward this down and return
5323 //
5324
5325 if(srb) {
5326 ExFreePool(srb);
5327 }
5328
5329 IoCopyCurrentIrpStackLocationToNext(Irp);
5330
5331 ClassReleaseRemoveLock(DeviceObject, Irp);
5332 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5333
5334 } else {
5335
5336 //
5337 // Call to the FDO - handle the ejection control.
5338 //
5339
5340 status = ClasspMcnControl(DeviceObject->DeviceExtension,
5341 Irp,
5342 srb);
5343 }
5344 goto SetStatusAndReturn;
5345 }
5346
5347 case IOCTL_STORAGE_RESERVE:
5348 case IOCTL_STORAGE_RELEASE: {
5349
5350 //
5351 // Reserve logical unit.
5352 //
5353
5354 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
5355
5356 if(!commonExtension->IsFdo) {
5357
5358 IoCopyCurrentIrpStackLocationToNext(Irp);
5359
5360 ClassReleaseRemoveLock(DeviceObject, Irp);
5361 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5362 goto SetStatusAndReturn;
5363 } else {
5364 fdoExtension = DeviceObject->DeviceExtension;
5365 }
5366
5367 srb->CdbLength = 6;
5368
5369 if(modifiedIoControlCode == IOCTL_STORAGE_RESERVE) {
5370 cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT;
5371 } else {
5372 cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT;
5373 }
5374
5375 //
5376 // Set timeout value.
5377 //
5378
5379 srb->TimeOutValue = fdoExtension->TimeOutValue;
5380
5381 status = ClassSendSrbAsynchronous(DeviceObject,
5382 srb,
5383 Irp,
5384 NULL,
5385 0,
5386 FALSE);
5387
5388 break;
5389 }
5390
5391 case IOCTL_STORAGE_EJECT_MEDIA:
5392 case IOCTL_STORAGE_LOAD_MEDIA:
5393 case IOCTL_STORAGE_LOAD_MEDIA2:{
5394
5395 //
5396 // Eject media.
5397 //
5398
5399 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
5400
5401 if(!commonExtension->IsFdo) {
5402
5403 IoCopyCurrentIrpStackLocationToNext(Irp);
5404
5405 ClassReleaseRemoveLock(DeviceObject, Irp);
5406
5407 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5408 goto SetStatusAndReturn;
5409 } else {
5410 fdoExtension = DeviceObject->DeviceExtension;
5411 }
5412
5413 if(commonExtension->PagingPathCount != 0) {
5414
5415 DebugPrint((1, "ClassDeviceControl: call to eject paging device - "
5416 "failure\n"));
5417
5418 status = STATUS_FILES_OPEN;
5419 Irp->IoStatus.Status = status;
5420
5421 Irp->IoStatus.Information = 0;
5422
5423 if(srb) {
5424 ExFreePool(srb);
5425 }
5426
5427 ClassReleaseRemoveLock(DeviceObject, Irp);
5428 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5429 goto SetStatusAndReturn;
5430 }
5431
5432 //
5433 // Synchronize with ejection control and ejection cleanup code as
5434 // well as other eject/load requests.
5435 //
5436
5437 KeEnterCriticalRegion();
5438 KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent),
5439 UserRequest,
5440 UserMode,
5441 FALSE,
5442 NULL);
5443
5444 if(fdoExtension->ProtectedLockCount != 0) {
5445
5446 DebugPrint((1, "ClassDeviceControl: call to eject protected locked "
5447 "device - failure\n"));
5448
5449 status = STATUS_DEVICE_BUSY;
5450 Irp->IoStatus.Status = status;
5451 Irp->IoStatus.Information = 0;
5452
5453 if(srb) {
5454 ExFreePool(srb);
5455 }
5456
5457 ClassReleaseRemoveLock(DeviceObject, Irp);
5458 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5459
5460 KeSetEvent(&fdoExtension->EjectSynchronizationEvent,
5461 IO_NO_INCREMENT,
5462 FALSE);
5463 KeLeaveCriticalRegion();
5464
5465 goto SetStatusAndReturn;
5466 }
5467
5468 srb->CdbLength = 6;
5469
5470 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
5471 cdb->START_STOP.LoadEject = 1;
5472
5473 if(modifiedIoControlCode == IOCTL_STORAGE_EJECT_MEDIA) {
5474 cdb->START_STOP.Start = 0;
5475 } else {
5476 cdb->START_STOP.Start = 1;
5477 }
5478
5479 //
5480 // Set timeout value.
5481 //
5482
5483 srb->TimeOutValue = fdoExtension->TimeOutValue;
5484 status = ClassSendSrbAsynchronous(DeviceObject,
5485 srb,
5486 Irp,
5487 NULL,
5488 0,
5489 FALSE);
5490
5491 KeSetEvent(&fdoExtension->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE);
5492 KeLeaveCriticalRegion();
5493
5494 break;
5495 }
5496
5497 case IOCTL_STORAGE_FIND_NEW_DEVICES: {
5498
5499 if(srb) {
5500 ExFreePool(srb);
5501 }
5502
5503 if(commonExtension->IsFdo) {
5504
5505 IoInvalidateDeviceRelations(
5506 ((PFUNCTIONAL_DEVICE_EXTENSION) commonExtension)->LowerPdo,
5507 BusRelations);
5508
5509 status = STATUS_SUCCESS;
5510 Irp->IoStatus.Status = status;
5511
5512 ClassReleaseRemoveLock(DeviceObject, Irp);
5513 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5514 }
5515 else {
5516
5517 IoCopyCurrentIrpStackLocationToNext(Irp);
5518
5519 ClassReleaseRemoveLock(DeviceObject, Irp);
5520 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5521 }
5522 break;
5523 }
5524
5525 case IOCTL_STORAGE_GET_DEVICE_NUMBER: {
5526
5527 if(srb) {
5528 ExFreePool(srb);
5529 }
5530
5531 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
5532 sizeof(STORAGE_DEVICE_NUMBER)) {
5533
5534 PSTORAGE_DEVICE_NUMBER deviceNumber =
5535 Irp->AssociatedIrp.SystemBuffer;
5536 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
5537 commonExtension->PartitionZeroExtension;
5538
5539 deviceNumber->DeviceType = fdoExtension->CommonExtension.DeviceObject->DeviceType;
5540 deviceNumber->DeviceNumber = fdoExtension->DeviceNumber;
5541 deviceNumber->PartitionNumber = commonExtension->PartitionNumber;
5542
5543 status = STATUS_SUCCESS;
5544 Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER);
5545
5546 } else {
5547 status = STATUS_BUFFER_TOO_SMALL;
5548 Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER);
5549 }
5550
5551 Irp->IoStatus.Status = status;
5552 ClassReleaseRemoveLock(DeviceObject, Irp);
5553 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5554
5555 break;
5556 }
5557
5558 default: {
5559
5560 DebugPrint((4, "IoDeviceControl: Unsupported device IOCTL %x for %p\n",
5561 controlCode, DeviceObject));
5562
5563 //
5564 // Pass the device control to the next driver.
5565 //
5566
5567 if(srb) {
5568 ExFreePool(srb);
5569 }
5570
5571 //
5572 // Copy the Irp stack parameters to the next stack location.
5573 //
5574
5575 IoCopyCurrentIrpStackLocationToNext(Irp);
5576
5577 ClassReleaseRemoveLock(DeviceObject, Irp);
5578 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
5579 break;
5580 }
5581
5582 } // end switch( ...
5583
5584 SetStatusAndReturn:
5585
5586 DBGTRACE(ClassDebugTrace, ("< ioctl %xh (%s): status %xh.", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode), status));
5587
5588 return status;
5589 } // end ClassDeviceControl()
5590
5591 /*++////////////////////////////////////////////////////////////////////////////
5592
5593 ClassShutdownFlush()
5594
5595 Routine Description:
5596
5597 This routine is called for a shutdown and flush IRPs. These are sent by the
5598 system before it actually shuts down or when the file system does a flush.
5599 If it exists, the device-specific driver's routine will be invoked. If there
5600 wasn't one specified, the Irp will be completed with an Invalid device request.
5601
5602 Arguments:
5603
5604 DriverObject - Pointer to device object to being shutdown by system.
5605
5606 Irp - IRP involved.
5607
5608 Return Value:
5609
5610 NT Status
5611
5612 --*/
5613 NTSTATUS
5614 NTAPI
5615 ClassShutdownFlush(
5616 IN PDEVICE_OBJECT DeviceObject,
5617 IN PIRP Irp
5618 )
5619 {
5620 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
5621
5622 ULONG isRemoved;
5623
5624 //NTSTATUS status;
5625
5626 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
5627
5628 if(isRemoved) {
5629
5630 ClassReleaseRemoveLock(DeviceObject, Irp);
5631
5632 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
5633
5634 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5635
5636 return STATUS_DEVICE_DOES_NOT_EXIST;
5637 }
5638
5639 if (commonExtension->DevInfo->ClassShutdownFlush) {
5640
5641 //
5642 // Call the device-specific driver's routine.
5643 //
5644
5645 return commonExtension->DevInfo->ClassShutdownFlush(DeviceObject, Irp);
5646 }
5647
5648 //
5649 // Device-specific driver doesn't support this.
5650 //
5651
5652 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
5653
5654 ClassReleaseRemoveLock(DeviceObject, Irp);
5655 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
5656
5657 return STATUS_INVALID_DEVICE_REQUEST;
5658 } // end ClassShutdownFlush()
5659
5660 /*++////////////////////////////////////////////////////////////////////////////
5661
5662 ClassCreateDeviceObject()
5663
5664 Routine Description:
5665
5666 This routine creates an object for the physical device specified and
5667 sets up the deviceExtension's function pointers for each entry point
5668 in the device-specific driver.
5669
5670 Arguments:
5671
5672 DriverObject - Pointer to driver object created by system.
5673
5674 ObjectNameBuffer - Dir. name of the object to create.
5675
5676 LowerDeviceObject - Pointer to the lower device object
5677
5678 IsFdo - should this be an fdo or a pdo
5679
5680 DeviceObject - Pointer to the device object pointer we will return.
5681
5682 Return Value:
5683
5684 NTSTATUS
5685
5686 --*/
5687 NTSTATUS
5688 NTAPI
5689 ClassCreateDeviceObject(
5690 IN PDRIVER_OBJECT DriverObject,
5691 IN PCCHAR ObjectNameBuffer,
5692 IN PDEVICE_OBJECT LowerDevice,
5693 IN BOOLEAN IsFdo,
5694 IN OUT PDEVICE_OBJECT *DeviceObject
5695 )
5696 {
5697 BOOLEAN isPartitionable;
5698 STRING ntNameString;
5699 UNICODE_STRING ntUnicodeString;
5700 NTSTATUS status;
5701 PDEVICE_OBJECT deviceObject = NULL;
5702
5703 ULONG characteristics;
5704
5705 PCLASS_DRIVER_EXTENSION
5706 driverExtension = IoGetDriverObjectExtension(DriverObject,
5707 CLASS_DRIVER_EXTENSION_KEY);
5708
5709 PCLASS_DEV_INFO devInfo;
5710
5711 PAGED_CODE();
5712
5713 *DeviceObject = NULL;
5714 RtlInitUnicodeString(&ntUnicodeString, NULL);
5715
5716 DebugPrint((2, "ClassCreateFdo: Create device object\n"));
5717
5718 ASSERT(LowerDevice);
5719
5720 //
5721 // Make sure that if we're making PDO's we have an enumeration routine
5722 //
5723
5724 isPartitionable = (driverExtension->InitData.ClassEnumerateDevice != NULL);
5725
5726 ASSERT(IsFdo || isPartitionable);
5727
5728 //
5729 // Grab the correct dev-info structure out of the init data
5730 //
5731
5732 if(IsFdo) {
5733 devInfo = &(driverExtension->InitData.FdoData);
5734 } else {
5735 devInfo = &(driverExtension->InitData.PdoData);
5736 }
5737
5738 characteristics = devInfo->DeviceCharacteristics;
5739
5740 if(ARGUMENT_PRESENT(ObjectNameBuffer)) {
5741 DebugPrint((2, "ClassCreateFdo: Name is %s\n", ObjectNameBuffer));
5742
5743 RtlInitString(&ntNameString, ObjectNameBuffer);
5744
5745 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, &ntNameString, TRUE);
5746
5747 if (!NT_SUCCESS(status)) {
5748
5749 DebugPrint((1,
5750 "ClassCreateFdo: Cannot convert string %s\n",
5751 ObjectNameBuffer));
5752
5753 ntUnicodeString.Buffer = NULL;
5754 return status;
5755 }
5756 } else {
5757 DebugPrint((2, "ClassCreateFdo: Object will be unnamed\n"));
5758
5759 if(IsFdo == FALSE) {
5760
5761 //
5762 // PDO's have to have some sort of name.
5763 //
5764
5765 SET_FLAG(characteristics, FILE_AUTOGENERATED_DEVICE_NAME);
5766 }
5767
5768 RtlInitUnicodeString(&ntUnicodeString, NULL);
5769 }
5770
5771 status = IoCreateDevice(DriverObject,
5772 devInfo->DeviceExtensionSize,
5773 &ntUnicodeString,
5774 devInfo->DeviceType,
5775 devInfo->DeviceCharacteristics,
5776 FALSE,
5777 &deviceObject);
5778
5779 if (!NT_SUCCESS(status)) {
5780
5781 DebugPrint((1, "ClassCreateFdo: Can not create device object %lx\n",
5782 status));
5783 ASSERT(deviceObject == NULL);
5784
5785 //
5786 // buffer is not used any longer here.
5787 //
5788
5789 if (ntUnicodeString.Buffer != NULL) {
5790 DebugPrint((1, "ClassCreateFdo: Freeing unicode name buffer\n"));
5791 ExFreePool(ntUnicodeString.Buffer);
5792 RtlInitUnicodeString(&ntUnicodeString, NULL);
5793 }
5794
5795 } else {
5796
5797 PCOMMON_DEVICE_EXTENSION commonExtension = deviceObject->DeviceExtension;
5798
5799 RtlZeroMemory(
5800 deviceObject->DeviceExtension,
5801 devInfo->DeviceExtensionSize);
5802
5803 //
5804 // Setup version code
5805 //
5806
5807 commonExtension->Version = 0x03;
5808
5809 //
5810 // Setup the remove lock and event
5811 //
5812
5813 commonExtension->IsRemoved = NO_REMOVE;
5814 commonExtension->RemoveLock = 0;
5815 KeInitializeEvent(&commonExtension->RemoveEvent,
5816 SynchronizationEvent,
5817 FALSE);
5818
5819 #if DBG
5820 KeInitializeSpinLock(&commonExtension->RemoveTrackingSpinlock);
5821 commonExtension->RemoveTrackingList = NULL;
5822 #else
5823 commonExtension->RemoveTrackingSpinlock = (ULONG_PTR) -1;
5824 commonExtension->RemoveTrackingList = (PVOID) -1;
5825 #endif
5826
5827 //
5828 // Acquire the lock once. This reference will be released when the
5829 // remove IRP has been received.
5830 //
5831
5832 ClassAcquireRemoveLock(deviceObject, (PIRP) deviceObject);
5833
5834 //
5835 // Store a pointer to the driver extension so we don't have to do
5836 // lookups to get it.
5837 //
5838
5839 commonExtension->DriverExtension = driverExtension;
5840
5841 //
5842 // Fill in entry points
5843 //
5844
5845 commonExtension->DevInfo = devInfo;
5846
5847 //
5848 // Initialize some of the common values in the structure
5849 //
5850
5851 commonExtension->DeviceObject = deviceObject;
5852
5853 commonExtension->LowerDeviceObject = NULL;
5854
5855 if(IsFdo) {
5856
5857 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PVOID) commonExtension;
5858
5859 commonExtension->PartitionZeroExtension = deviceObject->DeviceExtension;
5860
5861 //
5862 // Set the initial device object flags.
5863 //
5864
5865 SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE);
5866
5867 //
5868 // Clear the PDO list
5869 //
5870
5871 commonExtension->ChildList = NULL;
5872
5873 commonExtension->DriverData =
5874 ((PFUNCTIONAL_DEVICE_EXTENSION) deviceObject->DeviceExtension + 1);
5875
5876 if(isPartitionable) {
5877
5878 commonExtension->PartitionNumber = 0;
5879 } else {
5880 commonExtension->PartitionNumber = (ULONG) (-1L);
5881 }
5882
5883 fdoExtension->DevicePowerState = PowerDeviceD0;
5884
5885 KeInitializeEvent(&fdoExtension->EjectSynchronizationEvent,
5886 SynchronizationEvent,
5887 TRUE);
5888
5889 KeInitializeEvent(&fdoExtension->ChildLock,
5890 SynchronizationEvent,
5891 TRUE);
5892
5893 status = ClasspAllocateReleaseRequest(deviceObject);
5894
5895 if(!NT_SUCCESS(status)) {
5896 IoDeleteDevice(deviceObject);
5897 *DeviceObject = NULL;
5898
5899 if (ntUnicodeString.Buffer != NULL) {
5900 DebugPrint((1, "ClassCreateFdo: Freeing unicode name buffer\n"));
5901 ExFreePool(ntUnicodeString.Buffer);
5902 RtlInitUnicodeString(&ntUnicodeString, NULL);
5903 }
5904
5905 return status;
5906 }
5907
5908 } else {
5909
5910 PPHYSICAL_DEVICE_EXTENSION pdoExtension =
5911 deviceObject->DeviceExtension;
5912
5913 PFUNCTIONAL_DEVICE_EXTENSION p0Extension =
5914 LowerDevice->DeviceExtension;
5915
5916 SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE);
5917
5918 commonExtension->PartitionZeroExtension = p0Extension;
5919
5920 //
5921 // Stick this onto the PDO list
5922 //
5923
5924 ClassAddChild(p0Extension, pdoExtension, TRUE);
5925
5926 commonExtension->DriverData = (PVOID) (pdoExtension + 1);
5927
5928 //
5929 // Get the top of stack for the lower device - this allows
5930 // filters to get stuck in between the partitions and the
5931 // physical disk.
5932 //
5933
5934 commonExtension->LowerDeviceObject =
5935 IoGetAttachedDeviceReference(LowerDevice);
5936
5937 //
5938 // Pnp will keep a reference to the lower device object long
5939 // after this partition has been deleted. Dereference now so
5940 // we don't have to deal with it later.
5941 //
5942
5943 ObDereferenceObject(commonExtension->LowerDeviceObject);
5944 }
5945
5946 KeInitializeEvent(&commonExtension->PathCountEvent, SynchronizationEvent, TRUE);
5947
5948 commonExtension->IsFdo = IsFdo;
5949
5950 commonExtension->DeviceName = ntUnicodeString;
5951
5952 commonExtension->PreviousState = 0xff;
5953
5954 InitializeDictionary(&(commonExtension->FileObjectDictionary));
5955
5956 commonExtension->CurrentState = IRP_MN_STOP_DEVICE;
5957 }
5958
5959 *DeviceObject = deviceObject;
5960
5961 return status;
5962 } // end ClassCreateDeviceObject()
5963
5964 /*++////////////////////////////////////////////////////////////////////////////
5965
5966 ClassClaimDevice()
5967
5968 Routine Description:
5969
5970 This function claims a device in the port driver. The port driver object
5971 is updated with the correct driver object if the device is successfully
5972 claimed.
5973
5974 Arguments:
5975
5976 LowerDeviceObject - Supplies the base port device object.
5977
5978 Release - Indicates the logical unit should be released rather than claimed.
5979
5980 Return Value:
5981
5982 Returns a status indicating success or failure of the operation.
5983
5984 --*/
5985 NTSTATUS
5986 NTAPI
5987 ClassClaimDevice(
5988 IN PDEVICE_OBJECT LowerDeviceObject,
5989 IN BOOLEAN Release
5990 )
5991 {
5992 IO_STATUS_BLOCK ioStatus;
5993 PIRP irp;
5994 PIO_STACK_LOCATION irpStack;
5995 KEVENT event;
5996 NTSTATUS status;
5997 SCSI_REQUEST_BLOCK srb;
5998
5999 PAGED_CODE();
6000
6001 //
6002 // Clear the SRB fields.
6003 //
6004
6005 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
6006
6007 //
6008 // Write length to SRB.
6009 //
6010
6011 srb.Length = sizeof(SCSI_REQUEST_BLOCK);
6012
6013 srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE :
6014 SRB_FUNCTION_CLAIM_DEVICE;
6015
6016 //
6017 // Set the event object to the unsignaled state.
6018 // It will be used to signal request completion
6019 //
6020
6021 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
6022
6023 //
6024 // Build synchronous request with no transfer.
6025 //
6026
6027 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
6028 LowerDeviceObject,
6029 NULL,
6030 0,
6031 NULL,
6032 0,
6033 TRUE,
6034 &event,
6035 &ioStatus);
6036
6037 if (irp == NULL) {
6038 DebugPrint((1, "ClassClaimDevice: Can't allocate Irp\n"));
6039 return STATUS_INSUFFICIENT_RESOURCES;
6040 }
6041
6042 irpStack = IoGetNextIrpStackLocation(irp);
6043
6044 //
6045 // Save SRB address in next stack for port driver.
6046 //
6047
6048 irpStack->Parameters.Scsi.Srb = &srb;
6049
6050 //
6051 // Set up IRP Address.
6052 //
6053
6054 srb.OriginalRequest = irp;
6055
6056 //
6057 // Call the port driver with the request and wait for it to complete.
6058 //
6059
6060 status = IoCallDriver(LowerDeviceObject, irp);
6061 if (status == STATUS_PENDING) {
6062
6063 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
6064 status = ioStatus.Status;
6065 }
6066
6067 //
6068 // If this is a release request, then just decrement the reference count
6069 // and return. The status does not matter.
6070 //
6071
6072 if (Release) {
6073
6074 // ObDereferenceObject(LowerDeviceObject);
6075 return STATUS_SUCCESS;
6076 }
6077
6078 if (!NT_SUCCESS(status)) {
6079 return status;
6080 }
6081
6082 ASSERT(srb.DataBuffer != NULL);
6083 ASSERT(!TEST_FLAG(srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
6084
6085 return status;
6086 } // end ClassClaimDevice()
6087
6088 /*++////////////////////////////////////////////////////////////////////////////
6089
6090 ClassInternalIoControl()
6091
6092 Routine Description:
6093
6094 This routine passes internal device controls to the port driver.
6095 Internal device controls are used by higher level drivers both for ioctls
6096 and to pass through scsi requests.
6097
6098 If the IoControlCode does not match any of the handled ioctls and is
6099 a valid system address then the request will be treated as an SRB and
6100 passed down to the lower driver. If the IoControlCode is not a valid
6101 system address the ioctl will be failed.
6102
6103 Callers must therefore be extremely cautious to pass correct, initialized
6104 values to this function.
6105
6106 Arguments:
6107
6108 DeviceObject - Supplies a pointer to the device object for this request.
6109
6110 Irp - Supplies the Irp making the request.
6111
6112 Return Value:
6113
6114 Returns back a STATUS_PENDING or a completion status.
6115
6116 --*/
6117 NTSTATUS
6118 NTAPI
6119 ClassInternalIoControl(
6120 IN PDEVICE_OBJECT DeviceObject,
6121 IN PIRP Irp
6122 )
6123 {
6124 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
6125
6126 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
6127 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
6128
6129 ULONG isRemoved;
6130
6131 PSCSI_REQUEST_BLOCK srb;
6132
6133 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
6134
6135 if(isRemoved) {
6136
6137 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
6138
6139 ClassReleaseRemoveLock(DeviceObject, Irp);
6140
6141 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
6142
6143 return STATUS_DEVICE_DOES_NOT_EXIST;
6144 }
6145
6146 //
6147 // Get a pointer to the SRB.
6148 //
6149
6150 srb = irpStack->Parameters.Scsi.Srb;
6151
6152 //
6153 // Set the parameters in the next stack location.
6154 //
6155
6156 if(commonExtension->IsFdo) {
6157 nextStack->Parameters.Scsi.Srb = srb;
6158 nextStack->MajorFunction = IRP_MJ_SCSI;
6159 nextStack->MinorFunction = IRP_MN_SCSI_CLASS;
6160
6161 } else {
6162
6163 IoCopyCurrentIrpStackLocationToNext(Irp);
6164 }
6165
6166 ClassReleaseRemoveLock(DeviceObject, Irp);
6167
6168 return IoCallDriver(commonExtension->LowerDeviceObject, Irp);
6169 } // end ClassInternalIoControl()
6170
6171 /*++////////////////////////////////////////////////////////////////////////////
6172
6173 ClassQueryTimeOutRegistryValue()
6174
6175 Routine Description:
6176
6177 This routine determines whether a reg key for a user-specified timeout
6178 value exists. This should be called at initialization time.
6179
6180 Arguments:
6181
6182 DeviceObject - Pointer to the device object we are retrieving the timeout
6183 value for
6184
6185 Return Value:
6186
6187 None, but it sets a new default timeout for a class of devices.
6188
6189 --*/
6190 ULONG
6191 NTAPI
6192 ClassQueryTimeOutRegistryValue(
6193 IN PDEVICE_OBJECT DeviceObject
6194 )
6195 {
6196 //
6197 // Find the appropriate reg. key
6198 //
6199
6200 PCLASS_DRIVER_EXTENSION
6201 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
6202 CLASS_DRIVER_EXTENSION_KEY);
6203
6204 PUNICODE_STRING registryPath = &(driverExtension->RegistryPath);
6205
6206 PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
6207 PWSTR path;
6208 NTSTATUS status;
6209 LONG timeOut = 0;
6210 ULONG zero = 0;
6211 ULONG size;
6212
6213 PAGED_CODE();
6214
6215 if (!registryPath) {
6216 return 0;
6217 }
6218
6219 parameters = ExAllocatePoolWithTag(NonPagedPool,
6220 sizeof(RTL_QUERY_REGISTRY_TABLE)*2,
6221 '1BcS');
6222
6223 if (!parameters) {
6224 return 0;
6225 }
6226
6227 size = registryPath->MaximumLength + sizeof(WCHAR);
6228 path = ExAllocatePoolWithTag(NonPagedPool, size, '2BcS');
6229
6230 if (!path) {
6231 ExFreePool(parameters);
6232 return 0;
6233 }
6234
6235 RtlZeroMemory(path,size);
6236 RtlCopyMemory(path, registryPath->Buffer, size - sizeof(WCHAR));
6237
6238
6239 //
6240 // Check for the Timeout value.
6241 //
6242
6243 RtlZeroMemory(parameters,
6244 (sizeof(RTL_QUERY_REGISTRY_TABLE)*2));
6245
6246 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
6247 parameters[0].Name = L"TimeOutValue";
6248 parameters[0].EntryContext = &timeOut;
6249 parameters[0].DefaultType = REG_DWORD;
6250 parameters[0].DefaultData = &zero;
6251 parameters[0].DefaultLength = sizeof(ULONG);
6252
6253 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
6254 path,
6255 parameters,
6256 NULL,
6257 NULL);
6258
6259 if (!(NT_SUCCESS(status))) {
6260 timeOut = 0;
6261 }
6262
6263 ExFreePool(parameters);
6264 ExFreePool(path);
6265
6266 DebugPrint((2,
6267 "ClassQueryTimeOutRegistryValue: Timeout value %d\n",
6268 timeOut));
6269
6270
6271 return timeOut;
6272
6273 } // end ClassQueryTimeOutRegistryValue()
6274
6275 /*++////////////////////////////////////////////////////////////////////////////
6276
6277 ClassCheckVerifyComplete() ISSUE-2000/02/18-henrygab - why public?!
6278
6279 Routine Description:
6280
6281 This routine executes when the port driver has completed a check verify
6282 ioctl. It will set the status of the master Irp, copy the media change
6283 count and complete the request.
6284
6285 Arguments:
6286
6287 Fdo - Supplies the functional device object which represents the logical unit.
6288
6289 Irp - Supplies the Irp which has completed.
6290
6291 Context - NULL
6292
6293 Return Value:
6294
6295 NT status
6296
6297 --*/
6298 NTSTATUS
6299 NTAPI
6300 ClassCheckVerifyComplete(
6301 IN PDEVICE_OBJECT Fdo,
6302 IN PIRP Irp,
6303 IN PVOID Context
6304 )
6305 {
6306 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
6307 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
6308
6309 PIRP originalIrp;
6310
6311 ASSERT_FDO(Fdo);
6312
6313 originalIrp = irpStack->Parameters.Others.Argument1;
6314
6315 //
6316 // Copy the media change count and status
6317 //
6318
6319 *((PULONG) (originalIrp->AssociatedIrp.SystemBuffer)) =
6320 fdoExtension->MediaChangeCount;
6321
6322 DebugPrint((2, "ClassCheckVerifyComplete - Media change count for"
6323 "device %d is %lx - saved as %lx\n",
6324 fdoExtension->DeviceNumber,
6325 fdoExtension->MediaChangeCount,
6326 *((PULONG) originalIrp->AssociatedIrp.SystemBuffer)));
6327
6328 originalIrp->IoStatus.Status = Irp->IoStatus.Status;
6329 originalIrp->IoStatus.Information = sizeof(ULONG);
6330
6331 ClassReleaseRemoveLock(Fdo, originalIrp);
6332 ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT);
6333
6334 IoFreeIrp(Irp);
6335
6336 return STATUS_MORE_PROCESSING_REQUIRED;
6337
6338 } // end ClassCheckVerifyComplete()
6339
6340 /*++////////////////////////////////////////////////////////////////////////////
6341
6342 ClassGetDescriptor()
6343
6344 Routine Description:
6345
6346 This routine will perform a query for the specified property id and will
6347 allocate a non-paged buffer to store the data in. It is the responsibility
6348 of the caller to ensure that this buffer is freed.
6349
6350 This routine must be run at IRQL_PASSIVE_LEVEL
6351
6352 Arguments:
6353
6354 DeviceObject - the device to query
6355 DeviceInfo - a location to store a pointer to the buffer we allocate
6356
6357 Return Value:
6358
6359 status
6360 if status is unsuccessful *DeviceInfo will be set to NULL, else the
6361 buffer allocated on behalf of the caller.
6362
6363 --*/
6364 NTSTATUS
6365 NTAPI
6366 ClassGetDescriptor(
6367 IN PDEVICE_OBJECT DeviceObject,
6368 IN PSTORAGE_PROPERTY_ID PropertyId,
6369 OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor
6370 )
6371 {
6372 STORAGE_PROPERTY_QUERY query;
6373 IO_STATUS_BLOCK ioStatus;
6374
6375 PSTORAGE_DESCRIPTOR_HEADER descriptor = NULL;
6376 ULONG length;
6377
6378 //UCHAR pass = 0;
6379
6380 PAGED_CODE();
6381
6382 //
6383 // Set the passed-in descriptor pointer to NULL as default
6384 //
6385
6386 *Descriptor = NULL;
6387
6388
6389 RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY));
6390 query.PropertyId = *PropertyId;
6391 query.QueryType = PropertyStandardQuery;
6392
6393 //
6394 // On the first pass we just want to get the first few
6395 // bytes of the descriptor so we can read it's size
6396 //
6397
6398 descriptor = (PVOID)&query;
6399
6400 ASSERT(sizeof(STORAGE_PROPERTY_QUERY) >= (sizeof(ULONG)*2));
6401
6402 ClassSendDeviceIoControlSynchronous(
6403 IOCTL_STORAGE_QUERY_PROPERTY,
6404 DeviceObject,
6405 &query,
6406 sizeof(STORAGE_PROPERTY_QUERY),
6407 sizeof(ULONG) * 2,
6408 FALSE,
6409 &ioStatus
6410 );
6411
6412 if(!NT_SUCCESS(ioStatus.Status)) {
6413
6414 DebugPrint((1, "ClassGetDescriptor: error %lx trying to "
6415 "query properties #1\n", ioStatus.Status));
6416 return ioStatus.Status;
6417 }
6418
6419 if (descriptor->Size == 0) {
6420
6421 //
6422 // This DebugPrint is to help third-party driver writers
6423 //
6424
6425 DebugPrint((0, "ClassGetDescriptor: size returned was zero?! (status "
6426 "%x\n", ioStatus.Status));
6427 return STATUS_UNSUCCESSFUL;
6428
6429 }
6430
6431 //
6432 // This time we know how much data there is so we can
6433 // allocate a buffer of the correct size
6434 //
6435
6436 length = descriptor->Size;
6437
6438 descriptor = ExAllocatePoolWithTag(NonPagedPool, length, '4BcS');
6439
6440 if(descriptor == NULL) {
6441
6442 DebugPrint((1, "ClassGetDescriptor: unable to memory for descriptor "
6443 "(%d bytes)\n", length));
6444 return STATUS_INSUFFICIENT_RESOURCES;
6445 }
6446
6447 //
6448 // setup the query again, as it was overwritten above
6449 //
6450
6451 RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY));
6452 query.PropertyId = *PropertyId;
6453 query.QueryType = PropertyStandardQuery;
6454
6455 //
6456 // copy the input to the new outputbuffer
6457 //
6458
6459 RtlCopyMemory(descriptor,
6460 &query,
6461 sizeof(STORAGE_PROPERTY_QUERY)
6462 );
6463
6464 ClassSendDeviceIoControlSynchronous(
6465 IOCTL_STORAGE_QUERY_PROPERTY,
6466 DeviceObject,
6467 descriptor,
6468 sizeof(STORAGE_PROPERTY_QUERY),
6469 length,
6470 FALSE,
6471 &ioStatus
6472 );
6473
6474 if(!NT_SUCCESS(ioStatus.Status)) {
6475
6476 DebugPrint((1, "ClassGetDescriptor: error %lx trying to "
6477 "query properties #1\n", ioStatus.Status));
6478 ExFreePool(descriptor);
6479 return ioStatus.Status;
6480 }
6481
6482 //
6483 // return the memory we've allocated to the caller
6484 //
6485
6486 *Descriptor = descriptor;
6487 return ioStatus.Status;
6488 } // end ClassGetDescriptor()
6489
6490 /*++////////////////////////////////////////////////////////////////////////////
6491
6492 ClassSignalCompletion()
6493
6494 Routine Description:
6495
6496 This completion routine will signal the event given as context and then
6497 return STATUS_MORE_PROCESSING_REQUIRED to stop event completion. It is
6498 the responsibility of the routine waiting on the event to complete the
6499 request and free the event.
6500
6501 Arguments:
6502
6503 DeviceObject - a pointer to the device object
6504
6505 Irp - a pointer to the irp
6506
6507 Event - a pointer to the event to signal
6508
6509 Return Value:
6510
6511 STATUS_MORE_PROCESSING_REQUIRED
6512
6513 --*/
6514 NTSTATUS
6515 NTAPI
6516 ClassSignalCompletion(
6517 IN PDEVICE_OBJECT DeviceObject,
6518 IN PIRP Irp,
6519 IN PKEVENT Event
6520 )
6521 {
6522 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
6523
6524 return STATUS_MORE_PROCESSING_REQUIRED;
6525 } // end ClassSignalCompletion()
6526
6527 /*++////////////////////////////////////////////////////////////////////////////
6528
6529 ClassPnpQueryFdoRelations()
6530
6531 Routine Description:
6532
6533 This routine will call the driver's enumeration routine to update the
6534 list of PDO's. It will then build a response to the
6535 IRP_MN_QUERY_DEVICE_RELATIONS and place it into the information field in
6536 the irp.
6537
6538 Arguments:
6539
6540 Fdo - a pointer to the functional device object we are enumerating
6541
6542 Irp - a pointer to the enumeration request
6543
6544 Return Value:
6545
6546 status
6547
6548 --*/
6549 NTSTATUS
6550 NTAPI
6551 ClassPnpQueryFdoRelations(
6552 IN PDEVICE_OBJECT Fdo,
6553 IN PIRP Irp
6554 )
6555 {
6556 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
6557 PCLASS_DRIVER_EXTENSION
6558 driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject,
6559 CLASS_DRIVER_EXTENSION_KEY);
6560 NTSTATUS status;
6561
6562 PAGED_CODE();
6563
6564 //
6565 // If there's already an enumeration in progress then don't start another
6566 // one.
6567 //
6568
6569 if(InterlockedIncrement(&(fdoExtension->EnumerationInterlock)) == 1) {
6570 status = driverExtension->InitData.ClassEnumerateDevice(Fdo);
6571 }
6572
6573 Irp->IoStatus.Information = (ULONG_PTR) NULL;
6574
6575 Irp->IoStatus.Status = ClassRetrieveDeviceRelations(
6576 Fdo,
6577 BusRelations,
6578 (PDEVICE_RELATIONS*)&Irp->IoStatus.Information);
6579 InterlockedDecrement(&(fdoExtension->EnumerationInterlock));
6580
6581 return Irp->IoStatus.Status;
6582 } // end ClassPnpQueryFdoRelations()
6583
6584 /*++////////////////////////////////////////////////////////////////////////////
6585
6586 ClassMarkChildrenMissing()
6587
6588 Routine Description:
6589
6590 This routine will call ClassMarkChildMissing() for all children.
6591 It acquires the ChildLock before calling ClassMarkChildMissing().
6592
6593 Arguments:
6594
6595 Fdo - the "bus's" device object, such as the disk FDO for non-removable
6596 disks with multiple partitions.
6597
6598 Return Value:
6599
6600 None
6601
6602 --*/
6603 VOID
6604 NTAPI
6605 ClassMarkChildrenMissing(
6606 IN PFUNCTIONAL_DEVICE_EXTENSION Fdo
6607 )
6608 {
6609 PCOMMON_DEVICE_EXTENSION commonExtension = &(Fdo->CommonExtension);
6610 PPHYSICAL_DEVICE_EXTENSION nextChild = commonExtension->ChildList;
6611
6612 PAGED_CODE();
6613
6614 ClassAcquireChildLock(Fdo);
6615
6616 while (nextChild){
6617 PPHYSICAL_DEVICE_EXTENSION tmpChild;
6618
6619 /*
6620 * ClassMarkChildMissing will also dequeue the child extension.
6621 * So get the next pointer before calling ClassMarkChildMissing.
6622 */
6623 tmpChild = nextChild;
6624 nextChild = tmpChild->CommonExtension.ChildList;
6625 ClassMarkChildMissing(tmpChild, FALSE);
6626 }
6627 ClassReleaseChildLock(Fdo);
6628 return;
6629 } // end ClassMarkChildrenMissing()
6630
6631 /*++////////////////////////////////////////////////////////////////////////////
6632
6633 ClassMarkChildMissing()
6634
6635 Routine Description:
6636
6637 This routine will make an active child "missing." If the device has never
6638 been enumerated then it will be deleted on the spot. If the device has
6639 not been enumerated then it will be marked as missing so that we can
6640 not report it in the next device enumeration.
6641
6642 Arguments:
6643
6644 Child - the child device to be marked as missing.
6645
6646 AcquireChildLock - TRUE if the child lock should be acquired before removing
6647 the missing child. FALSE if the child lock is already
6648 acquired by this thread.
6649
6650 Return Value:
6651
6652 returns whether or not the child device object has previously been reported
6653 to PNP.
6654
6655 --*/
6656 BOOLEAN
6657 NTAPI
6658 ClassMarkChildMissing(
6659 IN PPHYSICAL_DEVICE_EXTENSION Child,
6660 IN BOOLEAN AcquireChildLock
6661 )
6662 {
6663 BOOLEAN returnValue = Child->IsEnumerated;
6664
6665 PAGED_CODE();
6666 ASSERT_PDO(Child->DeviceObject);
6667
6668 Child->IsMissing = TRUE;
6669
6670 //
6671 // Make sure this child is not in the active list.
6672 //
6673
6674 ClassRemoveChild(Child->CommonExtension.PartitionZeroExtension,
6675 Child,
6676 AcquireChildLock);
6677
6678 if(Child->IsEnumerated == FALSE) {
6679 ClassRemoveDevice(Child->DeviceObject, IRP_MN_REMOVE_DEVICE);
6680 }
6681
6682 return returnValue;
6683 } // end ClassMarkChildMissing()
6684
6685 /*++////////////////////////////////////////////////////////////////////////////
6686
6687 ClassRetrieveDeviceRelations()
6688
6689 Routine Description:
6690
6691 This routine will allocate a buffer to hold the specified list of
6692 relations. It will then fill in the list with referenced device pointers
6693 and will return the request.
6694
6695 Arguments:
6696
6697 Fdo - pointer to the FDO being queried
6698
6699 RelationType - what type of relations are being queried
6700
6701 DeviceRelations - a location to store a pointer to the response
6702
6703 Return Value:
6704
6705 status
6706
6707 --*/
6708 NTSTATUS
6709 NTAPI
6710 ClassRetrieveDeviceRelations(
6711 IN PDEVICE_OBJECT Fdo,
6712 IN DEVICE_RELATION_TYPE RelationType,
6713 OUT PDEVICE_RELATIONS *DeviceRelations
6714 )
6715 {
6716 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
6717
6718 ULONG count = 0;
6719 ULONG i;
6720
6721 PPHYSICAL_DEVICE_EXTENSION nextChild;
6722
6723 ULONG relationsSize;
6724 PDEVICE_RELATIONS deviceRelations = NULL;
6725
6726 NTSTATUS status;
6727
6728 PAGED_CODE();
6729
6730 ClassAcquireChildLock(fdoExtension);
6731
6732 nextChild = fdoExtension->CommonExtension.ChildList;
6733
6734 //
6735 // Count the number of PDO's attached to this disk
6736 //
6737
6738 while(nextChild != NULL) {
6739 PCOMMON_DEVICE_EXTENSION commonExtension;
6740
6741 commonExtension = &(nextChild->CommonExtension);
6742
6743 ASSERTMSG("ClassPnp internal error: missing child on active list\n",
6744 (nextChild->IsMissing == FALSE));
6745
6746 nextChild = commonExtension->ChildList;
6747
6748 count++;
6749 };
6750
6751 relationsSize = (sizeof(DEVICE_RELATIONS) +
6752 (count * sizeof(PDEVICE_OBJECT)));
6753
6754 deviceRelations = ExAllocatePoolWithTag(PagedPool, relationsSize, '5BcS');
6755
6756 if(deviceRelations == NULL) {
6757
6758 DebugPrint((1, "ClassRetrieveDeviceRelations: unable to allocate "
6759 "%d bytes for device relations\n", relationsSize));
6760
6761 ClassReleaseChildLock(fdoExtension);
6762
6763 return STATUS_INSUFFICIENT_RESOURCES;
6764 }
6765
6766 RtlZeroMemory(deviceRelations, relationsSize);
6767
6768 nextChild = fdoExtension->CommonExtension.ChildList;
6769 i = count - 1;
6770
6771 while(nextChild != NULL) {
6772 PCOMMON_DEVICE_EXTENSION commonExtension;
6773
6774 commonExtension = &(nextChild->CommonExtension);
6775
6776 ASSERTMSG("ClassPnp internal error: missing child on active list\n",
6777 (nextChild->IsMissing == FALSE));
6778
6779 deviceRelations->Objects[i--] = nextChild->DeviceObject;
6780
6781 status = ObReferenceObjectByPointer(
6782 nextChild->DeviceObject,
6783 0,
6784 NULL,
6785 KernelMode);
6786 ASSERT(NT_SUCCESS(status));
6787
6788 nextChild->IsEnumerated = TRUE;
6789 nextChild = commonExtension->ChildList;
6790 }
6791
6792 ASSERTMSG("Child list has changed: ", i == -1);
6793
6794 deviceRelations->Count = count;
6795 *DeviceRelations = deviceRelations;
6796 ClassReleaseChildLock(fdoExtension);
6797 return STATUS_SUCCESS;
6798 } // end ClassRetrieveDeviceRelations()
6799
6800 /*++////////////////////////////////////////////////////////////////////////////
6801
6802 ClassGetPdoId()
6803
6804 Routine Description:
6805
6806 This routine will call into the driver to retrieve a copy of one of it's
6807 id strings.
6808
6809 Arguments:
6810
6811 Pdo - a pointer to the pdo being queried
6812
6813 IdType - which type of id string is being queried
6814
6815 IdString - an allocated unicode string structure which the driver
6816 can fill in.
6817
6818 Return Value:
6819
6820 status
6821
6822 --*/
6823 NTSTATUS
6824 NTAPI
6825 ClassGetPdoId(
6826 IN PDEVICE_OBJECT Pdo,
6827 IN BUS_QUERY_ID_TYPE IdType,
6828 IN PUNICODE_STRING IdString
6829 )
6830 {
6831 PCLASS_DRIVER_EXTENSION
6832 driverExtension = IoGetDriverObjectExtension(Pdo->DriverObject,
6833 CLASS_DRIVER_EXTENSION_KEY);
6834
6835 ASSERT_PDO(Pdo);
6836 ASSERT(driverExtension->InitData.ClassQueryId);
6837
6838 PAGED_CODE();
6839
6840 return driverExtension->InitData.ClassQueryId( Pdo, IdType, IdString);
6841 } // end ClassGetPdoId()
6842
6843 /*++////////////////////////////////////////////////////////////////////////////
6844
6845 ClassQueryPnpCapabilities()
6846
6847 Routine Description:
6848
6849 This routine will call into the class driver to retrieve it's pnp
6850 capabilities.
6851
6852 Arguments:
6853
6854 PhysicalDeviceObject - The physical device object to retrieve properties
6855 for.
6856
6857 Return Value:
6858
6859 status
6860
6861 --*/
6862 NTSTATUS
6863 NTAPI
6864 ClassQueryPnpCapabilities(
6865 IN PDEVICE_OBJECT DeviceObject,
6866 IN PDEVICE_CAPABILITIES Capabilities
6867 )
6868 {
6869 PCLASS_DRIVER_EXTENSION driverExtension =
6870 ClassGetDriverExtension(DeviceObject->DriverObject);
6871 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
6872
6873 PCLASS_QUERY_PNP_CAPABILITIES queryRoutine = NULL;
6874
6875 PAGED_CODE();
6876
6877 ASSERT(DeviceObject);
6878 ASSERT(Capabilities);
6879
6880 if(commonExtension->IsFdo) {
6881 queryRoutine = driverExtension->InitData.FdoData.ClassQueryPnpCapabilities;
6882 } else {
6883 queryRoutine = driverExtension->InitData.PdoData.ClassQueryPnpCapabilities;
6884 }
6885
6886 if(queryRoutine) {
6887 return queryRoutine(DeviceObject,
6888 Capabilities);
6889 } else {
6890 return STATUS_NOT_IMPLEMENTED;
6891 }
6892 } // end ClassQueryPnpCapabilities()
6893
6894 /*++////////////////////////////////////////////////////////////////////////////
6895
6896 ClassInvalidateBusRelations()
6897
6898 Routine Description:
6899
6900 This routine re-enumerates the devices on the "bus". It will call into
6901 the driver's ClassEnumerate routine to update the device objects
6902 immediately. It will then schedule a bus re-enumeration for pnp by calling
6903 IoInvalidateDeviceRelations.
6904
6905 Arguments:
6906
6907 Fdo - a pointer to the functional device object for this bus
6908
6909 Return Value:
6910
6911 none
6912
6913 --*/
6914 VOID
6915 NTAPI
6916 ClassInvalidateBusRelations(
6917 IN PDEVICE_OBJECT Fdo
6918 )
6919 {
6920 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
6921 PCLASS_DRIVER_EXTENSION
6922 driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject,
6923 CLASS_DRIVER_EXTENSION_KEY);
6924
6925 NTSTATUS status = STATUS_SUCCESS;
6926
6927 PAGED_CODE();
6928
6929 ASSERT_FDO(Fdo);
6930 ASSERT(driverExtension->InitData.ClassEnumerateDevice != NULL);
6931
6932 if(InterlockedIncrement(&(fdoExtension->EnumerationInterlock)) == 1) {
6933 status = driverExtension->InitData.ClassEnumerateDevice(Fdo);
6934 }
6935 InterlockedDecrement(&(fdoExtension->EnumerationInterlock));
6936
6937 if(!NT_SUCCESS(status)) {
6938
6939 DebugPrint((1, "ClassInvalidateBusRelations: EnumerateDevice routine "
6940 "returned %lx\n", status));
6941 }
6942
6943 IoInvalidateDeviceRelations(fdoExtension->LowerPdo, BusRelations);
6944
6945 return;
6946 } // end ClassInvalidateBusRelations()
6947
6948 /*++////////////////////////////////////////////////////////////////////////////
6949
6950 ClassRemoveDevice() ISSUE-2000/02/18-henrygab - why public?!
6951
6952 Routine Description:
6953
6954 This routine is called to handle the "removal" of a device. It will
6955 forward the request downwards if necesssary, call into the driver
6956 to release any necessary resources (memory, events, etc) and then
6957 will delete the device object.
6958
6959 Arguments:
6960
6961 DeviceObject - a pointer to the device object being removed
6962
6963 RemoveType - indicates what type of remove this is (regular or surprise).
6964
6965 Return Value:
6966
6967 status
6968
6969 --*/
6970 NTSTATUS
6971 NTAPI
6972 ClassRemoveDevice(
6973 IN PDEVICE_OBJECT DeviceObject,
6974 IN UCHAR RemoveType
6975 )
6976 {
6977 PCLASS_DRIVER_EXTENSION
6978 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
6979 CLASS_DRIVER_EXTENSION_KEY);
6980 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
6981 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
6982 PCLASS_WMI_INFO classWmiInfo;
6983 BOOLEAN proceedWithRemove = TRUE;
6984 NTSTATUS status;
6985
6986 PAGED_CODE();
6987
6988 commonExtension->IsRemoved = REMOVE_PENDING;
6989
6990 /*
6991 * Deregister from WMI.
6992 */
6993 classWmiInfo = commonExtension->IsFdo ?
6994 &driverExtension->InitData.FdoData.ClassWmiInfo :
6995 &driverExtension->InitData.PdoData.ClassWmiInfo;
6996 if (classWmiInfo->GuidRegInfo){
6997 status = IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_DEREGISTER);
6998 DBGTRACE(ClassDebugInfo, ("ClassRemoveDevice: IoWMIRegistrationControl(%p, WMI_ACTION_DEREGISTER) --> %lx", DeviceObject, status));
6999 }
7000
7001 /*
7002 * If we exposed a "shingle" (a named device interface openable by CreateFile)
7003 * then delete it now.
7004 */
7005 if (commonExtension->MountedDeviceInterfaceName.Buffer){
7006 IoSetDeviceInterfaceState(&commonExtension->MountedDeviceInterfaceName, FALSE);
7007 RtlFreeUnicodeString(&commonExtension->MountedDeviceInterfaceName);
7008 RtlInitUnicodeString(&commonExtension->MountedDeviceInterfaceName, NULL);
7009 }
7010
7011 //
7012 // If this is a surprise removal we leave the device around - which means
7013 // we don't have to (or want to) drop the remove lock and wait for pending
7014 // requests to complete.
7015 //
7016
7017 if (RemoveType == IRP_MN_REMOVE_DEVICE){
7018
7019 //
7020 // Release the lock we acquired when the device object was created.
7021 //
7022
7023 ClassReleaseRemoveLock(DeviceObject, (PIRP) DeviceObject);
7024
7025 DebugPrint((1, "ClasspRemoveDevice - Reference count is now %d\n",
7026 commonExtension->RemoveLock));
7027
7028 KeWaitForSingleObject(&commonExtension->RemoveEvent,
7029 Executive,
7030 KernelMode,
7031 FALSE,
7032 NULL);
7033
7034 DebugPrint((1, "ClasspRemoveDevice - removing device %p\n", DeviceObject));
7035
7036 if(commonExtension->IsFdo) {
7037
7038 DebugPrint((1, "ClasspRemoveDevice - FDO %p has received a "
7039 "remove request.\n", DeviceObject));
7040
7041 }
7042 else {
7043 PPHYSICAL_DEVICE_EXTENSION pdoExtension = DeviceObject->DeviceExtension;
7044
7045 if (pdoExtension->IsMissing){
7046 /*
7047 * The child partition PDO is missing, so we are going to go ahead
7048 * and delete it for the remove.
7049 */
7050 DBGTRACE(ClassDebugWarning, ("ClasspRemoveDevice - PDO %p is missing and will be removed", DeviceObject));
7051 }
7052 else {
7053 /*
7054 * We got a remove for a child partition PDO which is not actually missing.
7055 * So we will NOT actually delete it.
7056 */
7057 DBGTRACE(ClassDebugWarning, ("ClasspRemoveDevice - PDO %p still exists and will be removed when it disappears", DeviceObject));
7058
7059 //
7060 // Reacquire the remove lock for the next time this comes around.
7061 //
7062
7063 ClassAcquireRemoveLock(DeviceObject, (PIRP) DeviceObject);
7064
7065 //
7066 // the device wasn't missing so it's not really been removed.
7067 //
7068
7069 commonExtension->IsRemoved = NO_REMOVE;
7070
7071 IoInvalidateDeviceRelations(
7072 commonExtension->PartitionZeroExtension->LowerPdo,
7073 BusRelations);
7074
7075 proceedWithRemove = FALSE;
7076 }
7077 }
7078 }
7079
7080
7081 if (proceedWithRemove){
7082
7083 /*
7084 * Call the class driver's remove handler.
7085 * All this is supposed to do is clean up its data and device interfaces.
7086 */
7087 ASSERT(commonExtension->DevInfo->ClassRemoveDevice);
7088 status = commonExtension->DevInfo->ClassRemoveDevice(DeviceObject, RemoveType);
7089 ASSERT(NT_SUCCESS(status));
7090 status = STATUS_SUCCESS;
7091
7092 if (commonExtension->IsFdo){
7093 //PDEVICE_OBJECT pdo;
7094 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
7095
7096 ClasspDisableTimer(fdoExtension->DeviceObject);
7097
7098 if (RemoveType == IRP_MN_REMOVE_DEVICE){
7099
7100 PPHYSICAL_DEVICE_EXTENSION child;
7101
7102 //
7103 // Cleanup the media detection resources now that the class driver
7104 // has stopped it's timer (if any) and we can be sure they won't
7105 // call us to do detection again.
7106 //
7107
7108 ClassCleanupMediaChangeDetection(fdoExtension);
7109
7110 //
7111 // Cleanup any Failure Prediction stuff
7112 //
7113 if (fdoExtension->FailurePredictionInfo) {
7114 ExFreePool(fdoExtension->FailurePredictionInfo);
7115 fdoExtension->FailurePredictionInfo = NULL;
7116 }
7117
7118 /*
7119 * Ordinarily all child PDOs will be removed by the time
7120 * that the parent gets the REMOVE_DEVICE.
7121 * However, if a child PDO has been created but has not
7122 * been announced in a QueryDeviceRelations, then it is
7123 * just a private data structure unknown to pnp, and we have
7124 * to delete it ourselves.
7125 */
7126 ClassAcquireChildLock(fdoExtension);
7127 while (child = ClassRemoveChild(fdoExtension, NULL, FALSE)){
7128
7129 //
7130 // Yank the pdo. This routine will unlink the device from the
7131 // pdo list so NextPdo will point to the next one when it's
7132 // complete.
7133 //
7134 child->IsMissing = TRUE;
7135 ClassRemoveDevice(child->DeviceObject, IRP_MN_REMOVE_DEVICE);
7136 }
7137 ClassReleaseChildLock(fdoExtension);
7138 }
7139 else if (RemoveType == IRP_MN_SURPRISE_REMOVAL){
7140 /*
7141 * This is a surprise-remove on the parent FDO.
7142 * We will mark the child PDOs as missing so that they
7143 * will actually get deleted when they get a REMOVE_DEVICE.
7144 */
7145 ClassMarkChildrenMissing(fdoExtension);
7146 }
7147
7148 ClasspFreeReleaseRequest(DeviceObject);
7149
7150 if (RemoveType == IRP_MN_REMOVE_DEVICE){
7151
7152 //
7153 // Free FDO-specific data structs
7154 //
7155 if (fdoExtension->PrivateFdoData){
7156
7157 DestroyAllTransferPackets(DeviceObject);
7158
7159 ExFreePool(fdoExtension->PrivateFdoData);
7160 fdoExtension->PrivateFdoData = NULL;
7161 }
7162
7163 if (commonExtension->DeviceName.Buffer) {
7164 ExFreePool(commonExtension->DeviceName.Buffer);
7165 RtlInitUnicodeString(&commonExtension->DeviceName, NULL);
7166 }
7167
7168 if (fdoExtension->AdapterDescriptor) {
7169 ExFreePool(fdoExtension->AdapterDescriptor);
7170 fdoExtension->AdapterDescriptor = NULL;
7171 }
7172
7173 if (fdoExtension->DeviceDescriptor) {
7174 ExFreePool(fdoExtension->DeviceDescriptor);
7175 fdoExtension->DeviceDescriptor = NULL;
7176 }
7177
7178 //
7179 // Detach our device object from the stack - there's no reason
7180 // to hold off our cleanup any longer.
7181 //
7182
7183 IoDetachDevice(lowerDeviceObject);
7184 }
7185 }
7186 else {
7187 /*
7188 * This is a child partition PDO.
7189 * We have already determined that it was previously marked
7190 * as missing. So if this is a REMOVE_DEVICE, we will actually
7191 * delete it.
7192 */
7193 if (RemoveType == IRP_MN_REMOVE_DEVICE){
7194 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
7195 commonExtension->PartitionZeroExtension;
7196 PPHYSICAL_DEVICE_EXTENSION pdoExtension =
7197 (PPHYSICAL_DEVICE_EXTENSION) commonExtension;
7198
7199 //
7200 // See if this device is in the child list (if this was a suprise
7201 // removal it might be) and remove it.
7202 //
7203
7204 ClassRemoveChild(fdoExtension, pdoExtension, TRUE);
7205 }
7206 }
7207
7208 commonExtension->PartitionLength.QuadPart = 0;
7209
7210 if (RemoveType == IRP_MN_REMOVE_DEVICE){
7211 IoDeleteDevice(DeviceObject);
7212 }
7213 }
7214
7215 return STATUS_SUCCESS;
7216 } // end ClassRemoveDevice()
7217
7218 /*++////////////////////////////////////////////////////////////////////////////
7219
7220 ClassGetDriverExtension()
7221
7222 Routine Description:
7223
7224 This routine will return the classpnp's driver extension.
7225
7226 Arguments:
7227
7228 DriverObject - the driver object for which to get classpnp's extension
7229
7230 Return Value:
7231
7232 Either NULL if none, or a pointer to the driver extension
7233
7234 --*/
7235 PCLASS_DRIVER_EXTENSION
7236 NTAPI
7237 ClassGetDriverExtension(
7238 IN PDRIVER_OBJECT DriverObject
7239 )
7240 {
7241 return IoGetDriverObjectExtension(DriverObject, CLASS_DRIVER_EXTENSION_KEY);
7242 } // end ClassGetDriverExtension()
7243
7244 /*++////////////////////////////////////////////////////////////////////////////
7245
7246 ClasspStartIo()
7247
7248 Routine Description:
7249
7250 This routine wraps the class driver's start io routine. If the device
7251 is being removed it will complete any requests with
7252 STATUS_DEVICE_DOES_NOT_EXIST and fire up the next packet.
7253
7254 Arguments:
7255
7256 Return Value:
7257
7258 none
7259
7260 --*/
7261 VOID
7262 NTAPI
7263 ClasspStartIo(
7264 IN PDEVICE_OBJECT DeviceObject,
7265 IN PIRP Irp
7266 )
7267 {
7268 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
7269
7270 //
7271 // We're already holding the remove lock so just check the variable and
7272 // see what's going on.
7273 //
7274
7275 if(commonExtension->IsRemoved) {
7276
7277 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
7278
7279 ClassAcquireRemoveLock(DeviceObject, (PIRP) ClasspStartIo);
7280 ClassReleaseRemoveLock(DeviceObject, Irp);
7281 ClassCompleteRequest(DeviceObject, Irp, IO_DISK_INCREMENT);
7282 IoStartNextPacket(DeviceObject, FALSE);
7283 ClassReleaseRemoveLock(DeviceObject, (PIRP) ClasspStartIo);
7284 return;
7285 }
7286
7287 commonExtension->DriverExtension->InitData.ClassStartIo(
7288 DeviceObject,
7289 Irp);
7290
7291 return;
7292 } // ClasspStartIo()
7293
7294 /*++////////////////////////////////////////////////////////////////////////////
7295
7296 ClassUpdateInformationInRegistry()
7297
7298 Routine Description:
7299
7300 This routine has knowledge about the layout of the device map information
7301 in the registry. It will update this information to include a value
7302 entry specifying the dos device name that is assumed to get assigned
7303 to this NT device name. For more information on this assigning of the
7304 dos device name look in the drive support routine in the hal that assigns
7305 all dos names.
7306
7307 Since some versions of some device's firmware did not work and some
7308 vendors did not bother to follow the specification, the entire inquiry
7309 information must also be stored in the registry so than someone can
7310 figure out the firmware version.
7311
7312 Arguments:
7313
7314 DeviceObject - A pointer to the device object for the tape device.
7315
7316 Return Value:
7317
7318 None
7319
7320 --*/
7321 VOID
7322 NTAPI
7323 ClassUpdateInformationInRegistry(
7324 IN PDEVICE_OBJECT Fdo,
7325 IN PCHAR DeviceName,
7326 IN ULONG DeviceNumber,
7327 IN PINQUIRYDATA InquiryData,
7328 IN ULONG InquiryDataLength
7329 )
7330 {
7331 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
7332 NTSTATUS status;
7333 SCSI_ADDRESS scsiAddress;
7334 OBJECT_ATTRIBUTES objectAttributes;
7335 PUCHAR buffer;
7336 STRING string;
7337 UNICODE_STRING unicodeName;
7338 UNICODE_STRING unicodeRegistryPath;
7339 UNICODE_STRING unicodeData;
7340 HANDLE targetKey;
7341 IO_STATUS_BLOCK ioStatus;
7342
7343
7344 PAGED_CODE();
7345
7346 ASSERT(DeviceName);
7347 fdoExtension = Fdo->DeviceExtension;
7348 buffer = NULL;
7349 targetKey = NULL;
7350 RtlZeroMemory(&unicodeName, sizeof(UNICODE_STRING));
7351 RtlZeroMemory(&unicodeData, sizeof(UNICODE_STRING));
7352 RtlZeroMemory(&unicodeRegistryPath, sizeof(UNICODE_STRING));
7353
7354 TRY {
7355
7356 //
7357 // Issue GET_ADDRESS Ioctl to determine path, target, and lun information.
7358 //
7359
7360 ClassSendDeviceIoControlSynchronous(
7361 IOCTL_SCSI_GET_ADDRESS,
7362 Fdo,
7363 &scsiAddress,
7364 0,
7365 sizeof(SCSI_ADDRESS),
7366 FALSE,
7367 &ioStatus
7368 );
7369
7370 if (!NT_SUCCESS(ioStatus.Status)) {
7371
7372 status = ioStatus.Status;
7373 DebugPrint((1,
7374 "UpdateInformationInRegistry: Get Address failed %lx\n",
7375 status));
7376 LEAVE;
7377
7378 } else {
7379
7380 DebugPrint((1,
7381 "GetAddress: Port %x, Path %x, Target %x, Lun %x\n",
7382 scsiAddress.PortNumber,
7383 scsiAddress.PathId,
7384 scsiAddress.TargetId,
7385 scsiAddress.Lun));
7386
7387 }
7388
7389 //
7390 // Allocate a buffer for the reg. spooge.
7391 //
7392
7393 buffer = ExAllocatePoolWithTag(PagedPool, 1024, '6BcS');
7394
7395 if (buffer == NULL) {
7396
7397 //
7398 // There is not return value for this. Since this is done at
7399 // claim device time (currently only system initialization) getting
7400 // the registry information correct will be the least of the worries.
7401 //
7402
7403 LEAVE;
7404 }
7405
7406 sprintf(buffer,
7407 "\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi\\Scsi Port %d\\Scsi Bus %d\\Target Id %d\\Logical Unit Id %d",
7408 scsiAddress.PortNumber,
7409 scsiAddress.PathId,
7410 scsiAddress.TargetId,
7411 scsiAddress.Lun);
7412
7413 RtlInitString(&string, buffer);
7414
7415 status = RtlAnsiStringToUnicodeString(&unicodeRegistryPath,
7416 &string,
7417 TRUE);
7418
7419 if (!NT_SUCCESS(status)) {
7420 LEAVE;
7421 }
7422
7423 //
7424 // Open the registry key for the scsi information for this
7425 // scsibus, target, lun.
7426 //
7427
7428 InitializeObjectAttributes(&objectAttributes,
7429 &unicodeRegistryPath,
7430 OBJ_CASE_INSENSITIVE,
7431 NULL,
7432 NULL);
7433
7434 status = ZwOpenKey(&targetKey,
7435 KEY_READ | KEY_WRITE,
7436 &objectAttributes);
7437
7438 if (!NT_SUCCESS(status)) {
7439 LEAVE;
7440 }
7441
7442 //
7443 // Now construct and attempt to create the registry value
7444 // specifying the device name in the appropriate place in the
7445 // device map.
7446 //
7447
7448 RtlInitUnicodeString(&unicodeName, L"DeviceName");
7449
7450 sprintf(buffer, "%s%d", DeviceName, DeviceNumber);
7451 RtlInitString(&string, buffer);
7452 status = RtlAnsiStringToUnicodeString(&unicodeData,
7453 &string,
7454 TRUE);
7455 if (NT_SUCCESS(status)) {
7456 status = ZwSetValueKey(targetKey,
7457 &unicodeName,
7458 0,
7459 REG_SZ,
7460 unicodeData.Buffer,
7461 unicodeData.Length);
7462 }
7463
7464 //
7465 // if they sent in data, update the registry
7466 //
7467
7468 if (InquiryDataLength) {
7469
7470 ASSERT(InquiryData);
7471
7472 RtlInitUnicodeString(&unicodeName, L"InquiryData");
7473 status = ZwSetValueKey(targetKey,
7474 &unicodeName,
7475 0,
7476 REG_BINARY,
7477 InquiryData,
7478 InquiryDataLength);
7479 }
7480
7481 // that's all, except to clean up.
7482
7483 } FINALLY {
7484
7485 if (unicodeData.Buffer) {
7486 RtlFreeUnicodeString(&unicodeData);
7487 }
7488 if (unicodeRegistryPath.Buffer) {
7489 RtlFreeUnicodeString(&unicodeRegistryPath);
7490 }
7491 if (targetKey) {
7492 ZwClose(targetKey);
7493 }
7494 if (buffer) {
7495 ExFreePool(buffer);
7496 }
7497
7498 }
7499
7500 } // end ClassUpdateInformationInRegistry()
7501
7502 /*++////////////////////////////////////////////////////////////////////////////
7503
7504 ClasspSendSynchronousCompletion()
7505
7506 Routine Description:
7507
7508 This completion routine will set the user event in the irp after
7509 freeing the irp and the associated MDL (if any).
7510
7511 Arguments:
7512
7513 DeviceObject - the device object which requested the completion routine
7514
7515 Irp - the irp being completed
7516
7517 Context - unused
7518
7519 Return Value:
7520
7521 STATUS_MORE_PROCESSING_REQUIRED
7522
7523 --*/
7524 NTSTATUS
7525 NTAPI
7526 ClasspSendSynchronousCompletion(
7527 IN PDEVICE_OBJECT DeviceObject,
7528 IN PIRP Irp,
7529 IN PVOID Context
7530 )
7531 {
7532 DebugPrint((3, "ClasspSendSynchronousCompletion: %p %p %p\n",
7533 DeviceObject, Irp, Context));
7534 //
7535 // First set the status and information fields in the io status block
7536 // provided by the caller.
7537 //
7538
7539 *(Irp->UserIosb) = Irp->IoStatus;
7540
7541 //
7542 // Unlock the pages for the data buffer.
7543 //
7544
7545 if(Irp->MdlAddress) {
7546 MmUnlockPages(Irp->MdlAddress);
7547 IoFreeMdl(Irp->MdlAddress);
7548 }
7549
7550 //
7551 // Signal the caller's event.
7552 //
7553
7554 KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
7555
7556 //
7557 // Free the MDL and the IRP.
7558 //
7559
7560 IoFreeIrp(Irp);
7561
7562 return STATUS_MORE_PROCESSING_REQUIRED;
7563 } // end ClasspSendSynchronousCompletion()
7564
7565 /*++
7566
7567 ISSUE-2000/02/20-henrygab Not documented ClasspRegisterMountedDeviceInterface
7568
7569 --*/
7570 VOID
7571 NTAPI
7572 ClasspRegisterMountedDeviceInterface(
7573 IN PDEVICE_OBJECT DeviceObject
7574 )
7575 {
7576
7577 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
7578 BOOLEAN isFdo = commonExtension->IsFdo;
7579
7580 PDEVICE_OBJECT pdo;
7581 UNICODE_STRING interfaceName;
7582
7583 NTSTATUS status;
7584
7585 if(isFdo) {
7586
7587 PFUNCTIONAL_DEVICE_EXTENSION functionalExtension;
7588
7589 functionalExtension =
7590 (PFUNCTIONAL_DEVICE_EXTENSION) commonExtension;
7591 pdo = functionalExtension->LowerPdo;
7592 } else {
7593 pdo = DeviceObject;
7594 }
7595
7596 status = IoRegisterDeviceInterface(
7597 pdo,
7598 &MOUNTDEV_MOUNTED_DEVICE_GUID,
7599 NULL,
7600 &interfaceName
7601 );
7602
7603 if(NT_SUCCESS(status)) {
7604
7605 //
7606 // Copy the interface name before setting the interface state - the
7607 // name is needed by the components we notify.
7608 //
7609
7610 commonExtension->MountedDeviceInterfaceName = interfaceName;
7611 status = IoSetDeviceInterfaceState(&interfaceName, TRUE);
7612
7613 if(!NT_SUCCESS(status)) {
7614 RtlFreeUnicodeString(&interfaceName);
7615 }
7616 }
7617
7618 if(!NT_SUCCESS(status)) {
7619 RtlInitUnicodeString(&(commonExtension->MountedDeviceInterfaceName),
7620 NULL);
7621 }
7622 return;
7623 } // end ClasspRegisterMountedDeviceInterface()
7624
7625 /*++////////////////////////////////////////////////////////////////////////////
7626
7627 ClassSendDeviceIoControlSynchronous()
7628
7629 Routine Description:
7630
7631 This routine is based upon IoBuildDeviceIoControlRequest(). It has been
7632 modified to reduce code and memory by not double-buffering the io, using
7633 the same buffer for both input and output, allocating and deallocating
7634 the mdl on behalf of the caller, and waiting for the io to complete.
7635
7636 This routine also works around the rare cases in which APC's are disabled.
7637 Since IoBuildDeviceIoControl() used APC's to signal completion, this had
7638 led to a number of difficult-to-detect hangs, where the irp was completed,
7639 but the event passed to IoBuild..() was still being waited upon by the
7640 caller.
7641
7642 Arguments:
7643
7644 IoControlCode - the IOCTL to send
7645
7646 TargetDeviceObject - the device object that should handle the ioctl
7647
7648 Buffer - the input and output buffer, or NULL if no input/output
7649
7650 InputBufferLength - the number of bytes prepared for the IOCTL in Buffer
7651
7652 OutputBufferLength - the number of bytes to be filled in upon success
7653
7654 InternalDeviceIoControl - if TRUE, uses IRP_MJ_INTERNAL_DEVICE_CONTROL
7655
7656 IoStatus - the status block that contains the results of the operation
7657
7658 Return Value:
7659
7660 --*/
7661 VOID
7662 NTAPI
7663 ClassSendDeviceIoControlSynchronous(
7664 IN ULONG IoControlCode,
7665 IN PDEVICE_OBJECT TargetDeviceObject,
7666 IN OUT PVOID Buffer OPTIONAL,
7667 IN ULONG InputBufferLength,
7668 IN ULONG OutputBufferLength,
7669 IN BOOLEAN InternalDeviceIoControl,
7670 OUT PIO_STATUS_BLOCK IoStatus
7671 )
7672 {
7673 PIRP irp;
7674 PIO_STACK_LOCATION irpSp;
7675 ULONG method;
7676
7677 PAGED_CODE();
7678
7679 irp = NULL;
7680 method = IoControlCode & 3;
7681
7682
7683 #if DBG // Begin Argument Checking (nop in fre version)
7684
7685 ASSERT(ARGUMENT_PRESENT(IoStatus));
7686
7687 if ((InputBufferLength != 0) || (OutputBufferLength != 0)) {
7688 ASSERT(ARGUMENT_PRESENT(Buffer));
7689 }
7690 else {
7691 ASSERT(!ARGUMENT_PRESENT(Buffer));
7692 }
7693 #endif
7694
7695 //
7696 // Begin by allocating the IRP for this request. Do not charge quota to
7697 // the current process for this IRP.
7698 //
7699
7700 irp = IoAllocateIrp(TargetDeviceObject->StackSize, FALSE);
7701 if (!irp) {
7702 (*IoStatus).Information = 0;
7703 (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES;
7704 return;
7705 }
7706
7707 //
7708 // Get a pointer to the stack location of the first driver which will be
7709 // invoked. This is where the function codes and the parameters are set.
7710 //
7711
7712 irpSp = IoGetNextIrpStackLocation(irp);
7713
7714 //
7715 // Set the major function code based on the type of device I/O control
7716 // function the caller has specified.
7717 //
7718
7719 if (InternalDeviceIoControl) {
7720 irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
7721 } else {
7722 irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
7723 }
7724
7725 //
7726 // Copy the caller's parameters to the service-specific portion of the
7727 // IRP for those parameters that are the same for all four methods.
7728 //
7729
7730 irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
7731 irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
7732 irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
7733
7734 //
7735 // Get the method bits from the I/O control code to determine how the
7736 // buffers are to be passed to the driver.
7737 //
7738
7739 switch (method) {
7740 // case 0
7741 case METHOD_BUFFERED: {
7742 if ((InputBufferLength != 0) || (OutputBufferLength != 0)) {
7743
7744 irp->AssociatedIrp.SystemBuffer =
7745 ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
7746 max(InputBufferLength, OutputBufferLength),
7747 CLASS_TAG_DEVICE_CONTROL
7748 );
7749
7750 if (irp->AssociatedIrp.SystemBuffer == NULL) {
7751 IoFreeIrp(irp);
7752 (*IoStatus).Information = 0;
7753 (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES;
7754 return;
7755 }
7756
7757 if (InputBufferLength != 0) {
7758 RtlCopyMemory(irp->AssociatedIrp.SystemBuffer,
7759 Buffer,
7760 InputBufferLength);
7761 }
7762 } // end of buffering
7763
7764 irp->UserBuffer = Buffer;
7765 break;
7766 }
7767
7768 // case 1, case 2
7769 case METHOD_IN_DIRECT:
7770 case METHOD_OUT_DIRECT: {
7771
7772
7773 if (InputBufferLength != 0) {
7774 irp->AssociatedIrp.SystemBuffer = Buffer;
7775 }
7776
7777 if (OutputBufferLength != 0) {
7778
7779 irp->MdlAddress = IoAllocateMdl(Buffer,
7780 OutputBufferLength,
7781 FALSE, FALSE,
7782 (PIRP) NULL);
7783
7784 if (irp->MdlAddress == NULL) {
7785 IoFreeIrp(irp);
7786 (*IoStatus).Information = 0;
7787 (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES;
7788 return;
7789 }
7790
7791 if (method == METHOD_IN_DIRECT) {
7792 MmProbeAndLockPages(irp->MdlAddress,
7793 KernelMode,
7794 IoReadAccess);
7795 } else if (method == METHOD_OUT_DIRECT) {
7796 MmProbeAndLockPages(irp->MdlAddress,
7797 KernelMode,
7798 IoWriteAccess);
7799 } else {
7800 ASSERT(!"If other methods reach here, code is out of date");
7801 }
7802 }
7803 break;
7804 }
7805
7806 // case 3
7807 case METHOD_NEITHER: {
7808
7809 ASSERT(!"This routine does not support METHOD_NEITHER ioctls");
7810 IoStatus->Information = 0;
7811 IoStatus->Status = STATUS_NOT_SUPPORTED;
7812 return;
7813 break;
7814 }
7815 } // end of switch(method)
7816
7817 irp->Tail.Overlay.Thread = PsGetCurrentThread();
7818
7819 //
7820 // send the irp synchronously
7821 //
7822
7823 ClassSendIrpSynchronous(TargetDeviceObject, irp);
7824
7825 //
7826 // copy the iostatus block for the caller
7827 //
7828
7829 *IoStatus = irp->IoStatus;
7830
7831 //
7832 // free any allocated resources
7833 //
7834
7835 switch (method) {
7836 case METHOD_BUFFERED: {
7837
7838 ASSERT(irp->UserBuffer == Buffer);
7839
7840 //
7841 // first copy the buffered result, if any
7842 // Note that there are no security implications in
7843 // not checking for success since only drivers can
7844 // call into this routine anyways...
7845 //
7846
7847 if (OutputBufferLength != 0) {
7848 RtlCopyMemory(Buffer, // irp->UserBuffer
7849 irp->AssociatedIrp.SystemBuffer,
7850 OutputBufferLength
7851 );
7852 }
7853
7854 //
7855 // then free the memory allocated to buffer the io
7856 //
7857
7858 if ((InputBufferLength !=0) || (OutputBufferLength != 0)) {
7859 ExFreePool(irp->AssociatedIrp.SystemBuffer);
7860 irp->AssociatedIrp.SystemBuffer = NULL;
7861 }
7862 break;
7863 }
7864
7865 case METHOD_IN_DIRECT:
7866 case METHOD_OUT_DIRECT: {
7867
7868 //
7869 // we alloc a mdl if there is an output buffer specified
7870 // free it here after unlocking the pages
7871 //
7872
7873 if (OutputBufferLength != 0) {
7874 ASSERT(irp->MdlAddress != NULL);
7875 MmUnlockPages(irp->MdlAddress);
7876 IoFreeMdl(irp->MdlAddress);
7877 irp->MdlAddress = (PMDL) NULL;
7878 }
7879 break;
7880 }
7881
7882 case METHOD_NEITHER: {
7883 ASSERT(!"Code is out of date");
7884 break;
7885 }
7886 }
7887
7888 //
7889 // we always have allocated an irp. free it here.
7890 //
7891
7892 IoFreeIrp(irp);
7893 irp = (PIRP) NULL;
7894
7895 //
7896 // return the io status block's status to the caller
7897 //
7898
7899 return;
7900 } // end ClassSendDeviceIoControlSynchronous()
7901
7902 /*++////////////////////////////////////////////////////////////////////////////
7903
7904 ClassForwardIrpSynchronous()
7905
7906 Routine Description:
7907
7908 Forwards a given irp to the next lower device object.
7909
7910 Arguments:
7911
7912 CommonExtension - the common class extension
7913
7914 Irp - the request to forward down the stack
7915
7916 Return Value:
7917
7918 --*/
7919 NTSTATUS
7920 NTAPI
7921 ClassForwardIrpSynchronous(
7922 IN PCOMMON_DEVICE_EXTENSION CommonExtension,
7923 IN PIRP Irp
7924 )
7925 {
7926 IoCopyCurrentIrpStackLocationToNext(Irp);
7927 return ClassSendIrpSynchronous(CommonExtension->LowerDeviceObject, Irp);
7928 } // end ClassForwardIrpSynchronous()
7929
7930 /*++////////////////////////////////////////////////////////////////////////////
7931
7932 ClassSendIrpSynchronous()
7933
7934 Routine Description:
7935
7936 This routine sends the given irp to the given device object, and waits for
7937 it to complete. On debug versions, will print out a debug message and
7938 optionally assert for "lost" irps based upon classpnp's globals
7939
7940 Arguments:
7941
7942 TargetDeviceObject - the device object to handle this irp
7943
7944 Irp - the request to be sent
7945
7946 Return Value:
7947
7948 --*/
7949 NTSTATUS
7950 NTAPI
7951 ClassSendIrpSynchronous(
7952 IN PDEVICE_OBJECT TargetDeviceObject,
7953 IN PIRP Irp
7954 )
7955 {
7956 KEVENT event;
7957 NTSTATUS status;
7958
7959 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
7960 ASSERT(TargetDeviceObject != NULL);
7961 ASSERT(Irp != NULL);
7962 ASSERT(Irp->StackCount >= TargetDeviceObject->StackSize);
7963
7964 //
7965 // ISSUE-2000/02/20-henrygab What if APCs are disabled?
7966 // May need to enter critical section before IoCallDriver()
7967 // until the event is hit?
7968 //
7969
7970 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
7971 IoSetCompletionRoutine(Irp, ClassSignalCompletion, &event,
7972 TRUE, TRUE, TRUE);
7973
7974 status = IoCallDriver(TargetDeviceObject, Irp);
7975
7976 if (status == STATUS_PENDING) {
7977
7978 #if DBG
7979 LARGE_INTEGER timeout;
7980
7981 timeout.QuadPart = (LONGLONG)(-1 * 10 * 1000 * (LONGLONG)1000 *
7982 ClasspnpGlobals.SecondsToWaitForIrps);
7983
7984 do {
7985 status = KeWaitForSingleObject(&event,
7986 Executive,
7987 KernelMode,
7988 FALSE,
7989 &timeout);
7990
7991
7992 if (status == STATUS_TIMEOUT) {
7993
7994 //
7995 // This DebugPrint should almost always be investigated by the
7996 // party who sent the irp and/or the current owner of the irp.
7997 // Synchronous Irps should not take this long (currently 30
7998 // seconds) without good reason. This points to a potentially
7999 // serious problem in the underlying device stack.
8000 //
8001
8002 DebugPrint((0, "ClassSendIrpSynchronous: (%p) irp %p did not "
8003 "complete within %x seconds\n",
8004 TargetDeviceObject, Irp,
8005 ClasspnpGlobals.SecondsToWaitForIrps
8006 ));
8007
8008 if (ClasspnpGlobals.BreakOnLostIrps != 0) {
8009 ASSERT(!" - Irp failed to complete within 30 seconds - ");
8010 }
8011 }
8012
8013
8014 } while (status==STATUS_TIMEOUT);
8015 #else
8016 KeWaitForSingleObject(&event,
8017 Executive,
8018 KernelMode,
8019 FALSE,
8020 NULL);
8021 #endif
8022
8023 status = Irp->IoStatus.Status;
8024 }
8025
8026 return status;
8027 } // end ClassSendIrpSynchronous()
8028
8029 /*++////////////////////////////////////////////////////////////////////////////
8030
8031 ClassGetVpb()
8032
8033 Routine Description:
8034
8035 This routine returns the current VPB (Volume Parameter Block) for the
8036 given device object.
8037 The Vpb field is only visible in the ntddk.h (not the wdm.h) definition
8038 of DEVICE_OBJECT; hence this exported function.
8039
8040 Arguments:
8041
8042 DeviceObject - the device to get the VPB for
8043
8044 Return Value:
8045
8046 the VPB, or NULL if none.
8047
8048 --*/
8049 PVPB
8050 NTAPI
8051 ClassGetVpb(
8052 IN PDEVICE_OBJECT DeviceObject
8053 )
8054 {
8055 return DeviceObject->Vpb;
8056 } // end ClassGetVpb()
8057
8058 /*++
8059
8060 ISSUE-2000/02/20-henrygab Not documented ClasspAllocateReleaseRequest
8061
8062 --*/
8063 NTSTATUS
8064 NTAPI
8065 ClasspAllocateReleaseRequest(
8066 IN PDEVICE_OBJECT Fdo
8067 )
8068 {
8069 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
8070 //PIO_STACK_LOCATION irpStack;
8071
8072 KeInitializeSpinLock(&(fdoExtension->ReleaseQueueSpinLock));
8073
8074 fdoExtension->ReleaseQueueNeeded = FALSE;
8075 fdoExtension->ReleaseQueueInProgress = FALSE;
8076 fdoExtension->ReleaseQueueIrpFromPool = FALSE;
8077
8078 //
8079 // The class driver is responsible for allocating a properly sized irp,
8080 // or ClassReleaseQueue will attempt to do it on the first error.
8081 //
8082
8083 fdoExtension->ReleaseQueueIrp = NULL;
8084
8085 //
8086 // Write length to SRB.
8087 //
8088
8089 fdoExtension->ReleaseQueueSrb.Length = sizeof(SCSI_REQUEST_BLOCK);
8090
8091 return STATUS_SUCCESS;
8092 } // end ClasspAllocateReleaseRequest()
8093
8094 /*++
8095
8096 ISSUE-2000/02/20-henrygab Not documented ClasspFreeReleaseRequest
8097
8098 --*/
8099 VOID
8100 NTAPI
8101 ClasspFreeReleaseRequest(
8102 IN PDEVICE_OBJECT Fdo
8103 )
8104 {
8105 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
8106 //KIRQL oldIrql;
8107
8108 ASSERT(fdoExtension->CommonExtension.IsRemoved != NO_REMOVE);
8109
8110 //
8111 // free anything the driver allocated
8112 //
8113
8114 if (fdoExtension->ReleaseQueueIrp) {
8115 if (fdoExtension->ReleaseQueueIrpFromPool) {
8116 ExFreePool(fdoExtension->ReleaseQueueIrp);
8117 } else {
8118 IoFreeIrp(fdoExtension->ReleaseQueueIrp);
8119 }
8120 fdoExtension->ReleaseQueueIrp = NULL;
8121 }
8122
8123 //
8124 // free anything that we allocated
8125 //
8126
8127 if ((fdoExtension->PrivateFdoData) &&
8128 (fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated)) {
8129
8130 ExFreePool(fdoExtension->PrivateFdoData->ReleaseQueueIrp);
8131 fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated = FALSE;
8132 fdoExtension->PrivateFdoData->ReleaseQueueIrp = NULL;
8133 }
8134
8135 return;
8136 } // end ClasspFreeReleaseRequest()
8137
8138 /*++////////////////////////////////////////////////////////////////////////////
8139
8140 ClassReleaseQueue()
8141
8142 Routine Description:
8143
8144 This routine issues an internal device control command
8145 to the port driver to release a frozen queue. The call
8146 is issued asynchronously as ClassReleaseQueue will be invoked
8147 from the IO completion DPC (and will have no context to
8148 wait for a synchronous call to complete).
8149
8150 This routine must be called with the remove lock held.
8151
8152 Arguments:
8153
8154 Fdo - The functional device object for the device with the frozen queue.
8155
8156 Return Value:
8157
8158 None.
8159
8160 --*/
8161 VOID
8162 NTAPI
8163 ClassReleaseQueue(
8164 IN PDEVICE_OBJECT Fdo
8165 )
8166 {
8167 ClasspReleaseQueue(Fdo, NULL);
8168 return;
8169 } // end ClassReleaseQueue()
8170
8171 /*++////////////////////////////////////////////////////////////////////////////
8172
8173 ClasspAllocateReleaseQueueIrp()
8174
8175 Routine Description:
8176
8177 This routine allocates the release queue irp held in classpnp's private
8178 extension. This was added to allow no-memory conditions to be more
8179 survivable.
8180
8181 Return Value:
8182
8183 NT_SUCCESS value.
8184
8185 Notes:
8186
8187 Does not grab the spinlock. Should only be called from StartDevice()
8188 routine. May be called elsewhere for poorly-behaved drivers that cause
8189 the queue to lockup before the device is started. This should *never*
8190 occur, since it's illegal to send a request to a non-started PDO. This
8191 condition is checked for in ClasspReleaseQueue().
8192
8193 --*/
8194 NTSTATUS
8195 NTAPI
8196 ClasspAllocateReleaseQueueIrp(
8197 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
8198 )
8199 {
8200 //KIRQL oldIrql;
8201 UCHAR lowerStackSize;
8202
8203 //
8204 // do an initial check w/o the spinlock
8205 //
8206
8207 if (FdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) {
8208 return STATUS_SUCCESS;
8209 }
8210
8211
8212 lowerStackSize = FdoExtension->CommonExtension.LowerDeviceObject->StackSize;
8213
8214 //
8215 // don't allocate one if one is in progress! this means whoever called
8216 // this routine didn't check if one was in progress.
8217 //
8218
8219 ASSERT(!(FdoExtension->ReleaseQueueInProgress));
8220
8221 FdoExtension->PrivateFdoData->ReleaseQueueIrp =
8222 ExAllocatePoolWithTag(NonPagedPool,
8223 IoSizeOfIrp(lowerStackSize),
8224 CLASS_TAG_RELEASE_QUEUE
8225 );
8226
8227 if (FdoExtension->PrivateFdoData->ReleaseQueueIrp == NULL) {
8228 DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for "
8229 "release queue irp\n"));
8230 return STATUS_INSUFFICIENT_RESOURCES;
8231 }
8232 IoInitializeIrp(FdoExtension->PrivateFdoData->ReleaseQueueIrp,
8233 IoSizeOfIrp(lowerStackSize),
8234 lowerStackSize);
8235 FdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated = TRUE;
8236
8237 return STATUS_SUCCESS;
8238 }
8239
8240 /*++////////////////////////////////////////////////////////////////////////////
8241
8242 ClasspReleaseQueue()
8243
8244 Routine Description:
8245
8246 This routine issues an internal device control command
8247 to the port driver to release a frozen queue. The call
8248 is issued asynchronously as ClassReleaseQueue will be invoked
8249 from the IO completion DPC (and will have no context to
8250 wait for a synchronous call to complete).
8251
8252 This routine must be called with the remove lock held.
8253
8254 Arguments:
8255
8256 Fdo - The functional device object for the device with the frozen queue.
8257
8258 ReleaseQueueIrp - If this irp is supplied then the test to determine whether
8259 a release queue request is in progress will be ignored.
8260 The irp provided must be the IRP originally allocated
8261 for release queue requests (so this parameter can only
8262 really be provided by the release queue completion
8263 routine.)
8264
8265 Return Value:
8266
8267 None.
8268
8269 --*/
8270 VOID
8271 NTAPI
8272 ClasspReleaseQueue(
8273 IN PDEVICE_OBJECT Fdo,
8274 IN PIRP ReleaseQueueIrp OPTIONAL
8275 )
8276 {
8277 PIO_STACK_LOCATION irpStack;
8278 PIRP irp;
8279 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
8280 PDEVICE_OBJECT lowerDevice;
8281 PSCSI_REQUEST_BLOCK srb;
8282 KIRQL currentIrql;
8283
8284 lowerDevice = fdoExtension->CommonExtension.LowerDeviceObject;
8285
8286 //
8287 // we raise irql seperately so we're not swapped out or suspended
8288 // while holding the release queue irp in this routine. this lets
8289 // us release the spin lock before lowering irql.
8290 //
8291
8292 KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
8293
8294 KeAcquireSpinLockAtDpcLevel(&(fdoExtension->ReleaseQueueSpinLock));
8295
8296 //
8297 // make sure that if they passed us an irp, it matches our allocated irp.
8298 //
8299
8300 ASSERT((ReleaseQueueIrp == NULL) ||
8301 (ReleaseQueueIrp == fdoExtension->PrivateFdoData->ReleaseQueueIrp));
8302
8303 //
8304 // ASSERT that we've already allocated this. (should not occur)
8305 // try to allocate it anyways, then finally bugcheck if
8306 // there's still no memory...
8307 //
8308
8309 ASSERT(fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated);
8310 if (!fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) {
8311 ClasspAllocateReleaseQueueIrp(fdoExtension);
8312 }
8313 if (!fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) {
8314 KeBugCheckEx(SCSI_DISK_DRIVER_INTERNAL, 0x12, (ULONG_PTR)Fdo, 0x0, 0x0);
8315 }
8316
8317 if ((fdoExtension->ReleaseQueueInProgress) && (ReleaseQueueIrp == NULL)) {
8318
8319 //
8320 // Someone is already using the irp - just set the flag to indicate that
8321 // we need to release the queue again.
8322 //
8323
8324 fdoExtension->ReleaseQueueNeeded = TRUE;
8325 KeReleaseSpinLockFromDpcLevel(&(fdoExtension->ReleaseQueueSpinLock));
8326 KeLowerIrql(currentIrql);
8327 return;
8328
8329 }
8330
8331 //
8332 // Mark that there is a release queue in progress and drop the spinlock.
8333 //
8334
8335 fdoExtension->ReleaseQueueInProgress = TRUE;
8336 if (ReleaseQueueIrp) {
8337 irp = ReleaseQueueIrp;
8338 } else {
8339 irp = fdoExtension->PrivateFdoData->ReleaseQueueIrp;
8340 }
8341 srb = &(fdoExtension->ReleaseQueueSrb);
8342
8343 KeReleaseSpinLockFromDpcLevel(&(fdoExtension->ReleaseQueueSpinLock));
8344
8345 ASSERT(irp != NULL);
8346
8347 irpStack = IoGetNextIrpStackLocation(irp);
8348
8349 irpStack->MajorFunction = IRP_MJ_SCSI;
8350
8351 srb->OriginalRequest = irp;
8352
8353 //
8354 // Store the SRB address in next stack for port driver.
8355 //
8356
8357 irpStack->Parameters.Scsi.Srb = srb;
8358
8359 //
8360 // If this device is removable then flush the queue. This will also
8361 // release it.
8362 //
8363
8364 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
8365 srb->Function = SRB_FUNCTION_FLUSH_QUEUE;
8366 }
8367 else {
8368 srb->Function = SRB_FUNCTION_RELEASE_QUEUE;
8369 }
8370
8371 ClassAcquireRemoveLock(Fdo, irp);
8372
8373 IoSetCompletionRoutine(irp,
8374 ClassReleaseQueueCompletion,
8375 Fdo,
8376 TRUE,
8377 TRUE,
8378 TRUE);
8379
8380 IoCallDriver(lowerDevice, irp);
8381
8382 KeLowerIrql(currentIrql);
8383
8384 return;
8385
8386 } // end ClassReleaseQueue()
8387
8388 /*++////////////////////////////////////////////////////////////////////////////
8389
8390 ClassReleaseQueueCompletion()
8391
8392 Routine Description:
8393
8394 This routine is called when an asynchronous I/O request
8395 which was issused by the class driver completes. Examples of such requests
8396 are release queue or START UNIT. This routine releases the queue if
8397 necessary. It then frees the context and the IRP.
8398
8399 Arguments:
8400
8401 DeviceObject - The device object for the logical unit; however since this
8402 is the top stack location the value is NULL.
8403
8404 Irp - Supplies a pointer to the Irp to be processed.
8405
8406 Context - Supplies the context to be used to process this request.
8407
8408 Return Value:
8409
8410 None.
8411
8412 --*/
8413 NTSTATUS
8414 NTAPI
8415 ClassReleaseQueueCompletion(
8416 PDEVICE_OBJECT DeviceObject,
8417 PIRP Irp,
8418 PVOID Context
8419 )
8420 {
8421 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
8422 KIRQL oldIrql;
8423
8424 BOOLEAN releaseQueueNeeded;
8425
8426 DeviceObject = Context;
8427
8428 fdoExtension = DeviceObject->DeviceExtension;
8429
8430 ClassReleaseRemoveLock(DeviceObject, Irp);
8431
8432 //
8433 // Grab the spinlock and clear the release queue in progress flag so others
8434 // can run. Save (and clear) the state of the release queue needed flag
8435 // so that we can issue a new release queue outside the spinlock.
8436 //
8437
8438 KeAcquireSpinLock(&(fdoExtension->ReleaseQueueSpinLock), &oldIrql);
8439
8440 releaseQueueNeeded = fdoExtension->ReleaseQueueNeeded;
8441
8442 fdoExtension->ReleaseQueueNeeded = FALSE;
8443 fdoExtension->ReleaseQueueInProgress = FALSE;
8444
8445 KeReleaseSpinLock(&(fdoExtension->ReleaseQueueSpinLock), oldIrql);
8446
8447 //
8448 // If we need a release queue then issue one now. Another processor may
8449 // have already started one in which case we'll try to issue this one after
8450 // it is done - but we should never recurse more than one deep.
8451 //
8452
8453 if(releaseQueueNeeded) {
8454 ClasspReleaseQueue(DeviceObject, Irp);
8455 }
8456
8457 //
8458 // Indicate the I/O system should stop processing the Irp completion.
8459 //
8460
8461 return STATUS_MORE_PROCESSING_REQUIRED;
8462
8463 } // ClassAsynchronousCompletion()
8464
8465 /*++////////////////////////////////////////////////////////////////////////////
8466
8467 ClassAcquireChildLock()
8468
8469 Routine Description:
8470
8471 This routine acquires the lock protecting children PDOs. It may be
8472 acquired recursively by the same thread, but must be release by the
8473 thread once for each acquisition.
8474
8475 Arguments:
8476
8477 FdoExtension - the device whose child list is protected.
8478
8479 Return Value:
8480
8481 None
8482
8483 --*/
8484 VOID
8485 NTAPI
8486 ClassAcquireChildLock(
8487 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
8488 )
8489 {
8490 PAGED_CODE();
8491
8492 if(FdoExtension->ChildLockOwner != KeGetCurrentThread()) {
8493 KeWaitForSingleObject(&FdoExtension->ChildLock,
8494 Executive, KernelMode,
8495 FALSE, NULL);
8496
8497 ASSERT(FdoExtension->ChildLockOwner == NULL);
8498 ASSERT(FdoExtension->ChildLockAcquisitionCount == 0);
8499
8500 FdoExtension->ChildLockOwner = KeGetCurrentThread();
8501 } else {
8502 ASSERT(FdoExtension->ChildLockAcquisitionCount != 0);
8503 }
8504
8505 FdoExtension->ChildLockAcquisitionCount++;
8506 return;
8507 }
8508
8509 /*++////////////////////////////////////////////////////////////////////////////
8510
8511 ClassReleaseChildLock() ISSUE-2000/02/18-henrygab - not documented
8512
8513 Routine Description:
8514
8515 This routine releases the lock protecting children PDOs. It must be
8516 called once for each time ClassAcquireChildLock was called.
8517
8518 Arguments:
8519
8520 FdoExtension - the device whose child list is protected
8521
8522 Return Value:
8523
8524 None.
8525
8526 --*/
8527 VOID
8528 NTAPI
8529 ClassReleaseChildLock(
8530 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
8531 )
8532 {
8533 ASSERT(FdoExtension->ChildLockOwner == KeGetCurrentThread());
8534 ASSERT(FdoExtension->ChildLockAcquisitionCount != 0);
8535
8536 FdoExtension->ChildLockAcquisitionCount -= 1;
8537
8538 if(FdoExtension->ChildLockAcquisitionCount == 0) {
8539 FdoExtension->ChildLockOwner = NULL;
8540 KeSetEvent(&FdoExtension->ChildLock, IO_NO_INCREMENT, FALSE);
8541 }
8542
8543 return;
8544 } // end ClassReleaseChildLock(
8545
8546 /*++////////////////////////////////////////////////////////////////////////////
8547
8548 ClassAddChild()
8549
8550 Routine Description:
8551
8552 This routine will insert a new child into the head of the child list.
8553
8554 Arguments:
8555
8556 Parent - the child's parent (contains the head of the list)
8557 Child - the child to be inserted.
8558 AcquireLock - whether the child lock should be acquired (TRUE) or whether
8559 it's already been acquired by or on behalf of the caller
8560 (FALSE).
8561
8562 Return Value:
8563
8564 None.
8565
8566 --*/
8567 VOID
8568 NTAPI
8569 ClassAddChild(
8570 IN PFUNCTIONAL_DEVICE_EXTENSION Parent,
8571 IN PPHYSICAL_DEVICE_EXTENSION Child,
8572 IN BOOLEAN AcquireLock
8573 )
8574 {
8575 if(AcquireLock) {
8576 ClassAcquireChildLock(Parent);
8577 }
8578
8579 #if DBG
8580 //
8581 // Make sure this child's not already in the list.
8582 //
8583 {
8584 PPHYSICAL_DEVICE_EXTENSION testChild;
8585
8586 for (testChild = Parent->CommonExtension.ChildList;
8587 testChild != NULL;
8588 testChild = testChild->CommonExtension.ChildList) {
8589
8590 ASSERT(testChild != Child);
8591 }
8592 }
8593 #endif
8594
8595 Child->CommonExtension.ChildList = Parent->CommonExtension.ChildList;
8596 Parent->CommonExtension.ChildList = Child;
8597
8598 if(AcquireLock) {
8599 ClassReleaseChildLock(Parent);
8600 }
8601 return;
8602 } // end ClassAddChild()
8603
8604 /*++////////////////////////////////////////////////////////////////////////////
8605
8606 ClassRemoveChild()
8607
8608 Routine Description:
8609
8610 This routine will remove a child from the child list.
8611
8612 Arguments:
8613
8614 Parent - the parent to be removed from.
8615
8616 Child - the child to be removed or NULL if the first child should be
8617 removed.
8618
8619 AcquireLock - whether the child lock should be acquired (TRUE) or whether
8620 it's already been acquired by or on behalf of the caller
8621 (FALSE).
8622
8623 Return Value:
8624
8625 A pointer to the child which was removed or NULL if no such child could
8626 be found in the list (or if Child was NULL but the list is empty).
8627
8628 --*/
8629 PPHYSICAL_DEVICE_EXTENSION
8630 NTAPI
8631 ClassRemoveChild(
8632 IN PFUNCTIONAL_DEVICE_EXTENSION Parent,
8633 IN PPHYSICAL_DEVICE_EXTENSION Child,
8634 IN BOOLEAN AcquireLock
8635 )
8636 {
8637 if(AcquireLock) {
8638 ClassAcquireChildLock(Parent);
8639 }
8640
8641 TRY {
8642 PCOMMON_DEVICE_EXTENSION previousChild = &Parent->CommonExtension;
8643
8644 //
8645 // If the list is empty then bail out now.
8646 //
8647
8648 if(Parent->CommonExtension.ChildList == NULL) {
8649 Child = NULL;
8650 LEAVE;
8651 }
8652
8653 //
8654 // If the caller specified a child then find the child object before
8655 // it. If none was specified then the FDO is the child object before
8656 // the one we want to remove.
8657 //
8658
8659 if(Child != NULL) {
8660
8661 //
8662 // Scan through the child list to find the entry which points to
8663 // this one.
8664 //
8665
8666 do {
8667 ASSERT(previousChild != &Child->CommonExtension);
8668
8669 if(previousChild->ChildList == Child) {
8670 break;
8671 }
8672
8673 previousChild = &previousChild->ChildList->CommonExtension;
8674 } while(previousChild != NULL);
8675
8676 if(previousChild == NULL) {
8677 Child = NULL;
8678 LEAVE;
8679 }
8680 }
8681
8682 //
8683 // Save the next child away then unlink it from the list.
8684 //
8685
8686 Child = previousChild->ChildList;
8687 previousChild->ChildList = Child->CommonExtension.ChildList;
8688 Child->CommonExtension.ChildList = NULL;
8689
8690 } FINALLY {
8691 if(AcquireLock) {
8692 ClassReleaseChildLock(Parent);
8693 }
8694 }
8695 return Child;
8696 } // end ClassRemoveChild()
8697
8698 /*++
8699
8700 ISSUE-2000/02/20-henrygab Not documented ClasspRetryRequestDpc
8701
8702 --*/
8703 VOID
8704 NTAPI
8705 ClasspRetryRequestDpc(
8706 IN PKDPC Dpc,
8707 IN PDEVICE_OBJECT DeviceObject,
8708 IN PVOID Arg1,
8709 IN PVOID Arg2
8710 )
8711 {
8712 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
8713 PCOMMON_DEVICE_EXTENSION commonExtension;
8714 PCLASS_PRIVATE_FDO_DATA fdoData;
8715 PCLASS_RETRY_INFO retryList;
8716 KIRQL irql;
8717
8718
8719 commonExtension = DeviceObject->DeviceExtension;
8720 ASSERT(commonExtension->IsFdo);
8721 fdoExtension = DeviceObject->DeviceExtension;
8722 fdoData = fdoExtension->PrivateFdoData;
8723
8724
8725 KeAcquireSpinLock(&fdoData->Retry.Lock, &irql);
8726 {
8727 LARGE_INTEGER now;
8728 KeQueryTickCount(&now);
8729
8730 //
8731 // if CurrentTick is less than now
8732 // fire another DPC
8733 // else
8734 // retry entire list
8735 // endif
8736 //
8737
8738 if (now.QuadPart < fdoData->Retry.Tick.QuadPart) {
8739
8740 ClasspRetryDpcTimer(fdoData);
8741 retryList = NULL;
8742
8743 } else {
8744
8745 retryList = fdoData->Retry.ListHead;
8746 fdoData->Retry.ListHead = NULL;
8747 fdoData->Retry.Delta.QuadPart = (LONGLONG)0;
8748 fdoData->Retry.Tick.QuadPart = (LONGLONG)0;
8749
8750 }
8751 }
8752 KeReleaseSpinLock(&fdoData->Retry.Lock, irql);
8753
8754 while (retryList != NULL) {
8755
8756 PIRP irp;
8757
8758 irp = CONTAINING_RECORD(retryList, IRP, Tail.Overlay.DriverContext[0]);
8759 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: -- %p\n", irp));
8760 retryList = retryList->Next;
8761 #if DBG
8762 irp->Tail.Overlay.DriverContext[0] = ULongToPtr(0xdddddddd); // invalidate data
8763 irp->Tail.Overlay.DriverContext[1] = ULongToPtr(0xdddddddd); // invalidate data
8764 irp->Tail.Overlay.DriverContext[2] = ULongToPtr(0xdddddddd); // invalidate data
8765 irp->Tail.Overlay.DriverContext[3] = ULongToPtr(0xdddddddd); // invalidate data
8766 #endif
8767
8768 IoCallDriver(commonExtension->LowerDeviceObject, irp);
8769
8770 }
8771 return;
8772
8773 } // end ClasspRetryRequestDpc()
8774
8775 /*++
8776
8777 ISSUE-2000/02/20-henrygab Not documented ClassRetryRequest
8778
8779 --*/
8780 VOID
8781 NTAPI
8782 ClassRetryRequest(
8783 IN PDEVICE_OBJECT SelfDeviceObject,
8784 IN PIRP Irp,
8785 IN LARGE_INTEGER TimeDelta100ns // in 100ns units
8786 )
8787 {
8788 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
8789 PCLASS_PRIVATE_FDO_DATA fdoData;
8790 PCLASS_RETRY_INFO retryInfo;
8791 //PCLASS_RETRY_INFO *previousNext;
8792 LARGE_INTEGER delta;
8793 KIRQL irql;
8794
8795 //
8796 // this checks we aren't destroying irps
8797 //
8798 ASSERT(sizeof(CLASS_RETRY_INFO) <= (4*sizeof(PVOID)));
8799
8800 fdoExtension = SelfDeviceObject->DeviceExtension;
8801 fdoData = fdoExtension->PrivateFdoData;
8802
8803 if (!fdoExtension->CommonExtension.IsFdo) {
8804
8805 //
8806 // this debug print/assertion should ALWAYS be investigated.
8807 // ClassRetryRequest can currently only be used by FDO's
8808 //
8809
8810 DebugPrint((ClassDebugError, "ClassRetryRequestEx: LOST IRP %p\n", Irp));
8811 ASSERT(!"ClassRetryRequestEx Called From PDO? LOST IRP");
8812 return;
8813
8814 }
8815
8816 if (TimeDelta100ns.QuadPart < 0) {
8817 ASSERT(!"ClassRetryRequest - must use positive delay");
8818 TimeDelta100ns.QuadPart *= -1;
8819 }
8820
8821 //
8822 // prepare what we can out of the loop
8823 //
8824
8825 retryInfo = (PCLASS_RETRY_INFO)(&Irp->Tail.Overlay.DriverContext[0]);
8826 RtlZeroMemory(retryInfo, sizeof(CLASS_RETRY_INFO));
8827
8828 delta.QuadPart = (TimeDelta100ns.QuadPart / fdoData->Retry.Granularity);
8829 if (TimeDelta100ns.QuadPart % fdoData->Retry.Granularity) {
8830 delta.QuadPart ++; // round up to next tick
8831 }
8832 if (delta.QuadPart == (LONGLONG)0) {
8833 delta.QuadPart = MINIMUM_RETRY_UNITS;
8834 }
8835
8836 //
8837 // now determine if we should fire another DPC or not
8838 //
8839
8840 KeAcquireSpinLock(&fdoData->Retry.Lock, &irql);
8841
8842 //
8843 // always add request to the list
8844 //
8845
8846 retryInfo->Next = fdoData->Retry.ListHead;
8847 fdoData->Retry.ListHead = retryInfo;
8848
8849 if (fdoData->Retry.Delta.QuadPart == (LONGLONG)0) {
8850
8851 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: +++ %p\n", Irp));
8852
8853 //
8854 // must be exactly one item on list
8855 //
8856
8857 ASSERT(fdoData->Retry.ListHead != NULL);
8858 ASSERT(fdoData->Retry.ListHead->Next == NULL);
8859
8860 //
8861 // if currentDelta is zero, always fire a DPC
8862 //
8863
8864 KeQueryTickCount(&fdoData->Retry.Tick);
8865 fdoData->Retry.Tick.QuadPart += delta.QuadPart;
8866 fdoData->Retry.Delta.QuadPart = delta.QuadPart;
8867 ClasspRetryDpcTimer(fdoData);
8868
8869 } else if (delta.QuadPart > fdoData->Retry.Delta.QuadPart) {
8870
8871 //
8872 // if delta is greater than the list's current delta,
8873 // increase the DPC handling time by difference
8874 // and update the delta to new larger value
8875 // allow the DPC to re-fire itself if needed
8876 //
8877
8878 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: ++ %p\n", Irp));
8879
8880 //
8881 // must be at least two items on list
8882 //
8883
8884 ASSERT(fdoData->Retry.ListHead != NULL);
8885 ASSERT(fdoData->Retry.ListHead->Next != NULL);
8886
8887 fdoData->Retry.Tick.QuadPart -= fdoData->Retry.Delta.QuadPart;
8888 fdoData->Retry.Tick.QuadPart += delta.QuadPart;
8889
8890 fdoData->Retry.Delta.QuadPart = delta.QuadPart;
8891
8892 } else {
8893
8894 //
8895 // just inserting it on the list was enough
8896 //
8897
8898 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: ++ %p\n", Irp));
8899
8900 }
8901
8902
8903 KeReleaseSpinLock(&fdoData->Retry.Lock, irql);
8904
8905
8906 } // end ClassRetryRequest()
8907
8908 /*++
8909
8910 ISSUE-2000/02/20-henrygab Not documented ClasspRetryDpcTimer
8911
8912 --*/
8913 VOID
8914 NTAPI
8915 ClasspRetryDpcTimer(
8916 IN PCLASS_PRIVATE_FDO_DATA FdoData
8917 )
8918 {
8919 LARGE_INTEGER fire;
8920
8921 ASSERT(FdoData->Retry.Tick.QuadPart != (LONGLONG)0);
8922 ASSERT(FdoData->Retry.ListHead != NULL); // never fire an empty list
8923
8924 //
8925 // fire == (CurrentTick - now) * (100ns per tick)
8926 //
8927 // NOTE: Overflow is nearly impossible and is ignored here
8928 //
8929
8930 KeQueryTickCount(&fire);
8931 fire.QuadPart = FdoData->Retry.Tick.QuadPart - fire.QuadPart;
8932 fire.QuadPart *= FdoData->Retry.Granularity;
8933
8934 //
8935 // fire is now multiples of 100ns until should fire the timer.
8936 // if timer should already have expired, or would fire too quickly,
8937 // fire it in some arbitrary number of ticks to prevent infinitely
8938 // recursing.
8939 //
8940
8941 if (fire.QuadPart < MINIMUM_RETRY_UNITS) {
8942 fire.QuadPart = MINIMUM_RETRY_UNITS;
8943 }
8944
8945 DebugPrint((ClassDebugDelayedRetry,
8946 "ClassRetry: ======= %I64x ticks\n",
8947 fire.QuadPart));
8948
8949 //
8950 // must use negative to specify relative time to fire
8951 //
8952
8953 fire.QuadPart = fire.QuadPart * ((LONGLONG)-1);
8954
8955 //
8956 // set the timer, since this is the first addition
8957 //
8958
8959 KeSetTimerEx(&FdoData->Retry.Timer, fire, 0, &FdoData->Retry.Dpc);
8960
8961 return;
8962 } // end ClasspRetryDpcTimer()
8963
8964 NTSTATUS
8965 NTAPI
8966 ClasspInitializeHotplugInfo(
8967 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
8968 )
8969 {
8970 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
8971 DEVICE_REMOVAL_POLICY deviceRemovalPolicy;
8972 NTSTATUS status;
8973 ULONG resultLength = 0;
8974 ULONG writeCacheOverride;
8975
8976 PAGED_CODE();
8977
8978 //
8979 // start with some default settings
8980 //
8981 RtlZeroMemory(&(fdoData->HotplugInfo), sizeof(STORAGE_HOTPLUG_INFO));
8982
8983 //
8984 // set the size (aka version)
8985 //
8986
8987 fdoData->HotplugInfo.Size = sizeof(STORAGE_HOTPLUG_INFO);
8988
8989 //
8990 // set if the device has removable media
8991 //
8992
8993 if (FdoExtension->DeviceDescriptor->RemovableMedia) {
8994 fdoData->HotplugInfo.MediaRemovable = TRUE;
8995 } else {
8996 fdoData->HotplugInfo.MediaRemovable = FALSE;
8997 }
8998
8999 //
9000 // this refers to devices which, for reasons not yet understood,
9001 // do not fail PREVENT_MEDIA_REMOVAL requests even though they
9002 // have no way to lock the media into the drive. this allows
9003 // the filesystems to turn off delayed-write caching for these
9004 // devices as well.
9005 //
9006
9007 if (TEST_FLAG(FdoExtension->PrivateFdoData->HackFlags,
9008 FDO_HACK_CANNOT_LOCK_MEDIA)) {
9009 fdoData->HotplugInfo.MediaHotplug = TRUE;
9010 } else {
9011 fdoData->HotplugInfo.MediaHotplug = FALSE;
9012 }
9013
9014
9015 //
9016 // Look into the registry to see if the user has chosen
9017 // to override the default setting for the removal policy
9018 //
9019
9020 RtlZeroMemory(&deviceRemovalPolicy, sizeof(DEVICE_REMOVAL_POLICY));
9021
9022 ClassGetDeviceParameter(FdoExtension,
9023 CLASSP_REG_SUBKEY_NAME,
9024 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME,
9025 (PULONG)&deviceRemovalPolicy);
9026
9027 if (deviceRemovalPolicy == 0)
9028 {
9029 //
9030 // Query the default removal policy from the kernel
9031 //
9032
9033 status = IoGetDeviceProperty(FdoExtension->LowerPdo,
9034 DevicePropertyRemovalPolicy,
9035 sizeof(DEVICE_REMOVAL_POLICY),
9036 (PVOID)&deviceRemovalPolicy,
9037 &resultLength);
9038 if (!NT_SUCCESS(status))
9039 {
9040 return status;
9041 }
9042
9043 if (resultLength != sizeof(DEVICE_REMOVAL_POLICY))
9044 {
9045 return STATUS_UNSUCCESSFUL;
9046 }
9047 }
9048
9049 //
9050 // use this info to set the DeviceHotplug setting
9051 // don't rely on DeviceCapabilities, since it can't properly
9052 // determine device relations, etc. let the kernel figure this
9053 // stuff out instead.
9054 //
9055
9056 if (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval) {
9057 fdoData->HotplugInfo.DeviceHotplug = TRUE;
9058 } else {
9059 fdoData->HotplugInfo.DeviceHotplug = FALSE;
9060 }
9061
9062 //
9063 // this refers to the *filesystem* caching, but has to be included
9064 // here since it's a per-device setting. this may change to be
9065 // stored by the system in the future.
9066 //
9067
9068 writeCacheOverride = FALSE;
9069 ClassGetDeviceParameter(FdoExtension,
9070 CLASSP_REG_SUBKEY_NAME,
9071 CLASSP_REG_WRITE_CACHE_VALUE_NAME,
9072 &writeCacheOverride);
9073
9074 if (writeCacheOverride) {
9075 fdoData->HotplugInfo.WriteCacheEnableOverride = TRUE;
9076 } else {
9077 fdoData->HotplugInfo.WriteCacheEnableOverride = FALSE;
9078 }
9079
9080 return STATUS_SUCCESS;
9081 }
9082
9083 VOID
9084 NTAPI
9085 ClasspScanForClassHacks(
9086 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
9087 IN ULONG_PTR Data
9088 )
9089 {
9090 PAGED_CODE();
9091
9092 //
9093 // remove invalid flags and save
9094 //
9095
9096 CLEAR_FLAG(Data, FDO_HACK_INVALID_FLAGS);
9097 SET_FLAG(FdoExtension->PrivateFdoData->HackFlags, Data);
9098 return;
9099 }
9100
9101 VOID
9102 NTAPI
9103 ClasspScanForSpecialInRegistry(
9104 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
9105 )
9106 {
9107 HANDLE deviceParameterHandle; // device instance key
9108 HANDLE classParameterHandle; // classpnp subkey
9109 OBJECT_ATTRIBUTES objectAttributes;
9110 UNICODE_STRING subkeyName;
9111 NTSTATUS status;
9112
9113 //
9114 // seeded in the ENUM tree by ClassInstaller
9115 //
9116 ULONG deviceHacks;
9117 RTL_QUERY_REGISTRY_TABLE queryTable[2]; // null terminated array
9118
9119 PAGED_CODE();
9120
9121 deviceParameterHandle = NULL;
9122 classParameterHandle = NULL;
9123 deviceHacks = 0;
9124
9125 status = IoOpenDeviceRegistryKey(FdoExtension->LowerPdo,
9126 PLUGPLAY_REGKEY_DEVICE,
9127 KEY_WRITE,
9128 &deviceParameterHandle
9129 );
9130
9131 if (!NT_SUCCESS(status)) {
9132 goto cleanupScanForSpecial;
9133 }
9134
9135 RtlInitUnicodeString(&subkeyName, CLASSP_REG_SUBKEY_NAME);
9136 InitializeObjectAttributes(&objectAttributes,
9137 &subkeyName,
9138 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
9139 deviceParameterHandle,
9140 NULL
9141 );
9142
9143 status = ZwOpenKey( &classParameterHandle,
9144 KEY_READ,
9145 &objectAttributes
9146 );
9147
9148 if (!NT_SUCCESS(status)) {
9149 goto cleanupScanForSpecial;
9150 }
9151
9152 //
9153 // Zero out the memory
9154 //
9155
9156 RtlZeroMemory(&queryTable[0], 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
9157
9158 //
9159 // Setup the structure to read
9160 //
9161
9162 queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
9163 queryTable[0].Name = CLASSP_REG_HACK_VALUE_NAME;
9164 queryTable[0].EntryContext = &deviceHacks;
9165 queryTable[0].DefaultType = REG_DWORD;
9166 queryTable[0].DefaultData = &deviceHacks;
9167 queryTable[0].DefaultLength = 0;
9168
9169 //
9170 // read values
9171 //
9172
9173 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
9174 (PWSTR)classParameterHandle,
9175 &queryTable[0],
9176 NULL,
9177 NULL
9178 );
9179 if (!NT_SUCCESS(status)) {
9180 goto cleanupScanForSpecial;
9181 }
9182
9183 //
9184 // remove unknown values and save...
9185 //
9186
9187 KdPrintEx((DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL,
9188 "Classpnp => ScanForSpecial: HackFlags %#08x\n",
9189 deviceHacks));
9190
9191 CLEAR_FLAG(deviceHacks, FDO_HACK_INVALID_FLAGS);
9192 SET_FLAG(FdoExtension->PrivateFdoData->HackFlags, deviceHacks);
9193
9194
9195 cleanupScanForSpecial:
9196
9197 if (deviceParameterHandle) {
9198 ZwClose(deviceParameterHandle);
9199 }
9200
9201 if (classParameterHandle) {
9202 ZwClose(classParameterHandle);
9203 }
9204
9205 //
9206 // we should modify the system hive to include another key for us to grab
9207 // settings from. in this case: Classpnp\HackFlags
9208 //
9209 // the use of a DWORD value for the HackFlags allows 32 hacks w/o
9210 // significant use of the registry, and also reduces OEM exposure.
9211 //
9212 // definition of bit flags:
9213 // 0x00000001 -- Device succeeds PREVENT_MEDIUM_REMOVAL, but
9214 // cannot actually prevent removal.
9215 // 0x00000002 -- Device hard-hangs or times out for GESN requests.
9216 // 0xfffffffc -- Currently reserved, may be used later.
9217 //
9218
9219 return;
9220 }