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