summaryrefslogtreecommitdiff
path: root/storage/class/classpnp/src/create.c
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /storage/class/classpnp/src/create.c
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'storage/class/classpnp/src/create.c')
-rw-r--r--storage/class/classpnp/src/create.c1018
1 files changed, 1018 insertions, 0 deletions
diff --git a/storage/class/classpnp/src/create.c b/storage/class/classpnp/src/create.c
new file mode 100644
index 00000000..f871ab26
--- /dev/null
+++ b/storage/class/classpnp/src/create.c
@@ -0,0 +1,1018 @@
+/*++
+
+Copyright (C) Microsoft Corporation, 1991 - 2010
+
+Module Name:
+
+ class.c
+
+Abstract:
+
+ SCSI class driver routines
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+
+Revision History:
+
+--*/
+
+#define CLASS_INIT_GUID 0
+#include "classp.h"
+#include "debug.h"
+
+#ifdef DEBUG_USE_WPP
+#include "create.tmh"
+#endif
+
+ULONG BreakOnClose = 0;
+
+const PCSZ LockTypeStrings[] = {
+ "Simple",
+ "Secure",
+ "Internal"
+};
+
+
+VOID
+ClasspCleanupDisableMcn(
+ IN PFILE_OBJECT_EXTENSION FsContext
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, ClassCreateClose)
+#pragma alloc_text(PAGE, ClasspCreateClose)
+#pragma alloc_text(PAGE, ClasspCleanupProtectedLocks)
+#pragma alloc_text(PAGE, ClasspEjectionControl)
+#pragma alloc_text(PAGE, ClasspCleanupDisableMcn)
+#pragma alloc_text(PAGE, ClassGetFsContext)
+#endif
+
+NTSTATUS
+ClassCreateClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ SCSI class driver create and close routine. This is called by the I/O system
+ when the device is opened or closed.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by system.
+
+ Irp - IRP involved.
+
+Return Value:
+
+ Device-specific drivers return value or STATUS_SUCCESS.
+
+--*/
+
+{
+ PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
+ ULONG removeState;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ //
+ // If we're getting a close request then we know the device object hasn't
+ // been completely destroyed. Let the driver cleanup if necessary.
+ //
+
+ removeState = ClassAcquireRemoveLock(DeviceObject, Irp);
+
+ //
+ // Invoke the device-specific routine, if one exists. Otherwise complete
+ // with SUCCESS
+ //
+
+ if((removeState == NO_REMOVE) ||
+ IS_CLEANUP_REQUEST(IoGetCurrentIrpStackLocation(Irp)->MajorFunction)) {
+
+ status = ClasspCreateClose(DeviceObject, Irp);
+
+ if((NT_SUCCESS(status)) &&
+ (commonExtension->DevInfo->ClassCreateClose)) {
+
+ return commonExtension->DevInfo->ClassCreateClose(DeviceObject, Irp);
+ }
+
+ } else {
+ status = STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ Irp->IoStatus.Status = status;
+ ClassReleaseRemoveLock(DeviceObject, Irp);
+ ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
+ return status;
+}
+
+
+NTSTATUS
+ClasspCreateClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ This routine will handle create/close operations for a given classpnp
+ device if the class driver doesn't supply it's own handler. If there
+ is a file object supplied for our driver (if it's a FO_DIRECT_DEVICE_OPEN
+ file object) then it will initialize a file extension on create or destroy
+ the extension on a close.
+
+Arguments:
+
+ DeviceObject - the device object being opened or closed.
+
+ Irp - the create/close irp
+
+Return Value:
+
+ status
+
+--*/
+{
+ PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ PFILE_OBJECT fileObject = irpStack->FileObject;
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+
+ //
+ // ISSUE-2000/3/28-henrygab - if lower stack fails create/close, we end up
+ // in an inconsistent state. re-write to verify all args and allocate all
+ // required resources, then pass the irp down, then complete the
+ // transaction. this is because we also cannot forward the irp, then fail
+ // it after it has succeeded a lower-level driver.
+ //
+
+ if(irpStack->MajorFunction == IRP_MJ_CREATE) {
+
+ PIO_SECURITY_CONTEXT securityContext =
+ irpStack->Parameters.Create.SecurityContext;
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCREATEClose: create received for device %p\n",
+ DeviceObject));
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCREATEClose: desired access %lx\n",
+ securityContext->DesiredAccess));
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCREATEClose: file object %p\n",
+ irpStack->FileObject));
+
+ NT_ASSERT(BreakOnClose == FALSE);
+
+ if(irpStack->FileObject != NULL) {
+
+ PFILE_OBJECT_EXTENSION fsContext;
+
+ //
+ // Allocate our own file object extension for this device object.
+ //
+
+ status = AllocateDictionaryEntry(
+ &commonExtension->FileObjectDictionary,
+ (ULONGLONG) irpStack->FileObject,
+ sizeof(FILE_OBJECT_EXTENSION),
+ CLASS_TAG_FILE_OBJECT_EXTENSION,
+ &fsContext);
+
+ if(NT_SUCCESS(status)) {
+
+ RtlZeroMemory(fsContext,
+ sizeof(FILE_OBJECT_EXTENSION));
+
+ fsContext->FileObject = irpStack->FileObject;
+ fsContext->DeviceObject = DeviceObject;
+ } else if (status == STATUS_OBJECT_NAME_COLLISION) {
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ } else {
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCreateCLOSE: close received for device %p\n",
+ DeviceObject));
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCreateCLOSE: file object %p\n",
+ fileObject));
+
+ if(irpStack->FileObject != NULL) {
+
+ PFILE_OBJECT_EXTENSION fsContext =
+ ClassGetFsContext(commonExtension, irpStack->FileObject);
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCreateCLOSE: file extension %p\n",
+ fsContext));
+
+ if(fsContext != NULL) {
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCreateCLOSE: extension is ours - "
+ "freeing\n"));
+ NT_ASSERT(BreakOnClose == FALSE);
+
+ ClasspCleanupProtectedLocks(fsContext);
+
+ ClasspCleanupDisableMcn(fsContext);
+
+ FreeDictionaryEntry(&(commonExtension->FileObjectDictionary),
+ fsContext);
+ }
+ }
+ }
+
+ //
+ // Notify the lower levels about the create or close operation - give them
+ // a chance to cleanup too.
+ //
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCreateClose: %s for devobj %p\n",
+ (NT_SUCCESS(status) ? "Success" : "FAILED"),
+ DeviceObject));
+
+
+ if(NT_SUCCESS(status)) {
+
+ KEVENT event;
+
+ //
+ // Set up the event to wait on
+ //
+
+ KeInitializeEvent(&event, SynchronizationEvent, FALSE);
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine( Irp, ClassSignalCompletion, &event,
+ TRUE, TRUE, TRUE);
+
+ status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
+
+ if(status == STATUS_PENDING) {
+ (VOID)KeWaitForSingleObject(&event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ status = Irp->IoStatus.Status;
+ }
+
+ if (!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT,
+ "ClasspCreateClose: Lower driver failed, but we "
+ "succeeded. This is a problem, lock counts will be "
+ "out of sync between levels.\n"));
+ }
+
+ }
+
+
+ return status;
+}
+
+
+VOID
+ClasspCleanupProtectedLocks(
+ IN PFILE_OBJECT_EXTENSION FsContext
+ )
+{
+ PCOMMON_DEVICE_EXTENSION commonExtension =
+ FsContext->DeviceObject->DeviceExtension;
+
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
+ commonExtension->PartitionZeroExtension;
+
+ ULONG newDeviceLockCount = 1;
+
+ PAGED_CODE();
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCleanupProtectedLocks called for %p\n",
+ FsContext->DeviceObject));
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCleanupProtectedLocks - FsContext %p is locked "
+ "%d times\n", FsContext, FsContext->LockCount));
+
+ NT_ASSERT(BreakOnClose == FALSE);
+
+ //
+ // Synchronize with ejection and ejection control requests.
+ //
+
+ KeEnterCriticalRegion();
+ (VOID)KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent),
+ UserRequest,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ //
+ // For each secure lock on this handle decrement the secured lock count
+ // for the FDO. Keep track of the new value.
+ //
+
+ if (FsContext->LockCount != 0) {
+
+ do {
+
+ InterlockedDecrement((volatile LONG *)&FsContext->LockCount);
+
+ newDeviceLockCount =
+ InterlockedDecrement(&fdoExtension->ProtectedLockCount);
+
+ } while (FsContext->LockCount > 0);
+
+ //
+ // If the new lock count has been dropped to zero then issue a lock
+ // command to the device.
+ //
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCleanupProtectedLocks: FDO secured lock count = %d "
+ "lock count = %d\n",
+ fdoExtension->ProtectedLockCount,
+ fdoExtension->LockCount));
+
+ if ((newDeviceLockCount == 0) && (fdoExtension->LockCount == 0)) {
+
+ SCSI_REQUEST_BLOCK srb = {0};
+ UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0};
+ PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer;
+ PCDB cdb = NULL;
+ NTSTATUS status;
+ PSCSI_REQUEST_BLOCK srbPtr;
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCleanupProtectedLocks: FDO lock count dropped "
+ "to zero\n"));
+
+ if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
+ #pragma prefast(suppress:26015, "InitializeStorageRequestBlock ensures buffer access is bounded")
+ status = InitializeStorageRequestBlock(srbEx,
+ STORAGE_ADDRESS_TYPE_BTL8,
+ sizeof(srbExBuffer),
+ 1,
+ SrbExDataTypeScsiCdb16);
+ if (NT_SUCCESS(status)) {
+ srbEx->TimeOutValue = fdoExtension->TimeOutValue;
+ SrbSetCdbLength(srbEx, 6);
+ cdb = SrbGetCdb(srbEx);
+ srbPtr = (PSCSI_REQUEST_BLOCK)srbEx;
+ } else {
+ //
+ // Should not happen. Revert to legacy SRB.
+ //
+ NT_ASSERT(FALSE);
+ srb.TimeOutValue = fdoExtension->TimeOutValue;
+ srb.CdbLength = 6;
+ cdb = (PCDB) &(srb.Cdb);
+ srbPtr = &srb;
+ }
+
+ } else {
+
+ srb.TimeOutValue = fdoExtension->TimeOutValue;
+ srb.CdbLength = 6;
+ cdb = (PCDB) &(srb.Cdb);
+ srbPtr = &srb;
+
+ }
+
+ cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
+
+ //
+ // TRUE - prevent media removal.
+ // FALSE - allow media removal.
+ //
+
+ cdb->MEDIA_REMOVAL.Prevent = FALSE;
+
+ status = ClassSendSrbSynchronous(fdoExtension->DeviceObject,
+ srbPtr,
+ NULL,
+ 0,
+ FALSE);
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT,
+ "ClasspCleanupProtectedLocks: unlock request to drive "
+ "returned status %lx\n", status));
+ }
+ }
+
+ KeSetEvent(&fdoExtension->EjectSynchronizationEvent,
+ IO_NO_INCREMENT,
+ FALSE);
+ KeLeaveCriticalRegion();
+ return;
+}
+
+
+VOID
+ClasspCleanupDisableMcn(
+ IN PFILE_OBJECT_EXTENSION FsContext
+ )
+{
+ PCOMMON_DEVICE_EXTENSION commonExtension =
+ FsContext->DeviceObject->DeviceExtension;
+
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
+ commonExtension->PartitionZeroExtension;
+
+ PAGED_CODE();
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
+ "ClasspCleanupDisableMcn called for %p\n",
+ FsContext->DeviceObject));
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
+ "ClasspCleanupDisableMcn - FsContext %p is disabled "
+ "%d times\n", FsContext, FsContext->McnDisableCount));
+
+ //
+ // For each secure lock on this handle decrement the secured lock count
+ // for the FDO. Keep track of the new value.
+ //
+
+ while(FsContext->McnDisableCount != 0) {
+ FsContext->McnDisableCount--;
+ ClassEnableMediaChangeDetection(fdoExtension);
+ }
+
+ return;
+}
+
+
+#if 1
+/*
+ * ISSUE: REMOVE this old function implementation as soon as the
+ * boottime pagefile problems with the new one (below)
+ * are resolved.
+ */
+NTSTATUS
+ClasspEjectionControl(
+ IN PDEVICE_OBJECT Fdo,
+ IN PIRP Irp,
+ IN MEDIA_LOCK_TYPE LockType,
+ IN BOOLEAN Lock
+ )
+{
+ PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = Fdo->DeviceExtension;
+ PCOMMON_DEVICE_EXTENSION commonExtension =
+ (PCOMMON_DEVICE_EXTENSION) FdoExtension;
+
+ PFILE_OBJECT_EXTENSION fsContext = NULL;
+ NTSTATUS status;
+ PSCSI_REQUEST_BLOCK srb = NULL;
+ BOOLEAN countChanged = FALSE;
+
+ PAGED_CODE();
+
+ /*
+ * Ensure that the user thread is not suspended while we are holding EjectSynchronizationEvent.
+ */
+ KeEnterCriticalRegion();
+
+ status = KeWaitForSingleObject(
+ &(FdoExtension->EjectSynchronizationEvent),
+ UserRequest,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ NT_ASSERT(status == STATUS_SUCCESS);
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
+ "ClasspEjectionControl: "
+ "Received request for %s lock type\n",
+ LockTypeStrings[LockType]
+ ));
+
+ try {
+ PCDB cdb = NULL;
+
+ //
+ // Determine if this is a "secured" request.
+ //
+
+ if (LockType == SecureMediaLock) {
+
+ PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
+ PFILE_OBJECT fileObject = irpStack->FileObject;
+
+ //
+ // Make sure that the file object we are supplied has a
+ // proper FsContext before we try doing a secured lock.
+ //
+
+ if (fileObject != NULL) {
+ fsContext = ClassGetFsContext(commonExtension, fileObject);
+ }
+
+ if (fsContext == NULL) {
+
+ //
+ // This handle isn't setup correctly. We can't let the
+ // operation go.
+ //
+
+ status = STATUS_INVALID_PARAMETER;
+ leave;
+ }
+ }
+
+ if (Lock) {
+
+ //
+ // This is a lock command. Reissue the command in case bus or
+ // device was reset and the lock was cleared.
+ // note: may need to decrement count if actual lock operation
+ // failed....
+ //
+
+ switch (LockType) {
+
+ case SimpleMediaLock: {
+ FdoExtension->LockCount++;
+ countChanged = TRUE;
+ break;
+ }
+
+ case SecureMediaLock: {
+ fsContext->LockCount++;
+ FdoExtension->ProtectedLockCount++;
+ countChanged = TRUE;
+ break;
+ }
+
+ case InternalMediaLock: {
+ FdoExtension->InternalLockCount++;
+ countChanged = TRUE;
+ break;
+ }
+ }
+
+ } else {
+
+ //
+ // This is an unlock command. If it's a secured one then make sure
+ // the caller has a lock outstanding or return an error.
+ // note: may need to re-increment the count if actual unlock
+ // operation fails....
+ //
+
+ switch (LockType) {
+
+ case SimpleMediaLock: {
+ if(FdoExtension->LockCount != 0) {
+ FdoExtension->LockCount--;
+ countChanged = TRUE;
+ }
+ break;
+ }
+
+ case SecureMediaLock: {
+ if(fsContext->LockCount == 0) {
+ status = STATUS_INVALID_DEVICE_STATE;
+ leave;
+ }
+ fsContext->LockCount--;
+ FdoExtension->ProtectedLockCount--;
+ countChanged = TRUE;
+ break;
+ }
+
+ case InternalMediaLock: {
+ NT_ASSERT(FdoExtension->InternalLockCount != 0);
+ FdoExtension->InternalLockCount--;
+ countChanged = TRUE;
+ break;
+ }
+ }
+
+ //
+ // We only send an unlock command to the drive if both the
+ // secured and unsecured lock counts have dropped to zero.
+ //
+
+ if ((FdoExtension->ProtectedLockCount != 0) ||
+ (FdoExtension->InternalLockCount != 0) ||
+ (FdoExtension->LockCount != 0)) {
+
+ status = STATUS_SUCCESS;
+ leave;
+ }
+ }
+
+ status = STATUS_SUCCESS;
+ if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
+
+ srb = (PSCSI_REQUEST_BLOCK)ClasspAllocateSrb(FdoExtension);
+
+ if (srb == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ leave;
+ }
+
+ if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
+
+ //
+ // NOTE - this is based on size used in ClasspAllocateSrb
+ //
+
+ status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srb,
+ STORAGE_ADDRESS_TYPE_BTL8,
+ CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE,
+ 1,
+ SrbExDataTypeScsiCdb16);
+ if (!NT_SUCCESS(status)) {
+ NT_ASSERT(FALSE);
+ leave;
+ }
+
+ } else {
+ RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
+ }
+
+ SrbSetCdbLength(srb, 6);
+ cdb = SrbGetCdb(srb);
+ NT_ASSERT(cdb != NULL);
+
+ cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
+
+ //
+ // TRUE - prevent media removal.
+ // FALSE - allow media removal.
+ //
+
+ cdb->MEDIA_REMOVAL.Prevent = Lock;
+
+ //
+ // Set timeout value.
+ //
+
+ SrbSetTimeOutValue(srb, FdoExtension->TimeOutValue);
+
+ //
+ // The actual lock operation on the device isn't so important
+ // as the internal lock counts. Ignore failures.
+ //
+
+ status = ClassSendSrbSynchronous(FdoExtension->DeviceObject,
+ srb,
+ NULL,
+ 0,
+ FALSE);
+ }
+
+ } finally {
+
+ if (!NT_SUCCESS(status)) {
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
+ "ClasspEjectionControl: FAILED status %x -- "
+ "reverting lock counts\n", status));
+
+ if (countChanged) {
+
+ //
+ // have to revert to previous counts if the
+ // lock/unlock operation actually failed.
+ //
+
+ if (Lock) {
+
+ switch (LockType) {
+
+ case SimpleMediaLock: {
+ FdoExtension->LockCount--;
+ break;
+ }
+
+ case SecureMediaLock: {
+ fsContext->LockCount--;
+ FdoExtension->ProtectedLockCount--;
+ break;
+ }
+
+ case InternalMediaLock: {
+ FdoExtension->InternalLockCount--;
+ break;
+ }
+ }
+
+ } else {
+
+ switch (LockType) {
+
+ case SimpleMediaLock: {
+ FdoExtension->LockCount++;
+ break;
+ }
+
+ case SecureMediaLock: {
+ fsContext->LockCount++;
+ FdoExtension->ProtectedLockCount++;
+ break;
+ }
+
+ case InternalMediaLock: {
+ FdoExtension->InternalLockCount++;
+ break;
+ }
+ }
+ }
+
+ }
+
+ } else {
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
+ "ClasspEjectionControl: Succeeded\n"));
+
+ }
+
+ TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL,
+ "ClasspEjectionControl: "
+ "Current Counts: Internal: %x Secure: %x Simple: %x\n",
+ FdoExtension->InternalLockCount,
+ FdoExtension->ProtectedLockCount,
+ FdoExtension->LockCount
+ ));
+
+ KeSetEvent(&(FdoExtension->EjectSynchronizationEvent),
+ IO_NO_INCREMENT,
+ FALSE);
+ KeLeaveCriticalRegion();
+
+ if (srb) {
+ ClassFreeOrReuseSrb(FdoExtension, srb);
+ }
+
+ }
+ return status;
+}
+
+#else
+
+/*
+ * ISSUE: RESTORE this (see above)
+ * This is a new implementation of the function that doesn't thrash memory
+ * or depend on the srbLookasideList.
+ * HOWEVER, it seems to cause pagefile initialization to fail during boot
+ * for some reason. Need to resolve this before switching to this function.
+ */
+NTSTATUS
+ClasspEjectionControl(
+ IN PDEVICE_OBJECT Fdo,
+ IN PIRP Irp,
+ IN MEDIA_LOCK_TYPE LockType,
+ IN BOOLEAN Lock
+ )
+{
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
+ PFILE_OBJECT_EXTENSION fsContext;
+ BOOLEAN fileHandleOk = TRUE;
+ BOOLEAN countChanged = FALSE;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ status = KeWaitForSingleObject(
+ &fdoExt->EjectSynchronizationEvent,
+ UserRequest,
+ KernelMode,
+ FALSE,
+ NULL);
+ NT_ASSERT(status == STATUS_SUCCESS);
+
+ /*
+ * If this is a "secured" request, we have to make sure
+ * that the file handle is valid.
+ */
+ if (LockType == SecureMediaLock){
+ PIO_STACK_LOCATION thisSp = IoGetCurrentIrpStackLocation(Irp);
+
+ /*
+ * Make sure that the file object we are supplied has a
+ * proper FsContext before we try doing a secured lock.
+ */
+ if (thisSp->FileObject){
+ PCOMMON_DEVICE_EXTENSION commonExt = (PCOMMON_DEVICE_EXTENSION)fdoExt;
+ fsContext = ClassGetFsContext(commonExt, thisSp->FileObject);
+ }
+ else {
+ fsContext = NULL;
+ }
+
+ if (!fsContext){
+ NT_ASSERT(fsContext);
+ fileHandleOk = FALSE;
+ }
+ }
+
+ if (fileHandleOk){
+
+ /*
+ * Adjust the lock counts and make sure they make sense.
+ */
+ status = STATUS_SUCCESS;
+ if (Lock){
+ switch(LockType) {
+ case SimpleMediaLock:
+ fdoExt->LockCount++;
+ countChanged = TRUE;
+ break;
+ case SecureMediaLock:
+ fsContext->LockCount++;
+ fdoExt->ProtectedLockCount++;
+ countChanged = TRUE;
+ break;
+ case InternalMediaLock:
+ fdoExt->InternalLockCount++;
+ countChanged = TRUE;
+ break;
+ }
+ }
+ else {
+ /*
+ * This is an unlock command. If it's a secured one then make sure
+ * the caller has a lock outstanding or return an error.
+ */
+ switch (LockType){
+ case SimpleMediaLock:
+ if (fdoExt->LockCount > 0){
+ fdoExt->LockCount--;
+ countChanged = TRUE;
+ }
+ else {
+ NT_ASSERT(fdoExt->LockCount > 0);
+ status = STATUS_INTERNAL_ERROR;
+ }
+ break;
+ case SecureMediaLock:
+ if (fsContext->LockCount > 0){
+ NT_ASSERT(fdoExt->ProtectedLockCount > 0);
+ fsContext->LockCount--;
+ fdoExt->ProtectedLockCount--;
+ countChanged = TRUE;
+ }
+ else {
+ NT_ASSERT(fsContext->LockCount > 0);
+ status = STATUS_INVALID_DEVICE_STATE;
+ }
+ break;
+ case InternalMediaLock:
+ NT_ASSERT(fdoExt->InternalLockCount > 0);
+ fdoExt->InternalLockCount--;
+ countChanged = TRUE;
+ break;
+ }
+ }
+
+ if (NT_SUCCESS(status)){
+ /*
+ * We only send an unlock command to the drive if
+ * all the lock counts have dropped to zero.
+ */
+ if (!Lock &&
+ (fdoExt->ProtectedLockCount ||
+ fdoExt->InternalLockCount ||
+ fdoExt->LockCount)){
+
+ /*
+ * The lock count is still positive, so don't unlock yet.
+ */
+ status = STATUS_SUCCESS;
+ }
+ else if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
+ /*
+ * The device isn't removable media. don't send a cmd.
+ */
+ status = STATUS_SUCCESS;
+ }
+ else {
+ TRANSFER_PACKET *pkt;
+
+ pkt = DequeueFreeTransferPacket(Fdo, TRUE);
+ if (pkt){
+ KEVENT event;
+
+ /*
+ * Store the number of packets servicing the irp (one)
+ * inside the original IRP. It will be used to counted down
+ * to zero when the packet completes.
+ * Initialize the original IRP's status to success.
+ * If the packet fails, we will set it to the error status.
+ */
+ Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ /*
+ * Set this up as a SYNCHRONOUS transfer, submit it,
+ * and wait for the packet to complete. The result
+ * status will be written to the original irp.
+ */
+ KeInitializeEvent(&event, SynchronizationEvent, FALSE);
+ SetupEjectionTransferPacket(pkt, Lock, &event, Irp);
+ SubmitTransferPacket(pkt);
+ (VOID)KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ status = Irp->IoStatus.Status;
+ }
+ else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ }
+ }
+ else {
+ status = STATUS_INVALID_PARAMETER;
+ }
+
+ if (!NT_SUCCESS(status) && countChanged) {
+
+ //
+ // have to revert to previous counts if the
+ // lock/unlock operation actually failed.
+ //
+
+ if(Lock) {
+
+ switch(LockType) {
+
+ case SimpleMediaLock: {
+ FdoExtension->LockCount--;
+ break;
+ }
+
+ case SecureMediaLock: {
+ fsContext->LockCount--;
+ FdoExtension->ProtectedLockCount--;
+ break;
+ }
+
+ case InternalMediaLock: {
+ FdoExtension->InternalLockCount--;
+ break;
+ }
+ }
+
+ } else {
+
+ switch(LockType) {
+
+ case SimpleMediaLock: {
+ FdoExtension->LockCount++;
+ break;
+ }
+
+ case SecureMediaLock: {
+ fsContext->LockCount++;
+ FdoExtension->ProtectedLockCount++;
+ break;
+ }
+
+ case InternalMediaLock: {
+ FdoExtension->InternalLockCount++;
+ break;
+ }
+ }
+ }
+ }
+
+
+
+ KeSetEvent(&fdoExt->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE);
+
+ return status;
+}
+#endif
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+PFILE_OBJECT_EXTENSION
+ClassGetFsContext(
+ _In_ PCOMMON_DEVICE_EXTENSION CommonExtension,
+ _In_ PFILE_OBJECT FileObject
+ )
+{
+ PAGED_CODE();
+ return GetDictionaryEntry(&(CommonExtension->FileObjectDictionary),
+ (ULONGLONG) FileObject);
+}