/* * BUGBUG REMOVE this old function implementation as soon as the * boottime pagefile problems with the new one (below) * are resolved. */ NTSTATUS NTAPI 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; volatile PSCSI_REQUEST_BLOCK srb = NULL; BOOLEAN countChanged = FALSE; PAGED_CODE(); // // Interlock with ejection and secure lock cleanup code. This is a // user request so we can allow the stack to get swapped out while we // wait for synchronization. // status = KeWaitForSingleObject( &(FdoExtension->EjectSynchronizationEvent), UserRequest, UserMode, FALSE, NULL); ASSERT(status == STATUS_SUCCESS); DebugPrint((2, "ClasspEjectionControl: " "Received request for %s lock type\n", LockTypeStrings[LockType] )); _SEH2_TRY { PCDB cdb; srb = ClasspAllocateSrb(FdoExtension); if(srb == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); cdb = (PCDB) srb->Cdb; // // 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 = ClasspGetFsContext(commonExtension, fileObject); } if (fsContext == NULL) { // // This handle isn't setup correctly. We can't let the // operation go. // status = STATUS_INVALID_PARAMETER; _SEH2_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; _SEH2_LEAVE; } fsContext->LockCount--; FdoExtension->ProtectedLockCount--; countChanged = TRUE; break; } case InternalMediaLock: { 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; _SEH2_LEAVE; } } status = STATUS_SUCCESS; if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { srb->CdbLength = 6; cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; // // TRUE - prevent media removal. // FALSE - allow media removal. // cdb->MEDIA_REMOVAL.Prevent = Lock; // // Set timeout value. // srb->TimeOutValue = 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); } } _SEH2_FINALLY { if (!NT_SUCCESS(status)) { DebugPrint((2, "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 { DebugPrint((2, "ClasspEjectionControl: Succeeded\n")); } DebugPrint((2, "ClasspEjectionControl: " "Current Counts: Internal: %x Secure: %x Simple: %x\n", FdoExtension->InternalLockCount, FdoExtension->ProtectedLockCount, FdoExtension->LockCount )); KeSetEvent(&(FdoExtension->EjectSynchronizationEvent), IO_NO_INCREMENT, FALSE); if (srb) { ClassFreeOrReuseSrb(FdoExtension, srb); } } _SEH2_END; return status; }
VOID NTAPI ClasspCleanupProtectedLocks( IN PFILE_OBJECT_EXTENSION FsContext ) { PCOMMON_DEVICE_EXTENSION commonExtension = FsContext->DeviceObject->DeviceExtension; PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension; ULONG newDeviceLockCount = 1; PAGED_CODE(); DebugPrint((2, "ClasspCleanupProtectedLocks called for %p\n", FsContext->DeviceObject)); DebugPrint((2, "ClasspCleanupProtectedLocks - FsContext %p is locked " "%d times\n", FsContext, FsContext->LockCount)); ASSERT(BreakOnClose == FALSE); // // Synchronize with ejection and ejection control requests. // KeEnterCriticalRegion(); KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent), UserRequest, UserMode, 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((PLONG)&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. // DebugPrint((2, "ClasspCleanupProtectedLocks: FDO secured lock count = %d " "lock count = %d\n", fdoExtension->ProtectedLockCount, fdoExtension->LockCount)); if((newDeviceLockCount == 0) && (fdoExtension->LockCount == 0)) { SCSI_REQUEST_BLOCK srb; PCDB cdb; NTSTATUS status; DebugPrint((2, "ClasspCleanupProtectedLocks: FDO lock count dropped " "to zero\n")); RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); cdb = (PCDB) &(srb.Cdb); srb.CdbLength = 6; cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; // // TRUE - prevent media removal. // FALSE - allow media removal. // cdb->MEDIA_REMOVAL.Prevent = FALSE; // // Set timeout value. // srb.TimeOutValue = fdoExtension->TimeOutValue; status = ClassSendSrbSynchronous(fdoExtension->DeviceObject, &srb, NULL, 0, FALSE); DebugPrint((2, "ClasspCleanupProtectedLocks: unlock request to drive " "returned status %lx\n", status)); } } KeSetEvent(&fdoExtension->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE); KeLeaveCriticalRegion(); return; }
/* * 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; }
/*++ Private so we can later expose to someone wanting to use a preallocated buffer --*/ NTSTATUS NTAPI CdRompGetConfiguration( IN PDEVICE_OBJECT Fdo, IN PGET_CONFIGURATION_HEADER Buffer, IN ULONG BufferSize, OUT PULONG ValidBytes, IN FEATURE_NUMBER StartingFeature, IN ULONG RequestedType ) { PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; PCDROM_DATA cdData; SCSI_REQUEST_BLOCK srb; PCDB cdb; ULONG_PTR returned; NTSTATUS status; PAGED_CODE(); ASSERT(Buffer); ASSERT(ValidBytes); *ValidBytes = 0; returned = 0; RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); RtlZeroMemory(Buffer, BufferSize); fdoExtension = Fdo->DeviceExtension; cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData); if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT)) { return STATUS_INVALID_DEVICE_REQUEST; } srb.TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT; srb.CdbLength = 10; cdb = (PCDB)srb.Cdb; cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION; cdb->GET_CONFIGURATION.RequestType = (UCHAR)RequestedType; cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(StartingFeature >> 8); cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(StartingFeature & 0xff); cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(BufferSize >> 8); cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(BufferSize & 0xff); status = ClassSendSrbSynchronous(Fdo, &srb, Buffer, BufferSize, FALSE); returned = srb.DataTransferLength; KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures, "CdromGetConfiguration: Status was %x\n", status)); if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { // // if returned more than can be stored in a ULONG, return false // if (returned > (ULONG)(-1)) { return STATUS_UNSUCCESSFUL; } ASSERT(returned <= BufferSize); *ValidBytes = (ULONG)returned; return STATUS_SUCCESS; } else { KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures, "CdromGetConfiguration: failed %x\n", status)); return status; } ASSERT(FALSE); return STATUS_UNSUCCESSFUL; }
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; }