927 lines
22 KiB
C
927 lines
22 KiB
C
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1996 - 1999
|
||
|
||
Module Name:
|
||
|
||
pdo.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the dispatch routines for scsiport's physical device
|
||
objects
|
||
|
||
Authors:
|
||
|
||
Peter Wieland
|
||
|
||
Environment:
|
||
|
||
Kernel mode only
|
||
|
||
Notes:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "port.h"
|
||
|
||
#if DBG
|
||
static const char *__file__ = __FILE__;
|
||
#endif
|
||
|
||
VOID
|
||
SpAdapterCleanup(
|
||
IN PADAPTER_EXTENSION DeviceExtension
|
||
);
|
||
|
||
VOID
|
||
SpReapChildren(
|
||
IN PADAPTER_EXTENSION Adapter
|
||
);
|
||
|
||
BOOLEAN
|
||
SpTerminateAdapterSynchronized (
|
||
IN PADAPTER_EXTENSION Adapter
|
||
);
|
||
|
||
BOOLEAN
|
||
SpRemoveAdapterSynchronized(
|
||
IN PADAPTER_EXTENSION Adapter
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, SpDeleteLogicalUnit)
|
||
#pragma alloc_text(PAGE, SpRemoveLogicalUnit)
|
||
#pragma alloc_text(PAGE, SpWaitForRemoveLock)
|
||
#pragma alloc_text(PAGE, SpAdapterCleanup)
|
||
#pragma alloc_text(PAGE, SpReapChildren)
|
||
|
||
#pragma alloc_text(PAGELOCK, ScsiPortRemoveAdapter)
|
||
#endif
|
||
|
||
|
||
BOOLEAN
|
||
SpRemoveLogicalUnit(
|
||
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
||
IN UCHAR RemoveType
|
||
)
|
||
|
||
{
|
||
PADAPTER_EXTENSION adapterExtension = LogicalUnit->AdapterExtension;
|
||
|
||
ULONG isRemoved;
|
||
ULONG oldDebugLevel;
|
||
|
||
PAGED_CODE();
|
||
|
||
if(LogicalUnit->CommonExtension.IsRemoved != REMOVE_COMPLETE) {
|
||
|
||
if(RemoveType == IRP_MN_REMOVE_DEVICE) {
|
||
|
||
SpWaitForRemoveLock(LogicalUnit->DeviceObject, SP_BASE_REMOVE_LOCK );
|
||
|
||
//
|
||
// If the device was claimed we should release it now.
|
||
//
|
||
|
||
if(LogicalUnit->IsClaimed) {
|
||
LogicalUnit->IsClaimed = FALSE;
|
||
LogicalUnit->IsLegacyClaim = FALSE;
|
||
}
|
||
|
||
}
|
||
|
||
DebugPrint((1, "SpRemoveLogicalUnit - %sremoving device %#p\n",
|
||
(RemoveType == IRP_MN_SURPRISE_REMOVAL) ? "surprise " : "",
|
||
LogicalUnit));
|
||
|
||
//
|
||
// If the lun isn't marked as missing yet or is marked as missing but
|
||
// PNP hasn't been informed yet then we cannot delete it. Set it back
|
||
// to the NO_REMOVE state so that we'll be able to attempt a rescan.
|
||
//
|
||
// Likewise if the lun is invisible then just swallow the remove
|
||
// operation now that we've cleared any existing claims.
|
||
//
|
||
|
||
if(RemoveType == IRP_MN_REMOVE_DEVICE) {
|
||
|
||
//
|
||
// If the device is not missing or is missing but is still
|
||
// enumerated then don't finish destroying it.
|
||
//
|
||
|
||
if((LogicalUnit->IsMissing == TRUE) &&
|
||
(LogicalUnit->IsEnumerated == FALSE)) {
|
||
|
||
// do nothing here - fall through and destroy the device.
|
||
|
||
} else {
|
||
|
||
DebugPrint((1, "SpRemoveLogicalUnit - device is not missing "
|
||
"and will not be destroyed\n"));
|
||
|
||
SpAcquireRemoveLock(LogicalUnit->DeviceObject, SP_BASE_REMOVE_LOCK);
|
||
|
||
LogicalUnit->CommonExtension.IsRemoved = NO_REMOVE;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
} else if((LogicalUnit->IsVisible == FALSE) &&
|
||
(LogicalUnit->IsMissing == FALSE)) {
|
||
|
||
//
|
||
// The surprise remove came because the device is no longer
|
||
// visible. We don't want to destroy it.
|
||
//
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Mark the device as uninitialized so that we'll go back and
|
||
// recreate all the necessary stuff if it gets restarted.
|
||
//
|
||
|
||
LogicalUnit->CommonExtension.IsInitialized = FALSE;
|
||
|
||
//
|
||
// Delete the device map entry for this one (if any).
|
||
//
|
||
|
||
SpDeleteDeviceMapEntry(&(LogicalUnit->CommonExtension));
|
||
|
||
if(RemoveType == IRP_MN_REMOVE_DEVICE) {
|
||
|
||
ASSERT(LogicalUnit->RequestTimeoutCounter == -1);
|
||
ASSERT(LogicalUnit->ReadyLogicalUnit == NULL);
|
||
ASSERT(LogicalUnit->PendingRequest == NULL);
|
||
ASSERT(LogicalUnit->BusyRequest == NULL);
|
||
ASSERT(LogicalUnit->QueueCount == 0);
|
||
|
||
LogicalUnit->CommonExtension.IsRemoved = REMOVE_COMPLETE;
|
||
|
||
//
|
||
// Yank this out of the logical unit list.
|
||
//
|
||
|
||
SpRemoveLogicalUnitFromBin(LogicalUnit->AdapterExtension,
|
||
LogicalUnit);
|
||
|
||
LogicalUnit->PathId = 0xff;
|
||
LogicalUnit->TargetId = 0xff;
|
||
LogicalUnit->Lun = 0xff;
|
||
|
||
//
|
||
// If this device wasn't temporary then delete it.
|
||
//
|
||
|
||
if(LogicalUnit->IsTemporary == FALSE) {
|
||
SpDeleteLogicalUnit(LogicalUnit);
|
||
}
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
VOID
|
||
SpDeleteLogicalUnit(
|
||
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will release any resources held for the logical unit, mark the
|
||
device extension as deleted, and call the io system to actually delete
|
||
the object. The device object will be deleted once it's reference count
|
||
drops to zero.
|
||
|
||
Arguments:
|
||
|
||
LogicalUnit - the device object for the logical unit to be deleted.
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
ASSERT(LogicalUnit->ReadyLogicalUnit == NULL);
|
||
ASSERT(LogicalUnit->PendingRequest == NULL);
|
||
ASSERT(LogicalUnit->BusyRequest == NULL);
|
||
ASSERT(LogicalUnit->QueueCount == 0);
|
||
|
||
ASSERT(LogicalUnit->PathId == 0xff);
|
||
ASSERT(LogicalUnit->TargetId == 0xff);
|
||
ASSERT(LogicalUnit->Lun == 0xff);
|
||
|
||
//
|
||
// Unregister with WMI.
|
||
//
|
||
|
||
if(LogicalUnit->CommonExtension.WmiInitialized == TRUE) {
|
||
|
||
//
|
||
// Destroy all our WMI resources and unregister with WMI.
|
||
//
|
||
|
||
IoWMIRegistrationControl(LogicalUnit->DeviceObject,
|
||
WMIREG_ACTION_DEREGISTER);
|
||
|
||
//
|
||
// We should be asking the WmiFreeRequestList of remove some
|
||
// free cells.
|
||
|
||
LogicalUnit->CommonExtension.WmiInitialized = FALSE;
|
||
SpWmiDestroySpRegInfo(LogicalUnit->DeviceObject);
|
||
}
|
||
|
||
#if DBG
|
||
// ASSERT(LogicalUnit->CommonExtension.RemoveTrackingList == NULL);
|
||
ExDeleteNPagedLookasideList(
|
||
&(LogicalUnit->CommonExtension.RemoveTrackingLookasideList));
|
||
#endif
|
||
|
||
//
|
||
// If the request sense irp still exists, delete it.
|
||
//
|
||
|
||
if(LogicalUnit->RequestSenseIrp != NULL) {
|
||
IoFreeIrp(LogicalUnit->RequestSenseIrp);
|
||
LogicalUnit->RequestSenseIrp = NULL;
|
||
}
|
||
|
||
if(LogicalUnit->HwLogicalUnitExtension != NULL) {
|
||
ExFreePool(LogicalUnit->HwLogicalUnitExtension);
|
||
LogicalUnit->HwLogicalUnitExtension = NULL;
|
||
}
|
||
|
||
if(LogicalUnit->SerialNumber.Buffer != NULL) {
|
||
ExFreePool(LogicalUnit->SerialNumber.Buffer);
|
||
RtlInitAnsiString(&(LogicalUnit->SerialNumber), NULL);
|
||
}
|
||
|
||
if(LogicalUnit->DeviceIdentifierPage != NULL) {
|
||
ExFreePool(LogicalUnit->DeviceIdentifierPage);
|
||
LogicalUnit->DeviceIdentifierPage = NULL;
|
||
}
|
||
|
||
//
|
||
// If this lun is temporary then clear the RescanLun field in the adapter.
|
||
//
|
||
|
||
if(LogicalUnit->IsTemporary) {
|
||
ASSERT(LogicalUnit->AdapterExtension->RescanLun = LogicalUnit);
|
||
LogicalUnit->AdapterExtension->RescanLun = NULL;
|
||
} else {
|
||
ASSERT(LogicalUnit->AdapterExtension->RescanLun != LogicalUnit);
|
||
}
|
||
|
||
IoDeleteDevice(LogicalUnit->DeviceObject);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
ScsiPortRemoveAdapter(
|
||
IN PDEVICE_OBJECT AdapterObject,
|
||
IN BOOLEAN Surprise
|
||
)
|
||
{
|
||
PADAPTER_EXTENSION adapter = AdapterObject->DeviceExtension;
|
||
PCOMMON_EXTENSION commonExtension = AdapterObject->DeviceExtension;
|
||
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT_FDO(AdapterObject);
|
||
ASSERT(adapter->IsPnp);
|
||
|
||
//
|
||
// Set the flag PD_ADAPTER_REMOVED to keep scsiport from calling into the
|
||
// miniport after we've started this teardown.
|
||
//
|
||
|
||
if(Surprise == FALSE) {
|
||
PVOID sectionHandle;
|
||
KIRQL oldIrql;
|
||
|
||
//
|
||
// Wait until all outstanding requests have been completed. If the
|
||
// adapter was surprise removed, we don't need to wait on the remove
|
||
// lock again, since we already waited for it in the surprise remove
|
||
// path.
|
||
//
|
||
|
||
if (commonExtension->CurrentPnpState != IRP_MN_SURPRISE_REMOVAL) {
|
||
SpWaitForRemoveLock(AdapterObject, AdapterObject);
|
||
}
|
||
|
||
//
|
||
// If the device is started we should uninitialize the miniport and
|
||
// release it's resources. Fortunately this is exactly what stop does.
|
||
//
|
||
|
||
if((commonExtension->CurrentPnpState != IRP_MN_SURPRISE_REMOVAL) &&
|
||
((commonExtension->CurrentPnpState == IRP_MN_START_DEVICE) ||
|
||
(commonExtension->PreviousPnpState == IRP_MN_START_DEVICE))) {
|
||
|
||
//
|
||
// Okay. If this adapter can't support remove then we're dead
|
||
//
|
||
|
||
ASSERT(SpIsAdapterControlTypeSupported(adapter, ScsiStopAdapter) == TRUE);
|
||
|
||
//
|
||
// Stop the miniport now that it's safe.
|
||
//
|
||
|
||
SpEnableDisableAdapter(adapter, FALSE);
|
||
|
||
//
|
||
// Mark the adapter as removed.
|
||
//
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
sectionHandle = MmLockPagableCodeSection(ScsiPortRemoveAdapter);
|
||
InterlockedIncrement(&SpPAGELOCKLockCount);
|
||
#endif
|
||
KeAcquireSpinLock(&(adapter->SpinLock), &oldIrql);
|
||
adapter->SynchronizeExecution(adapter->InterruptObject,
|
||
SpRemoveAdapterSynchronized,
|
||
adapter);
|
||
|
||
KeReleaseSpinLock(&(adapter->SpinLock), oldIrql);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
InterlockedDecrement(&SpPAGELOCKLockCount);
|
||
MmUnlockPagableImageSection(sectionHandle);
|
||
#endif
|
||
|
||
}
|
||
SpReapChildren(adapter);
|
||
}
|
||
|
||
if(commonExtension->WmiInitialized == TRUE) {
|
||
|
||
//
|
||
// Destroy all our WMI resources and unregister with WMI.
|
||
//
|
||
|
||
IoWMIRegistrationControl(AdapterObject, WMIREG_ACTION_DEREGISTER);
|
||
SpWmiRemoveFreeMiniPortRequestItems(adapter);
|
||
commonExtension->WmiInitialized = FALSE;
|
||
commonExtension->WmiMiniPortInitialized = FALSE;
|
||
}
|
||
|
||
//
|
||
// If we were surprise removed then this has already been done once.
|
||
// In that case don't try to run the cleanup code a second time even though
|
||
// it's safe to do so.
|
||
//
|
||
|
||
SpDeleteDeviceMapEntry(commonExtension);
|
||
SpDestroyAdapter(adapter, Surprise);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
SpWaitForRemoveLock(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PVOID LockTag
|
||
)
|
||
{
|
||
PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Mark the thing as removing
|
||
//
|
||
|
||
commonExtension->IsRemoved = REMOVE_PENDING;
|
||
|
||
//
|
||
// Release our outstanding lock.
|
||
//
|
||
|
||
SpReleaseRemoveLock(DeviceObject, LockTag);
|
||
|
||
DebugPrint((4, "SpWaitForRemoveLock - Reference count is now %d\n",
|
||
commonExtension->RemoveLock));
|
||
|
||
KeWaitForSingleObject(&(commonExtension->RemoveEvent),
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
|
||
DebugPrint((4, "SpWaitForRemoveLock - removing device %#p\n",
|
||
DeviceObject));
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
SpDestroyAdapter(
|
||
IN PADAPTER_EXTENSION Adapter,
|
||
IN BOOLEAN Surprise
|
||
)
|
||
{
|
||
SpReleaseAdapterResources(Adapter, Surprise);
|
||
SpAdapterCleanup(Adapter);
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
SpAdapterCleanup(
|
||
IN PADAPTER_EXTENSION Adapter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine cleans up the names associated with the specified adapter
|
||
and the i/o system counts.
|
||
|
||
Arguments:
|
||
|
||
Adapter - Supplies a pointer to the device extension to be deleted.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCOMMON_EXTENSION commonExtension = &(Adapter->CommonExtension);
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// If we assigned a port number to this adapter then attempt to delete the
|
||
// symbolic links we created to it.
|
||
//
|
||
|
||
if(Adapter->PortNumber != -1) {
|
||
|
||
PWCHAR wideNameStrings[] = {L"\\Device\\ScsiPort%d",
|
||
L"\\DosDevices\\Scsi%d:"};
|
||
ULONG i;
|
||
|
||
for(i = 0; i < (sizeof(wideNameStrings) / sizeof(PWCHAR)); i++) {
|
||
WCHAR wideLinkName[64];
|
||
UNICODE_STRING unicodeLinkName;
|
||
|
||
swprintf(wideLinkName, wideNameStrings[i], Adapter->PortNumber);
|
||
RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
|
||
IoDeleteSymbolicLink(&unicodeLinkName);
|
||
}
|
||
|
||
Adapter->PortNumber = -1;
|
||
|
||
//
|
||
// Decrement the scsiport count.
|
||
//
|
||
|
||
IoGetConfigurationInformation()->ScsiPortCount--;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
SpReleaseAdapterResources(
|
||
IN PADAPTER_EXTENSION Adapter,
|
||
IN BOOLEAN Surprise
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function deletes all of the storage associated with a device
|
||
extension, disconnects from the timers and interrupts and then deletes the
|
||
object. This function can be called at any time during the initialization.
|
||
|
||
Arguments:
|
||
|
||
Adapter - Supplies a pointer to the device extesnion to be deleted.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PCOMMON_EXTENSION commonExtension = &(Adapter->CommonExtension);
|
||
ULONG j;
|
||
PVOID tempPointer;
|
||
|
||
PAGED_CODE();
|
||
|
||
#if DBG
|
||
|
||
if(!Surprise) {
|
||
|
||
//
|
||
// Free the Remove tracking lookaside list.
|
||
//
|
||
|
||
ExDeleteNPagedLookasideList(&(commonExtension->RemoveTrackingLookasideList));
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Stop the time and disconnect the interrupt if they have been
|
||
// initialized. The interrupt object is connected after
|
||
// timer has been initialized, and the interrupt object is connected, but
|
||
// before the timer is started.
|
||
//
|
||
|
||
if(Adapter->DeviceObject->Timer != NULL) {
|
||
IoStopTimer(Adapter->DeviceObject);
|
||
KeCancelTimer(&(Adapter->MiniPortTimer));
|
||
}
|
||
|
||
if(Adapter->SynchronizeExecution != SpSynchronizeExecution) {
|
||
|
||
if (Adapter->InterruptObject) {
|
||
IoDisconnectInterrupt(Adapter->InterruptObject);
|
||
}
|
||
|
||
if (Adapter->InterruptObject2) {
|
||
IoDisconnectInterrupt(Adapter->InterruptObject2);
|
||
Adapter->InterruptObject2 = NULL;
|
||
}
|
||
|
||
//
|
||
// SpSynchronizeExecution expects to get a pointer to the
|
||
// adapter extension as the "interrupt" parameter.
|
||
//
|
||
|
||
Adapter->InterruptObject = (PVOID) Adapter;
|
||
Adapter->SynchronizeExecution = SpSynchronizeExecution;
|
||
}
|
||
|
||
//
|
||
// Delete the miniport's device extension
|
||
//
|
||
|
||
if (Adapter->HwDeviceExtension != NULL) {
|
||
|
||
PHW_DEVICE_EXTENSION devExt =
|
||
CONTAINING_RECORD(Adapter->HwDeviceExtension,
|
||
HW_DEVICE_EXTENSION,
|
||
HwDeviceExtension);
|
||
|
||
ExFreePool(devExt);
|
||
Adapter->HwDeviceExtension = NULL;
|
||
}
|
||
|
||
//
|
||
// Free the configuration information structure.
|
||
//
|
||
|
||
if (Adapter->PortConfig) {
|
||
ExFreePool(Adapter->PortConfig);
|
||
Adapter->PortConfig = NULL;
|
||
}
|
||
|
||
//
|
||
// Deallocate SCSIPORT WMI REGINFO information, if any.
|
||
//
|
||
|
||
SpWmiDestroySpRegInfo(Adapter->DeviceObject);
|
||
|
||
//
|
||
// Free the common buffer.
|
||
//
|
||
|
||
if (SpVerifyingCommonBuffer(Adapter)) {
|
||
|
||
SpFreeCommonBufferVrfy(Adapter);
|
||
|
||
} else {
|
||
|
||
if (Adapter->SrbExtensionBuffer != NULL &&
|
||
Adapter->CommonBufferSize != 0) {
|
||
|
||
if (Adapter->DmaAdapterObject == NULL) {
|
||
|
||
//
|
||
// Since there is no adapter just free the non-paged pool.
|
||
//
|
||
|
||
ExFreePool(Adapter->SrbExtensionBuffer);
|
||
|
||
} else {
|
||
|
||
if(Adapter->UncachedExtensionIsCommonBuffer == FALSE) {
|
||
MmFreeContiguousMemorySpecifyCache(Adapter->SrbExtensionBuffer,
|
||
Adapter->CommonBufferSize,
|
||
MmCached);
|
||
} else {
|
||
|
||
FreeCommonBuffer(
|
||
Adapter->DmaAdapterObject,
|
||
Adapter->CommonBufferSize,
|
||
Adapter->PhysicalCommonBuffer,
|
||
Adapter->SrbExtensionBuffer,
|
||
FALSE);
|
||
}
|
||
|
||
}
|
||
Adapter->SrbExtensionBuffer = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Get rid of our dma adapter.
|
||
//
|
||
|
||
if(Adapter->DmaAdapterObject != NULL) {
|
||
PutDmaAdapter(Adapter->DmaAdapterObject);
|
||
Adapter->DmaAdapterObject = NULL;
|
||
}
|
||
|
||
//
|
||
// Free the SRB data array.
|
||
//
|
||
|
||
if (Adapter->SrbDataListInitialized) {
|
||
|
||
if(Adapter->EmergencySrbData != NULL) {
|
||
|
||
ExFreeToNPagedLookasideList(
|
||
&Adapter->SrbDataLookasideList,
|
||
Adapter->EmergencySrbData);
|
||
Adapter->EmergencySrbData = NULL;
|
||
}
|
||
|
||
ExDeleteNPagedLookasideList(&Adapter->SrbDataLookasideList);
|
||
|
||
Adapter->SrbDataListInitialized = FALSE;
|
||
}
|
||
|
||
if (Adapter->InquiryBuffer != NULL) {
|
||
ExFreePool(Adapter->InquiryBuffer);
|
||
Adapter->InquiryBuffer = NULL;
|
||
}
|
||
|
||
if (Adapter->InquirySenseBuffer != NULL) {
|
||
ExFreePool(Adapter->InquirySenseBuffer);
|
||
Adapter->InquirySenseBuffer = NULL;
|
||
}
|
||
|
||
if (Adapter->InquiryIrp != NULL) {
|
||
IoFreeIrp(Adapter->InquiryIrp);
|
||
Adapter->InquiryIrp = NULL;
|
||
}
|
||
|
||
if (Adapter->InquiryMdl != NULL) {
|
||
IoFreeMdl(Adapter->InquiryMdl);
|
||
Adapter->InquiryMdl = NULL;
|
||
}
|
||
|
||
#ifndef USE_DMA_MACROS
|
||
//
|
||
// Free the Scatter Gather lookaside list.
|
||
//
|
||
|
||
if (Adapter->MediumScatterGatherListInitialized) {
|
||
|
||
ExDeleteNPagedLookasideList(
|
||
&Adapter->MediumScatterGatherLookasideList);
|
||
|
||
Adapter->MediumScatterGatherListInitialized = FALSE;
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Unmap any mapped areas.
|
||
//
|
||
|
||
SpReleaseMappedAddresses(Adapter);
|
||
|
||
//
|
||
// If we've got any resource lists allocated still we should free them
|
||
// now.
|
||
//
|
||
|
||
if(Adapter->AllocatedResources != NULL) {
|
||
ExFreePool(Adapter->AllocatedResources);
|
||
Adapter->AllocatedResources = NULL;
|
||
}
|
||
|
||
if(Adapter->TranslatedResources != NULL) {
|
||
ExFreePool(Adapter->TranslatedResources);
|
||
Adapter->TranslatedResources = NULL;
|
||
}
|
||
|
||
//
|
||
// Cleanup verifier resources.
|
||
//
|
||
|
||
if (SpVerifierActive(Adapter)) {
|
||
SpDoVerifierCleanup(Adapter);
|
||
}
|
||
|
||
#if defined(FORWARD_PROGRESS)
|
||
//
|
||
// Cleanup the adapter's reserved pages.
|
||
//
|
||
|
||
if (Adapter->ReservedPages != NULL) {
|
||
MmFreeMappingAddress(Adapter->ReservedPages,
|
||
SCSIPORT_TAG_MAPPING_LIST);
|
||
Adapter->ReservedPages = NULL;
|
||
}
|
||
|
||
if (Adapter->ReservedMdl != NULL) {
|
||
IoFreeMdl(Adapter->ReservedMdl);
|
||
Adapter->ReservedMdl = NULL;
|
||
}
|
||
#endif
|
||
|
||
Adapter->CommonExtension.IsInitialized = FALSE;
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
SpReapChildren(
|
||
IN PADAPTER_EXTENSION Adapter
|
||
)
|
||
{
|
||
ULONG j;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Run through the logical unit bins and remove any child devices which
|
||
// remain.
|
||
//
|
||
|
||
for(j = 0; j < NUMBER_LOGICAL_UNIT_BINS; j++) {
|
||
|
||
while(Adapter->LogicalUnitList[j].List != NULL) {
|
||
|
||
PLOGICAL_UNIT_EXTENSION lun =
|
||
Adapter->LogicalUnitList[j].List;
|
||
|
||
lun->IsMissing = TRUE;
|
||
lun->IsEnumerated = FALSE;
|
||
|
||
SpRemoveLogicalUnit(lun, IRP_MN_REMOVE_DEVICE);
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
SpTerminateAdapter(
|
||
IN PADAPTER_EXTENSION Adapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will terminate the miniport's control of the adapter. It
|
||
does not cleanly shutdown the miniport and should only be called when
|
||
scsiport is notified that the adapter has been surprise removed.
|
||
|
||
This works by synchronizing with the miniport and setting flags to
|
||
disable any new calls into the miniport. Once this has been done it can
|
||
run through and complete any i/o requests which may still be inside
|
||
the miniport.
|
||
|
||
Arguments:
|
||
|
||
Adapter - the adapter to terminate.
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL oldIrql;
|
||
|
||
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
|
||
|
||
KeAcquireSpinLockAtDpcLevel(&(Adapter->SpinLock));
|
||
|
||
if(Adapter->CommonExtension.PreviousPnpState == IRP_MN_START_DEVICE) {
|
||
|
||
//
|
||
// TA synchronized will stop all calls into the miniport and complete
|
||
// all active requests.
|
||
//
|
||
|
||
Adapter->SynchronizeExecution(Adapter->InterruptObject,
|
||
SpTerminateAdapterSynchronized,
|
||
Adapter);
|
||
|
||
Adapter->CommonExtension.PreviousPnpState = 0xff;
|
||
|
||
KeReleaseSpinLockFromDpcLevel(&(Adapter->SpinLock));
|
||
|
||
//
|
||
// Stop the miniport timer
|
||
//
|
||
|
||
KeCancelTimer(&(Adapter->MiniPortTimer));
|
||
|
||
//
|
||
// We keep the device object timer running so that any held, busy or
|
||
// otherwise deferred requests will have a chance to get flushed out.
|
||
// We can give the whole process a boost by setting the adapter timeout
|
||
// counter to 1 (it will go to zero in the tick handler) and running
|
||
// the tick handler by hand here.
|
||
//
|
||
|
||
// IoStopTimer(Adapter->DeviceObject);
|
||
Adapter->PortTimeoutCounter = 1;
|
||
|
||
ScsiPortTickHandler(Adapter->DeviceObject, NULL);
|
||
|
||
} else {
|
||
KeReleaseSpinLockFromDpcLevel(&(Adapter->SpinLock));
|
||
}
|
||
|
||
KeLowerIrql(oldIrql);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
SpTerminateAdapterSynchronized(
|
||
IN PADAPTER_EXTENSION Adapter
|
||
)
|
||
{
|
||
//
|
||
// Disable the interrupt from coming in.
|
||
//
|
||
|
||
SET_FLAG(Adapter->InterruptData.InterruptFlags, PD_ADAPTER_REMOVED);
|
||
CLEAR_FLAG(Adapter->InterruptData.InterruptFlags, PD_RESET_HOLD);
|
||
|
||
ScsiPortCompleteRequest(Adapter->HwDeviceExtension,
|
||
0xff,
|
||
0xff,
|
||
0xff,
|
||
SRB_STATUS_NO_HBA);
|
||
|
||
//
|
||
// Run the completion DPC.
|
||
//
|
||
|
||
if(TEST_FLAG(Adapter->InterruptData.InterruptFlags,
|
||
PD_NOTIFICATION_REQUIRED)) {
|
||
SpRequestCompletionDpc(Adapter->DeviceObject);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOLEAN
|
||
SpRemoveAdapterSynchronized(
|
||
PADAPTER_EXTENSION Adapter
|
||
)
|
||
{
|
||
//
|
||
// Disable the interrupt from coming in.
|
||
//
|
||
|
||
SET_FLAG(Adapter->InterruptData.InterruptFlags, PD_ADAPTER_REMOVED);
|
||
CLEAR_FLAG(Adapter->InterruptData.InterruptFlags, PD_RESET_HOLD);
|
||
|
||
return TRUE;
|
||
}
|