mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
926 lines
22 KiB
926 lines
22 KiB
/*++
|
|
|
|
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;
|
|
}
|