3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 SCSI class driver routines
24 #define CLASS_INIT_GUID 0
28 ULONG BreakOnClose
= 0;
30 PCSTR LockTypeStrings
[] = {
37 PFILE_OBJECT_EXTENSION
40 IN PCOMMON_DEVICE_EXTENSION CommonExtension
,
41 IN PFILE_OBJECT FileObject
46 ClasspCleanupDisableMcn(
47 IN PFILE_OBJECT_EXTENSION FsContext
51 #pragma alloc_text(PAGE, ClassCreateClose)
52 #pragma alloc_text(PAGE, ClasspCreateClose)
53 #pragma alloc_text(PAGE, ClasspCleanupProtectedLocks)
54 #pragma alloc_text(PAGE, ClasspEjectionControl)
55 #pragma alloc_text(PAGE, ClasspCleanupDisableMcn)
56 #pragma alloc_text(PAGE, ClasspGetFsContext)
62 IN PDEVICE_OBJECT DeviceObject
,
70 SCSI class driver create and close routine. This is called by the I/O system
71 when the device is opened or closed.
75 DriverObject - Pointer to driver object created by system.
81 Device-specific drivers return value or STATUS_SUCCESS.
86 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
93 // If we're getting a close request then we know the device object hasn't
94 // been completely destroyed. Let the driver cleanup if necessary.
97 removeState
= ClassAcquireRemoveLock(DeviceObject
, Irp
);
100 // Invoke the device-specific routine, if one exists. Otherwise complete
104 if((removeState
== NO_REMOVE
) ||
105 IS_CLEANUP_REQUEST(IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
)) {
107 status
= ClasspCreateClose(DeviceObject
, Irp
);
109 if((NT_SUCCESS(status
)) &&
110 (commonExtension
->DevInfo
->ClassCreateClose
)) {
112 return commonExtension
->DevInfo
->ClassCreateClose(DeviceObject
, Irp
);
116 status
= STATUS_DEVICE_DOES_NOT_EXIST
;
119 Irp
->IoStatus
.Status
= status
;
120 ClassReleaseRemoveLock(DeviceObject
, Irp
);
121 ClassCompleteRequest(DeviceObject
, Irp
, IO_NO_INCREMENT
);
128 IN PDEVICE_OBJECT DeviceObject
,
135 This routine will handle create/close operations for a given classpnp
136 device if the class driver doesn't supply it's own handler. If there
137 is a file object supplied for our driver (if it's a FO_DIRECT_DEVICE_OPEN
138 file object) then it will initialize a file extension on create or destroy
139 the extension on a close.
143 DeviceObject - the device object being opened or closed.
145 Irp - the create/close irp
153 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
154 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
156 PFILE_OBJECT fileObject
= irpStack
->FileObject
;
158 NTSTATUS status
= STATUS_SUCCESS
;
164 // ISSUE-2000/3/28-henrygab - if lower stack fails create/close, we end up
165 // in an inconsistent state. re-write to verify all args and allocate all
166 // required resources, then pass the irp down, then complete the
167 // transaction. this is because we also cannot forward the irp, then fail
168 // it after it has succeeded a lower-level driver.
171 if(irpStack
->MajorFunction
== IRP_MJ_CREATE
) {
173 PIO_SECURITY_CONTEXT securityContext
=
174 irpStack
->Parameters
.Create
.SecurityContext
;
176 "ClasspCREATEClose: create received for device %p\n",
179 "ClasspCREATEClose: desired access %lx\n",
180 securityContext
->DesiredAccess
));
182 "ClasspCREATEClose: file object %lx\n",
183 irpStack
->FileObject
));
185 ASSERT(BreakOnClose
== FALSE
);
187 if(irpStack
->FileObject
!= NULL
) {
189 PFILE_OBJECT_EXTENSION fsContext
;
192 // Allocate our own file object extension for this device object.
195 status
= AllocateDictionaryEntry(
196 &commonExtension
->FileObjectDictionary
,
197 (ULONG_PTR
)irpStack
->FileObject
,
198 sizeof(FILE_OBJECT_EXTENSION
),
199 CLASS_TAG_FILE_OBJECT_EXTENSION
,
200 (PVOID
*)&fsContext
);
202 if(NT_SUCCESS(status
)) {
204 RtlZeroMemory(fsContext
,
205 sizeof(FILE_OBJECT_EXTENSION
));
207 fsContext
->FileObject
= irpStack
->FileObject
;
208 fsContext
->DeviceObject
= DeviceObject
;
209 } else if (status
== STATUS_OBJECT_NAME_COLLISION
) {
210 status
= STATUS_SUCCESS
;
217 "ClasspCreateCLOSE: close received for device %p\n",
220 "ClasspCreateCLOSE: file object %p\n",
223 if(irpStack
->FileObject
!= NULL
) {
225 PFILE_OBJECT_EXTENSION fsContext
=
226 ClasspGetFsContext(commonExtension
, irpStack
->FileObject
);
229 "ClasspCreateCLOSE: file extension %p\n",
232 if(fsContext
!= NULL
) {
235 "ClasspCreateCLOSE: extension is ours - "
237 ASSERT(BreakOnClose
== FALSE
);
239 ClasspCleanupProtectedLocks(fsContext
);
241 ClasspCleanupDisableMcn(fsContext
);
243 FreeDictionaryEntry(&(commonExtension
->FileObjectDictionary
),
250 // Notify the lower levels about the create or close operation - give them
251 // a chance to cleanup too.
255 "ClasspCreateClose: %s for devobj %p\n",
256 (NT_SUCCESS(status
) ? "Success" : "FAILED"),
260 if(NT_SUCCESS(status
)) {
265 // Set up the event to wait on
268 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
270 IoCopyCurrentIrpStackLocationToNext(Irp
);
271 IoSetCompletionRoutine( Irp
, ClassSignalCompletion
, &event
,
274 status
= IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
276 if(status
== STATUS_PENDING
) {
277 KeWaitForSingleObject(&event
,
282 status
= Irp
->IoStatus
.Status
;
285 if (!NT_SUCCESS(status
)) {
286 DebugPrint((ClassDebugError
,
287 "ClasspCreateClose: Lower driver failed, but we "
288 "succeeded. This is a problem, lock counts will be "
289 "out of sync between levels.\n"));
300 ClasspCleanupProtectedLocks(
301 IN PFILE_OBJECT_EXTENSION FsContext
304 PCOMMON_DEVICE_EXTENSION commonExtension
=
305 FsContext
->DeviceObject
->DeviceExtension
;
307 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
308 commonExtension
->PartitionZeroExtension
;
310 ULONG newDeviceLockCount
= 1;
315 "ClasspCleanupProtectedLocks called for %p\n",
316 FsContext
->DeviceObject
));
318 "ClasspCleanupProtectedLocks - FsContext %p is locked "
319 "%d times\n", FsContext
, FsContext
->LockCount
));
321 ASSERT(BreakOnClose
== FALSE
);
324 // Synchronize with ejection and ejection control requests.
327 KeEnterCriticalRegion();
328 KeWaitForSingleObject(&(fdoExtension
->EjectSynchronizationEvent
),
335 // For each secure lock on this handle decrement the secured lock count
336 // for the FDO. Keep track of the new value.
339 if(FsContext
->LockCount
!= 0) {
343 InterlockedDecrement((PLONG
)&FsContext
->LockCount
);
346 InterlockedDecrement(&fdoExtension
->ProtectedLockCount
);
348 } while(FsContext
->LockCount
!= 0);
351 // If the new lock count has been dropped to zero then issue a lock
352 // command to the device.
356 "ClasspCleanupProtectedLocks: FDO secured lock count = %d "
358 fdoExtension
->ProtectedLockCount
,
359 fdoExtension
->LockCount
));
361 if((newDeviceLockCount
== 0) && (fdoExtension
->LockCount
== 0)) {
363 SCSI_REQUEST_BLOCK srb
;
368 "ClasspCleanupProtectedLocks: FDO lock count dropped "
371 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
372 cdb
= (PCDB
) &(srb
.Cdb
);
376 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
379 // TRUE - prevent media removal.
380 // FALSE - allow media removal.
383 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
386 // Set timeout value.
389 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
390 status
= ClassSendSrbSynchronous(fdoExtension
->DeviceObject
,
397 "ClasspCleanupProtectedLocks: unlock request to drive "
398 "returned status %lx\n", status
));
402 KeSetEvent(&fdoExtension
->EjectSynchronizationEvent
,
405 KeLeaveCriticalRegion();
411 ClasspCleanupDisableMcn(
412 IN PFILE_OBJECT_EXTENSION FsContext
415 PCOMMON_DEVICE_EXTENSION commonExtension
=
416 FsContext
->DeviceObject
->DeviceExtension
;
418 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
=
419 commonExtension
->PartitionZeroExtension
;
423 DebugPrint((ClassDebugTrace
,
424 "ClasspCleanupDisableMcn called for %p\n",
425 FsContext
->DeviceObject
));
426 DebugPrint((ClassDebugTrace
,
427 "ClasspCleanupDisableMcn - FsContext %p is disabled "
428 "%d times\n", FsContext
, FsContext
->McnDisableCount
));
431 // For each secure lock on this handle decrement the secured lock count
432 // for the FDO. Keep track of the new value.
435 while(FsContext
->McnDisableCount
!= 0) {
436 FsContext
->McnDisableCount
--;
437 ClassEnableMediaChangeDetection(fdoExtension
);
445 * BUGBUG REMOVE this old function implementation as soon as the
446 * boottime pagefile problems with the new one (below)
451 ClasspEjectionControl(
452 IN PDEVICE_OBJECT Fdo
,
454 IN MEDIA_LOCK_TYPE LockType
,
458 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
= Fdo
->DeviceExtension
;
459 PCOMMON_DEVICE_EXTENSION commonExtension
=
460 (PCOMMON_DEVICE_EXTENSION
) FdoExtension
;
462 PFILE_OBJECT_EXTENSION fsContext
= NULL
;
464 volatile PSCSI_REQUEST_BLOCK srb
= NULL
;
465 BOOLEAN countChanged
= FALSE
;
470 // Interlock with ejection and secure lock cleanup code. This is a
471 // user request so we can allow the stack to get swapped out while we
472 // wait for synchronization.
475 status
= KeWaitForSingleObject(
476 &(FdoExtension
->EjectSynchronizationEvent
),
482 ASSERT(status
== STATUS_SUCCESS
);
485 "ClasspEjectionControl: "
486 "Received request for %s lock type\n",
487 LockTypeStrings
[LockType
]
493 srb
= ClasspAllocateSrb(FdoExtension
);
496 status
= STATUS_INSUFFICIENT_RESOURCES
;
500 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
502 cdb
= (PCDB
) srb
->Cdb
;
505 // Determine if this is a "secured" request.
508 if(LockType
== SecureMediaLock
) {
510 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
511 PFILE_OBJECT fileObject
= irpStack
->FileObject
;
514 // Make sure that the file object we are supplied has a
515 // proper FsContext before we try doing a secured lock.
518 if(fileObject
!= NULL
) {
519 fsContext
= ClasspGetFsContext(commonExtension
, fileObject
);
522 if (fsContext
== NULL
) {
525 // This handle isn't setup correctly. We can't let the
529 status
= STATUS_INVALID_PARAMETER
;
537 // This is a lock command. Reissue the command in case bus or
538 // device was reset and the lock was cleared.
539 // note: may need to decrement count if actual lock operation
545 case SimpleMediaLock
: {
546 FdoExtension
->LockCount
++;
551 case SecureMediaLock
: {
552 fsContext
->LockCount
++;
553 FdoExtension
->ProtectedLockCount
++;
558 case InternalMediaLock
: {
559 FdoExtension
->InternalLockCount
++;
568 // This is an unlock command. If it's a secured one then make sure
569 // the caller has a lock outstanding or return an error.
570 // note: may need to re-increment the count if actual unlock
571 // operation fails....
576 case SimpleMediaLock
: {
577 if(FdoExtension
->LockCount
!= 0) {
578 FdoExtension
->LockCount
--;
584 case SecureMediaLock
: {
585 if(fsContext
->LockCount
== 0) {
586 status
= STATUS_INVALID_DEVICE_STATE
;
589 fsContext
->LockCount
--;
590 FdoExtension
->ProtectedLockCount
--;
595 case InternalMediaLock
: {
596 ASSERT(FdoExtension
->InternalLockCount
!= 0);
597 FdoExtension
->InternalLockCount
--;
604 // We only send an unlock command to the drive if both the
605 // secured and unsecured lock counts have dropped to zero.
608 if((FdoExtension
->ProtectedLockCount
!= 0) ||
609 (FdoExtension
->InternalLockCount
!= 0) ||
610 (FdoExtension
->LockCount
!= 0)) {
612 status
= STATUS_SUCCESS
;
617 status
= STATUS_SUCCESS
;
618 if (TEST_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
621 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
624 // TRUE - prevent media removal.
625 // FALSE - allow media removal.
628 cdb
->MEDIA_REMOVAL
.Prevent
= Lock
;
631 // Set timeout value.
634 srb
->TimeOutValue
= FdoExtension
->TimeOutValue
;
637 // The actual lock operation on the device isn't so important
638 // as the internal lock counts. Ignore failures.
641 status
= ClassSendSrbSynchronous(FdoExtension
->DeviceObject
,
650 if (!NT_SUCCESS(status
)) {
652 "ClasspEjectionControl: FAILED status %x -- "
653 "reverting lock counts\n", status
));
658 // have to revert to previous counts if the
659 // lock/unlock operation actually failed.
666 case SimpleMediaLock
: {
667 FdoExtension
->LockCount
--;
671 case SecureMediaLock
: {
672 fsContext
->LockCount
--;
673 FdoExtension
->ProtectedLockCount
--;
677 case InternalMediaLock
: {
678 FdoExtension
->InternalLockCount
--;
687 case SimpleMediaLock
: {
688 FdoExtension
->LockCount
++;
692 case SecureMediaLock
: {
693 fsContext
->LockCount
++;
694 FdoExtension
->ProtectedLockCount
++;
698 case InternalMediaLock
: {
699 FdoExtension
->InternalLockCount
++;
710 "ClasspEjectionControl: Succeeded\n"));
715 "ClasspEjectionControl: "
716 "Current Counts: Internal: %x Secure: %x Simple: %x\n",
717 FdoExtension
->InternalLockCount
,
718 FdoExtension
->ProtectedLockCount
,
719 FdoExtension
->LockCount
722 KeSetEvent(&(FdoExtension
->EjectSynchronizationEvent
),
726 ClassFreeOrReuseSrb(FdoExtension
, srb
);
737 * This is a new implementation of the function that doesn't thrash memory
738 * or depend on the srbLookasideList.
739 * HOWEVER, it seems to cause pagefile initialization to fail during boot
740 * for some reason. Need to resolve this before switching to this function.
744 ClasspEjectionControl(
745 IN PDEVICE_OBJECT Fdo
,
747 IN MEDIA_LOCK_TYPE LockType
,
751 PFUNCTIONAL_DEVICE_EXTENSION fdoExt
= Fdo
->DeviceExtension
;
752 PFILE_OBJECT_EXTENSION fsContext
;
753 BOOLEAN fileHandleOk
= TRUE
;
754 BOOLEAN countChanged
= FALSE
;
759 status
= KeWaitForSingleObject(
760 &fdoExt
->EjectSynchronizationEvent
,
765 ASSERT(status
== STATUS_SUCCESS
);
768 * If this is a "secured" request, we have to make sure
769 * that the file handle is valid.
771 if (LockType
== SecureMediaLock
){
772 PIO_STACK_LOCATION thisSp
= IoGetCurrentIrpStackLocation(Irp
);
775 * Make sure that the file object we are supplied has a
776 * proper FsContext before we try doing a secured lock.
778 if (thisSp
->FileObject
){
779 PCOMMON_DEVICE_EXTENSION commonExt
= (PCOMMON_DEVICE_EXTENSION
)fdoExt
;
780 fsContext
= ClasspGetFsContext(commonExt
, thisSp
->FileObject
);
788 fileHandleOk
= FALSE
;
795 * Adjust the lock counts and make sure they make sense.
797 status
= STATUS_SUCCESS
;
800 case SimpleMediaLock
:
804 case SecureMediaLock
:
805 fsContext
->LockCount
++;
806 fdoExt
->ProtectedLockCount
++;
809 case InternalMediaLock
:
810 fdoExt
->InternalLockCount
++;
817 * This is an unlock command. If it's a secured one then make sure
818 * the caller has a lock outstanding or return an error.
821 case SimpleMediaLock
:
822 if (fdoExt
->LockCount
> 0){
827 ASSERT(fdoExt
->LockCount
> 0);
828 status
= STATUS_INTERNAL_ERROR
;
831 case SecureMediaLock
:
832 if (fsContext
->LockCount
> 0){
833 ASSERT(fdoExt
->ProtectedLockCount
> 0);
834 fsContext
->LockCount
--;
835 fdoExt
->ProtectedLockCount
--;
839 ASSERT(fsContext
->LockCount
> 0);
840 status
= STATUS_INVALID_DEVICE_STATE
;
843 case InternalMediaLock
:
844 ASSERT(fdoExt
->InternalLockCount
> 0);
845 fdoExt
->InternalLockCount
--;
851 if (NT_SUCCESS(status
)){
853 * We only send an unlock command to the drive if
854 * all the lock counts have dropped to zero.
857 (fdoExt
->ProtectedLockCount
||
858 fdoExt
->InternalLockCount
||
862 * The lock count is still positive, so don't unlock yet.
864 status
= STATUS_SUCCESS
;
866 else if (!TEST_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
868 * The device isn't removable media. don't send a cmd.
870 status
= STATUS_SUCCESS
;
873 TRANSFER_PACKET
*pkt
;
875 pkt
= DequeueFreeTransferPacket(Fdo
, TRUE
);
880 * Store the number of packets servicing the irp (one)
881 * inside the original IRP. It will be used to counted down
882 * to zero when the packet completes.
883 * Initialize the original IRP's status to success.
884 * If the packet fails, we will set it to the error status.
886 Irp
->Tail
.Overlay
.DriverContext
[0] = LongToPtr(1);
887 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
890 * Set this up as a SYNCHRONOUS transfer, submit it,
891 * and wait for the packet to complete. The result
892 * status will be written to the original irp.
894 KeInitializeEvent(&event
, SynchronizationEvent
, FALSE
);
895 SetupEjectionTransferPacket(pkt
, Lock
, &event
, Irp
);
896 SubmitTransferPacket(pkt
);
897 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
898 status
= Irp
->IoStatus
.Status
;
901 status
= STATUS_INSUFFICIENT_RESOURCES
;
907 status
= STATUS_INVALID_PARAMETER
;
910 if (!NT_SUCCESS(status
) && countChanged
) {
913 // have to revert to previous counts if the
914 // lock/unlock operation actually failed.
921 case SimpleMediaLock
: {
922 FdoExtension
->LockCount
--;
926 case SecureMediaLock
: {
927 fsContext
->LockCount
--;
928 FdoExtension
->ProtectedLockCount
--;
932 case InternalMediaLock
: {
933 FdoExtension
->InternalLockCount
--;
942 case SimpleMediaLock
: {
943 FdoExtension
->LockCount
++;
947 case SecureMediaLock
: {
948 fsContext
->LockCount
++;
949 FdoExtension
->ProtectedLockCount
++;
953 case InternalMediaLock
: {
954 FdoExtension
->InternalLockCount
++;
963 KeSetEvent(&fdoExt
->EjectSynchronizationEvent
, IO_NO_INCREMENT
, FALSE
);
969 PFILE_OBJECT_EXTENSION
972 IN PCOMMON_DEVICE_EXTENSION CommonExtension
,
973 IN PFILE_OBJECT FileObject
977 return GetDictionaryEntry(&(CommonExtension
->FileObjectDictionary
),
978 (ULONG_PTR
)FileObject
);