3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 SCSI class driver routines
26 ULONG BreakOnClose
= 0;
28 PCSTR LockTypeStrings
[] = {
35 PFILE_OBJECT_EXTENSION
38 IN PCOMMON_DEVICE_EXTENSION CommonExtension
,
39 IN PFILE_OBJECT FileObject
44 ClasspCleanupDisableMcn(
45 IN PFILE_OBJECT_EXTENSION FsContext
49 #pragma alloc_text(PAGE, ClassCreateClose)
50 #pragma alloc_text(PAGE, ClasspCreateClose)
51 #pragma alloc_text(PAGE, ClasspCleanupProtectedLocks)
52 #pragma alloc_text(PAGE, ClasspEjectionControl)
53 #pragma alloc_text(PAGE, ClasspCleanupDisableMcn)
54 #pragma alloc_text(PAGE, ClasspGetFsContext)
60 IN PDEVICE_OBJECT DeviceObject
,
68 SCSI class driver create and close routine. This is called by the I/O system
69 when the device is opened or closed.
73 DriverObject - Pointer to driver object created by system.
79 Device-specific drivers return value or STATUS_SUCCESS.
84 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
91 // If we're getting a close request then we know the device object hasn't
92 // been completely destroyed. Let the driver cleanup if necessary.
95 removeState
= ClassAcquireRemoveLock(DeviceObject
, Irp
);
98 // Invoke the device-specific routine, if one exists. Otherwise complete
102 if((removeState
== NO_REMOVE
) ||
103 IS_CLEANUP_REQUEST(IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
)) {
105 status
= ClasspCreateClose(DeviceObject
, Irp
);
107 if((NT_SUCCESS(status
)) &&
108 (commonExtension
->DevInfo
->ClassCreateClose
)) {
110 return commonExtension
->DevInfo
->ClassCreateClose(DeviceObject
, Irp
);
114 status
= STATUS_DEVICE_DOES_NOT_EXIST
;
117 Irp
->IoStatus
.Status
= status
;
118 ClassReleaseRemoveLock(DeviceObject
, Irp
);
119 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
126 IN PDEVICE_OBJECT DeviceObject
,
133 This routine will handle create/close operations for a given classpnp
134 device if the class driver doesn't supply it's own handler. If there
135 is a file object supplied for our driver (if it's a FO_DIRECT_DEVICE_OPEN
136 file object) then it will initialize a file extension on create or destroy
137 the extension on a close.
141 DeviceObject - the device object being opened or closed.
143 Irp - the create/close irp
151 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
152 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
154 PFILE_OBJECT fileObject
= irpStack
->FileObject
;
156 NTSTATUS status
= STATUS_SUCCESS
;
162 // ISSUE-2000/3/28-henrygab - if lower stack fails create/close, we end up
163 // in an inconsistent state. re-write to verify all args and allocate all
164 // required resources, then pass the irp down, then complete the
165 // transaction. this is because we also cannot forward the irp, then fail
166 // it after it has succeeded a lower-level driver.
169 if(irpStack
->MajorFunction
== IRP_MJ_CREATE
) {
171 PIO_SECURITY_CONTEXT securityContext
=
172 irpStack
->Parameters
.Create
.SecurityContext
;
174 "ClasspCREATEClose: create received for device %p\n",
177 "ClasspCREATEClose: desired access %lx\n",
178 securityContext
->DesiredAccess
));
180 "ClasspCREATEClose: file object %lx\n",
181 irpStack
->FileObject
));
183 ASSERT(BreakOnClose
== FALSE
);
185 if(irpStack
->FileObject
!= NULL
) {
187 PFILE_OBJECT_EXTENSION fsContext
;
190 // Allocate our own file object extension for this device object.
193 status
= AllocateDictionaryEntry(
194 &commonExtension
->FileObjectDictionary
,
195 (ULONG_PTR
)irpStack
->FileObject
,
196 sizeof(FILE_OBJECT_EXTENSION
),
197 CLASS_TAG_FILE_OBJECT_EXTENSION
,
198 (PVOID
*)&fsContext
);
200 if(NT_SUCCESS(status
)) {
202 RtlZeroMemory(fsContext
,
203 sizeof(FILE_OBJECT_EXTENSION
));
205 fsContext
->FileObject
= irpStack
->FileObject
;
206 fsContext
->DeviceObject
= DeviceObject
;
207 } else if (status
== STATUS_OBJECT_NAME_COLLISION
) {
208 status
= STATUS_SUCCESS
;
215 "ClasspCreateCLOSE: close received for device %p\n",
218 "ClasspCreateCLOSE: file object %p\n",
221 if(irpStack
->FileObject
!= NULL
) {
223 PFILE_OBJECT_EXTENSION fsContext
=
224 ClasspGetFsContext(commonExtension
, irpStack
->FileObject
);
227 "ClasspCreateCLOSE: file extension %p\n",
230 if(fsContext
!= NULL
) {
233 "ClasspCreateCLOSE: extension is ours - "
235 ASSERT(BreakOnClose
== FALSE
);
237 ClasspCleanupProtectedLocks(fsContext
);
239 ClasspCleanupDisableMcn(fsContext
);
241 FreeDictionaryEntry(&(commonExtension
->FileObjectDictionary
),
248 // Notify the lower levels about the create or close operation - give them
249 // a chance to cleanup too.
253 "ClasspCreateClose: %s for devobj %p\n",
254 (NT_SUCCESS(status
) ? "Success" : "FAILED"),
258 if(NT_SUCCESS(status
)) {
263 // Set up the event to wait on
266 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
268 IoCopyCurrentIrpStackLocationToNext(Irp
);
269 IoSetCompletionRoutine( Irp
, ClassSignalCompletion
, &event
,
272 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
274 if(status
== STATUS_PENDING
) {
275 KeWaitForSingleObject(&event
,
280 status
= Irp
->IoStatus
.Status
;
283 if (!NT_SUCCESS(status
)) {
284 DebugPrint((ClassDebugError
,
285 "ClasspCreateClose: Lower driver failed, but we "
286 "succeeded. This is a problem, lock counts will be "
287 "out of sync between levels.\n"));
298 ClasspCleanupProtectedLocks(
299 IN PFILE_OBJECT_EXTENSION FsContext
302 PCOMMON_DEVICE_EXTENSION commonExtension
=
303 FsContext
->DeviceObject
->DeviceExtension
;
305 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
306 commonExtension
->PartitionZeroExtension
;
308 ULONG newDeviceLockCount
= 1;
313 "ClasspCleanupProtectedLocks called for %p\n",
314 FsContext
->DeviceObject
));
316 "ClasspCleanupProtectedLocks - FsContext %p is locked "
317 "%d times\n", FsContext
, FsContext
->LockCount
));
319 ASSERT(BreakOnClose
== FALSE
);
322 // Synchronize with ejection and ejection control requests.
325 KeEnterCriticalRegion();
326 KeWaitForSingleObject(&(fdoExtension
->EjectSynchronizationEvent
),
333 // For each secure lock on this handle decrement the secured lock count
334 // for the FDO. Keep track of the new value.
337 if(FsContext
->LockCount
!= 0) {
341 InterlockedDecrement((PLONG
)&FsContext
->LockCount
);
344 InterlockedDecrement(&fdoExtension
->ProtectedLockCount
);
346 } while(FsContext
->LockCount
!= 0);
349 // If the new lock count has been dropped to zero then issue a lock
350 // command to the device.
354 "ClasspCleanupProtectedLocks: FDO secured lock count = %d "
356 fdoExtension
->ProtectedLockCount
,
357 fdoExtension
->LockCount
));
359 if((newDeviceLockCount
== 0) && (fdoExtension
->LockCount
== 0)) {
361 SCSI_REQUEST_BLOCK srb
;
366 "ClasspCleanupProtectedLocks: FDO lock count dropped "
369 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
370 cdb
= (PCDB
) &(srb
.Cdb
);
374 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
377 // TRUE - prevent media removal.
378 // FALSE - allow media removal.
381 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
384 // Set timeout value.
387 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
388 status
= ClassSendSrbSynchronous(fdoExtension
->DeviceObject
,
395 "ClasspCleanupProtectedLocks: unlock request to drive "
396 "returned status %lx\n", status
));
400 KeSetEvent(&fdoExtension
->EjectSynchronizationEvent
,
403 KeLeaveCriticalRegion();
409 ClasspCleanupDisableMcn(
410 IN PFILE_OBJECT_EXTENSION FsContext
413 PCOMMON_DEVICE_EXTENSION commonExtension
=
414 FsContext
->DeviceObject
->DeviceExtension
;
416 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
417 commonExtension
->PartitionZeroExtension
;
421 DebugPrint((ClassDebugTrace
,
422 "ClasspCleanupDisableMcn called for %p\n",
423 FsContext
->DeviceObject
));
424 DebugPrint((ClassDebugTrace
,
425 "ClasspCleanupDisableMcn - FsContext %p is disabled "
426 "%d times\n", FsContext
, FsContext
->McnDisableCount
));
429 // For each secure lock on this handle decrement the secured lock count
430 // for the FDO. Keep track of the new value.
433 while(FsContext
->McnDisableCount
!= 0) {
434 FsContext
->McnDisableCount
--;
435 ClassEnableMediaChangeDetection(fdoExtension
);
443 * BUGBUG REMOVE this old function implementation as soon as the
444 * boottime pagefile problems with the new one (below)
449 ClasspEjectionControl(
450 IN PDEVICE_OBJECT Fdo
,
452 IN MEDIA_LOCK_TYPE LockType
,
456 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
= Fdo
->DeviceExtension
;
457 PCOMMON_DEVICE_EXTENSION commonExtension
=
458 (PCOMMON_DEVICE_EXTENSION
) FdoExtension
;
460 PFILE_OBJECT_EXTENSION fsContext
= NULL
;
462 volatile PSCSI_REQUEST_BLOCK srb
= NULL
;
463 BOOLEAN countChanged
= FALSE
;
468 // Interlock with ejection and secure lock cleanup code. This is a
469 // user request so we can allow the stack to get swapped out while we
470 // wait for synchronization.
473 status
= KeWaitForSingleObject(
474 &(FdoExtension
->EjectSynchronizationEvent
),
480 ASSERT(status
== STATUS_SUCCESS
);
483 "ClasspEjectionControl: "
484 "Received request for %s lock type\n",
485 LockTypeStrings
[LockType
]
491 srb
= ClasspAllocateSrb(FdoExtension
);
494 status
= STATUS_INSUFFICIENT_RESOURCES
;
498 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
500 cdb
= (PCDB
) srb
->Cdb
;
503 // Determine if this is a "secured" request.
506 if(LockType
== SecureMediaLock
) {
508 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
509 PFILE_OBJECT fileObject
= irpStack
->FileObject
;
512 // Make sure that the file object we are supplied has a
513 // proper FsContext before we try doing a secured lock.
516 if(fileObject
!= NULL
) {
517 fsContext
= ClasspGetFsContext(commonExtension
, fileObject
);
520 if (fsContext
== NULL
) {
523 // This handle isn't setup correctly. We can't let the
527 status
= STATUS_INVALID_PARAMETER
;
535 // This is a lock command. Reissue the command in case bus or
536 // device was reset and the lock was cleared.
537 // note: may need to decrement count if actual lock operation
543 case SimpleMediaLock
: {
544 FdoExtension
->LockCount
++;
549 case SecureMediaLock
: {
550 fsContext
->LockCount
++;
551 FdoExtension
->ProtectedLockCount
++;
556 case InternalMediaLock
: {
557 FdoExtension
->InternalLockCount
++;
566 // This is an unlock command. If it's a secured one then make sure
567 // the caller has a lock outstanding or return an error.
568 // note: may need to re-increment the count if actual unlock
569 // operation fails....
574 case SimpleMediaLock
: {
575 if(FdoExtension
->LockCount
!= 0) {
576 FdoExtension
->LockCount
--;
582 case SecureMediaLock
: {
583 if(fsContext
->LockCount
== 0) {
584 status
= STATUS_INVALID_DEVICE_STATE
;
587 fsContext
->LockCount
--;
588 FdoExtension
->ProtectedLockCount
--;
593 case InternalMediaLock
: {
594 ASSERT(FdoExtension
->InternalLockCount
!= 0);
595 FdoExtension
->InternalLockCount
--;
602 // We only send an unlock command to the drive if both the
603 // secured and unsecured lock counts have dropped to zero.
606 if((FdoExtension
->ProtectedLockCount
!= 0) ||
607 (FdoExtension
->InternalLockCount
!= 0) ||
608 (FdoExtension
->LockCount
!= 0)) {
610 status
= STATUS_SUCCESS
;
615 status
= STATUS_SUCCESS
;
616 if (TEST_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
619 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
622 // TRUE - prevent media removal.
623 // FALSE - allow media removal.
626 cdb
->MEDIA_REMOVAL
.Prevent
= Lock
;
629 // Set timeout value.
632 srb
->TimeOutValue
= FdoExtension
->TimeOutValue
;
635 // The actual lock operation on the device isn't so important
636 // as the internal lock counts. Ignore failures.
639 status
= ClassSendSrbSynchronous(FdoExtension
->DeviceObject
,
648 if (!NT_SUCCESS(status
)) {
650 "ClasspEjectionControl: FAILED status %x -- "
651 "reverting lock counts\n", status
));
656 // have to revert to previous counts if the
657 // lock/unlock operation actually failed.
664 case SimpleMediaLock
: {
665 FdoExtension
->LockCount
--;
669 case SecureMediaLock
: {
670 fsContext
->LockCount
--;
671 FdoExtension
->ProtectedLockCount
--;
675 case InternalMediaLock
: {
676 FdoExtension
->InternalLockCount
--;
685 case SimpleMediaLock
: {
686 FdoExtension
->LockCount
++;
690 case SecureMediaLock
: {
691 fsContext
->LockCount
++;
692 FdoExtension
->ProtectedLockCount
++;
696 case InternalMediaLock
: {
697 FdoExtension
->InternalLockCount
++;
708 "ClasspEjectionControl: Succeeded\n"));
713 "ClasspEjectionControl: "
714 "Current Counts: Internal: %x Secure: %x Simple: %x\n",
715 FdoExtension
->InternalLockCount
,
716 FdoExtension
->ProtectedLockCount
,
717 FdoExtension
->LockCount
720 KeSetEvent(&(FdoExtension
->EjectSynchronizationEvent
),
724 ClassFreeOrReuseSrb(FdoExtension
, srb
);
735 * This is a new implementation of the function that doesn't thrash memory
736 * or depend on the srbLookasideList.
737 * HOWEVER, it seems to cause pagefile initialization to fail during boot
738 * for some reason. Need to resolve this before switching to this function.
742 ClasspEjectionControl(
743 IN PDEVICE_OBJECT Fdo
,
745 IN MEDIA_LOCK_TYPE LockType
,
749 PFUNCTIONAL_DEVICE_EXTENSION fdoExt
= Fdo
->DeviceExtension
;
750 PFILE_OBJECT_EXTENSION fsContext
;
751 BOOLEAN fileHandleOk
= TRUE
;
752 BOOLEAN countChanged
= FALSE
;
757 status
= KeWaitForSingleObject(
758 &fdoExt
->EjectSynchronizationEvent
,
763 ASSERT(status
== STATUS_SUCCESS
);
766 * If this is a "secured" request, we have to make sure
767 * that the file handle is valid.
769 if (LockType
== SecureMediaLock
){
770 PIO_STACK_LOCATION thisSp
= IoGetCurrentIrpStackLocation(Irp
);
773 * Make sure that the file object we are supplied has a
774 * proper FsContext before we try doing a secured lock.
776 if (thisSp
->FileObject
){
777 PCOMMON_DEVICE_EXTENSION commonExt
= (PCOMMON_DEVICE_EXTENSION
)fdoExt
;
778 fsContext
= ClasspGetFsContext(commonExt
, thisSp
->FileObject
);
786 fileHandleOk
= FALSE
;
793 * Adjust the lock counts and make sure they make sense.
795 status
= STATUS_SUCCESS
;
798 case SimpleMediaLock
:
802 case SecureMediaLock
:
803 fsContext
->LockCount
++;
804 fdoExt
->ProtectedLockCount
++;
807 case InternalMediaLock
:
808 fdoExt
->InternalLockCount
++;
815 * This is an unlock command. If it's a secured one then make sure
816 * the caller has a lock outstanding or return an error.
819 case SimpleMediaLock
:
820 if (fdoExt
->LockCount
> 0){
825 ASSERT(fdoExt
->LockCount
> 0);
826 status
= STATUS_INTERNAL_ERROR
;
829 case SecureMediaLock
:
830 if (fsContext
->LockCount
> 0){
831 ASSERT(fdoExt
->ProtectedLockCount
> 0);
832 fsContext
->LockCount
--;
833 fdoExt
->ProtectedLockCount
--;
837 ASSERT(fsContext
->LockCount
> 0);
838 status
= STATUS_INVALID_DEVICE_STATE
;
841 case InternalMediaLock
:
842 ASSERT(fdoExt
->InternalLockCount
> 0);
843 fdoExt
->InternalLockCount
--;
849 if (NT_SUCCESS(status
)){
851 * We only send an unlock command to the drive if
852 * all the lock counts have dropped to zero.
855 (fdoExt
->ProtectedLockCount
||
856 fdoExt
->InternalLockCount
||
860 * The lock count is still positive, so don't unlock yet.
862 status
= STATUS_SUCCESS
;
864 else if (!TEST_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
866 * The device isn't removable media. don't send a cmd.
868 status
= STATUS_SUCCESS
;
871 TRANSFER_PACKET
*pkt
;
873 pkt
= DequeueFreeTransferPacket(Fdo
, TRUE
);
878 * Store the number of packets servicing the irp (one)
879 * inside the original IRP. It will be used to counted down
880 * to zero when the packet completes.
881 * Initialize the original IRP's status to success.
882 * If the packet fails, we will set it to the error status.
884 Irp
->Tail
.Overlay
.DriverContext
[0] = LongToPtr(1);
885 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
888 * Set this up as a SYNCHRONOUS transfer, submit it,
889 * and wait for the packet to complete. The result
890 * status will be written to the original irp.
892 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
893 SetupEjectionTransferPacket(pkt
, Lock
, &event
, Irp
);
894 SubmitTransferPacket(pkt
);
895 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
896 status
= Irp
->IoStatus
.Status
;
899 status
= STATUS_INSUFFICIENT_RESOURCES
;
905 status
= STATUS_INVALID_PARAMETER
;
908 if (!NT_SUCCESS(status
) && countChanged
) {
911 // have to revert to previous counts if the
912 // lock/unlock operation actually failed.
919 case SimpleMediaLock
: {
920 FdoExtension
->LockCount
--;
924 case SecureMediaLock
: {
925 fsContext
->LockCount
--;
926 FdoExtension
->ProtectedLockCount
--;
930 case InternalMediaLock
: {
931 FdoExtension
->InternalLockCount
--;
940 case SimpleMediaLock
: {
941 FdoExtension
->LockCount
++;
945 case SecureMediaLock
: {
946 fsContext
->LockCount
++;
947 FdoExtension
->ProtectedLockCount
++;
951 case InternalMediaLock
: {
952 FdoExtension
->InternalLockCount
++;
961 KeSetEvent(&fdoExt
->EjectSynchronizationEvent
, IO_NO_INCREMENT
, FALSE
);
967 PFILE_OBJECT_EXTENSION
970 IN PCOMMON_DEVICE_EXTENSION CommonExtension
,
971 IN PFILE_OBJECT FileObject
975 return GetDictionaryEntry(&(CommonExtension
->FileObjectDictionary
),
976 (ULONG_PTR
)FileObject
);