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.
4792 lines
120 KiB
4792 lines
120 KiB
/*++
|
|
|
|
Copyright (C) 1990-4 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
port.h
|
|
|
|
Abstract:
|
|
|
|
This file defines the necessary structures, defines, and functions for
|
|
the common SCSI port driver.
|
|
|
|
Author:
|
|
|
|
Jeff Havens (jhavens) 28-Feb-1991
|
|
Mike Glass
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#ifndef _PORT_H_
|
|
#define _PORT_H_
|
|
|
|
#include "stdarg.h"
|
|
#include "stddef.h"
|
|
#include "stdio.h"
|
|
#include "string.h"
|
|
|
|
#include "ntddk.h"
|
|
#include "scsi.h"
|
|
|
|
#include <ntddscsi.h>
|
|
#include <ntdddisk.h>
|
|
#include "ntddstor.h"
|
|
|
|
#include "wmistr.h"
|
|
|
|
#include "wdmguid.h"
|
|
#include "devguid.h"
|
|
#include "portlib.h"
|
|
|
|
//
|
|
// feature/debugginging #define switches
|
|
//
|
|
|
|
#define TEST_LISTS 0
|
|
|
|
//
|
|
// ScsiPort global variable declarations. These should be static data (like
|
|
// lookup tables) to avoid synchronization problems.
|
|
//
|
|
|
|
extern PDRIVER_DISPATCH AdapterMajorFunctionTable[];
|
|
extern PDRIVER_DISPATCH DeviceMajorFunctionTable[];
|
|
extern PDRIVER_DISPATCH Scsi1DeviceMajorFunctionTable[];
|
|
|
|
//
|
|
// Global list of scsi adapters. This is used by the srb data allocator routine
|
|
// to convert the "tag" provided into a pointer to the device object.
|
|
//
|
|
|
|
extern KSPIN_LOCK ScsiGlobalAdapterListSpinLock;
|
|
extern PDEVICE_OBJECT *ScsiGlobalAdapterList;
|
|
extern ULONG ScsiGlobalAdapterListElements;
|
|
|
|
//
|
|
// Count of how many times we've locked down the PAGELOCK section.
|
|
//
|
|
|
|
extern LONG SpPAGELOCKLockCount;
|
|
|
|
//
|
|
// Whether the system can do 64 bit PA's or not.
|
|
//
|
|
|
|
extern ULONG Sp64BitPhysicalAddresses;
|
|
|
|
//
|
|
// Handle to pageable verifier code section. We manually lock the verify
|
|
// code into memory iff we need it.
|
|
//
|
|
|
|
extern PVOID VerifierCodeSectionHandle;
|
|
extern PVOID VerifierApiCodeSectionHandle;
|
|
extern ULONG SpVrfyLevel;
|
|
|
|
//
|
|
// Constants and macros to enforce good use of Ex[Allocate|Free]PoolWithTag.
|
|
// Remeber that all pool tags will display in the debugger in reverse order
|
|
//
|
|
|
|
#if USE_EXFREEPOOLWITHTAG_ONLY
|
|
#define TAG(x) (x | 0x80000000)
|
|
#else
|
|
#define TAG(x) (x)
|
|
#endif
|
|
|
|
#define SCSIPORT_TAG_MINIPORT_PARAM TAG('aPcS') // Hold registry data
|
|
#define SCSIPORT_TAG_ACCESS_RANGE TAG('APcS') // Access Ranges
|
|
#define SCSIPORT_TAG_BUS_DATA TAG('bPcS') // Get Bus Data holder
|
|
#define SCSIPORT_TAG_QUEUE_BITMAP TAG('BPcS') // QueueTag BitMap
|
|
#define SCSIPORT_TAG_COMMON_BUFFER TAG('cPcS') // Fake Common Buffer
|
|
#define SCSIPORT_TAG_RESET TAG('CPcS') // reset bus code
|
|
#define SCSIPORT_TAG_PNP_ID TAG('dPcS') // Pnp id strings
|
|
#define SCSIPORT_TAG_SRB_DATA TAG('DPcS') // SRB_DATA allocations
|
|
#define SCSIPORT_TAG_PAE TAG('ePcS') // MDLs allocated for PAE requests
|
|
#define SCSIPORT_TAG_EMERGENCY_SG_ENTRY TAG('EPcS') // Scatter gather lists
|
|
#define SCSIPORT_TAG_VERIFIER TAG('fPcS') // Scsiport verifier entry
|
|
#define SCSIPORT_TAG_GLOBAL TAG('GPcS') // Global memory
|
|
#define SCSIPORT_TAG_DEV_EXT TAG('hPcS') // HwDevice Ext
|
|
#define SCSIPORT_TAG_LUN_EXT TAG('HPcS') // HwLogicalUnit Extension
|
|
#define SCSIPORT_TAG_SENSE_BUFFER TAG('iPcS') // Sense info
|
|
#define SCSIPORT_TAG_INIT_CHAIN TAG('IPcS') // Init data chain
|
|
#define SCSIPORT_TAG_LOCK_TRACKING TAG('lPcS') // remove lock tracking
|
|
#define SCSIPORT_TAG_LARGE_SG_ENTRY TAG('LPcS') // Scatter gather lists
|
|
#define SCSIPORT_TAG_MAPPING_LIST TAG('mPcS') // Address mapping lists
|
|
#define SCSIPORT_TAG_MEDIUM_SG_ENTRY TAG('MPcS') // Scatter gather lists
|
|
#define SCSIPORT_TAG_ENABLE TAG('pPcS') // device & adapter enable
|
|
#define SCSIPORT_TAG_PORT_CONFIG TAG('PpcS') // Scsi PortConfig copies
|
|
#define SCSIPORT_TAG_INQUIRY TAG('qPcS') // inquiry data
|
|
#define SCSIPORT_TAG_REQUEST_SENSE TAG('QPcS') // request sense
|
|
#define SCSIPORT_TAG_RESOURCE_LIST TAG('rPcS') // resource list copy
|
|
#define SCSIPORT_TAG_REGISTRY TAG('RPcS') // registry allocations
|
|
#define SCSIPORT_TAG_STOP_DEVICE TAG('sPcS') // stop device
|
|
#define SCSIPORT_TAG_STOP_ADAPTER TAG('SPcS') // stop Adapter
|
|
#define SCSIPORT_TAG_REROUTE TAG('tPcS') // Legacy request rerouting
|
|
#define SCSIPORT_TAG_INTERFACE_MAPPING TAG('TPcS') // Interface Mapping
|
|
#define SCSIPORT_TAG_DEVICE_RELATIONS TAG('uPcS') // device relation structs
|
|
#define SCSIPORT_TAG_EVENT TAG('vPcS') // KEVENT
|
|
#define SCSIPORT_TAG_DEVICE_MAP TAG('VPcS') // Device map allocations
|
|
|
|
#define SCSIPORT_TAG_WMI_EVENT TAG('wPcS') // WMI Events
|
|
#define SCSIPORT_TAG_WMI_REQUEST TAG('WPcS') // WMI Requests
|
|
|
|
#define SCSIPORT_TAG_REPORT_LUNS TAG('xPcS') // Report Luns
|
|
#define SCSIPORT_TAG_REPORT_TARGETS TAG('XPcS') // Report Targets
|
|
#define SCSIPORT_TAG_TEMP_ID_BUFFER TAG('yPcS') // Temporary id buffer
|
|
#define SCSIPORT_TAG_ID_BUFFER TAG('YPcS') // Id buffer
|
|
#define SCSIPORT_TAG_SYMBOLIC_LINK TAG('zPcS') // Symbolic link strings
|
|
#define SCSIPORT_TAG_DEVICE_NAME TAG('ZPcS') // Device name buffer
|
|
|
|
#ifdef POOL_TAGGING
|
|
#ifdef ExAllocatePool
|
|
#undef ExAllocatePool
|
|
#endif
|
|
#define ExAllocatePool #assert(0)
|
|
#endif
|
|
|
|
#if defined(FORWARD_PROGRESS)
|
|
#define SP_RESERVED_PAGES 4
|
|
#endif
|
|
|
|
//
|
|
// The tag to use for the base remove lock. This lock is only released when
|
|
// the device is finally ready to be destroyed.
|
|
//
|
|
|
|
#define SP_BASE_REMOVE_LOCK (UIntToPtr(0xabcdabcd))
|
|
|
|
|
|
//
|
|
// I/O System API routines which should not be called inside scsiport -
|
|
// these generally have scsiport versions which perform sanity checks before
|
|
// calling the real i/o routine in checked builds.
|
|
//
|
|
|
|
#if 0
|
|
#ifdef IoCompleteRequest
|
|
#ifndef KEEP_COMPLETE_REQUEST
|
|
#undef IoCompleteRequest
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
// If Count is not already aligned, then
|
|
// round Count up to an even multiple of "Pow2". "Pow2" must be a power of 2.
|
|
//
|
|
// DWORD
|
|
// ROUND_UP_COUNT(
|
|
// IN DWORD Count,
|
|
// IN DWORD Pow2
|
|
// );
|
|
#define ROUND_UP_COUNT(Count,Pow2) \
|
|
( ((Count)+(Pow2)-1) & (~(((LONG)(Pow2))-1)) )
|
|
|
|
// LPVOID
|
|
// ROUND_UP_POINTER(
|
|
// IN LPVOID Ptr,
|
|
// IN DWORD Pow2
|
|
// );
|
|
|
|
// If Ptr is not already aligned, then round it up until it is.
|
|
#define ROUND_UP_POINTER(Ptr,Pow2) \
|
|
( (PVOID) ( (((ULONG_PTR)(Ptr))+(Pow2)-1) & (~(((LONG)(Pow2))-1)) ) )
|
|
|
|
|
|
//
|
|
// Macros, constants and declarations for debug code and debug print
|
|
// routines.
|
|
//
|
|
|
|
#define DEBUG_BUFFER_LENGTH 256
|
|
|
|
#if SCSIDBG_ENABLED
|
|
extern ULONG ScsiDebug;
|
|
|
|
#ifdef DebugPrint
|
|
#undef DebugPrint
|
|
#endif
|
|
|
|
#if SCSIDBG_ENABLED
|
|
|
|
//
|
|
// Forward definition of ScsiDebugPrintInt (internal and not exported)
|
|
//
|
|
VOID
|
|
ScsiDebugPrintInt(
|
|
ULONG DebugPrintLevel,
|
|
PCCHAR DebugMessage,
|
|
...
|
|
);
|
|
|
|
#define DebugPrint(x) ScsiDebugPrintInt x
|
|
#else
|
|
#define DebugPrint(x)
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#define ASSERT_FDO(x) ASSERT(!(((PCOMMON_EXTENSION) (x)->DeviceExtension)->IsPdo))
|
|
#define ASSERT_PDO(x) ASSERT((((PCOMMON_EXTENSION) (x)->DeviceExtension)->IsPdo))
|
|
#define ASSERT_SRB_DATA(x) ASSERT(((PSRB_DATA)(x))->Type == SRB_DATA_TYPE)
|
|
|
|
#if DBG
|
|
#define SpStartNextPacket(DevObj, Cancelable) \
|
|
{ \
|
|
PADAPTER_EXTENSION ext = (DevObj)->DeviceExtension; \
|
|
ASSERT(!(TEST_FLAG(ext->Flags, PD_PENDING_DEVICE_REQUEST)));\
|
|
IoStartNextPacket((DevObj), (Cancelable)); \
|
|
}
|
|
#else
|
|
#define SpStartNextPacket IoStartNextPacket
|
|
#endif
|
|
|
|
//
|
|
// Some type defines and random macros which don't seem to be in the
|
|
// header files i've included (or didn't exist at all)
|
|
//
|
|
|
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
|
|
|
#if 0 // DBG
|
|
#undef INLINE
|
|
#define INLINE
|
|
#else
|
|
#define INLINE __inline
|
|
#endif
|
|
|
|
#define INTERLOCKED /* Should only be accessed using InterlockedXxx routines*/
|
|
|
|
#define SET_FLAG(Flags, Bit) ((Flags) |= (Bit))
|
|
#define CLEAR_FLAG(Flags, Bit) ((Flags) &= ~(Bit))
|
|
#define TEST_FLAG(Flags, Bit) ((Flags) & (Bit))
|
|
|
|
#define TEST(Value) ((BOOLEAN) ((Value) ? TRUE : FALSE));
|
|
|
|
#define ARRAY_ELEMENTS_FOR_BITMAP(NumberOfBits, ArrayType) \
|
|
((NumberOfBits) / sizeof(ArrayType))
|
|
|
|
//
|
|
// Assorted constant definifitions
|
|
//
|
|
#define NUMBER_LOGICAL_UNIT_BINS 8
|
|
|
|
#define SP_DEFAULT_PHYSICAL_BREAK_VALUE 17
|
|
#define SP_SMALL_PHYSICAL_BREAK_VALUE 17
|
|
#define SP_LARGE_PHYSICAL_BREAK_VALUE (SP_DEFAULT_PHYSICAL_BREAK_VALUE + 1)
|
|
|
|
#define SCSIPORT_CONTROL_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ScsiPort\\"
|
|
#define DISK_SERVICE_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Disk"
|
|
#define SCSIPORT_SPECIAL_TARGET_KEY L"SpecialTargetList"
|
|
#define SCSIPORT_VERIFIER_KEY L"Verifier"
|
|
|
|
//
|
|
// WMI constants
|
|
//
|
|
#define SPMOFRESOURCENAME L"SCSIPORTWMI"
|
|
#define SPMOFREGISTRYPATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\ScsiPort"
|
|
|
|
//
|
|
// NT uses a system time measured in 100 nanosecond intervals. define
|
|
// conveninent constants for setting the timer.
|
|
//
|
|
|
|
#define MICROSECONDS 10 // 10 nanoseconds
|
|
#define MILLISECONDS (MICROSECONDS * 1000)
|
|
#define SECONDS (MILLISECONDS * 1000)
|
|
#define MINUTES (SECONDS * 60)
|
|
|
|
#define TIMEOUT(x) ((x) * -1)
|
|
|
|
//
|
|
// Possible values for the IsRemoved flag
|
|
//
|
|
|
|
#define NO_REMOVE 0
|
|
#define REMOVE_PENDING 1
|
|
#define REMOVE_COMPLETE 2
|
|
|
|
#define NUMBER_HARDWARE_STRINGS 6
|
|
|
|
#define SRB_DATA_TYPE 'wp'
|
|
#define SRB_LIST_DEPTH 20
|
|
|
|
#define NUMBER_BYPASS_SRB_DATA_BLOCKS 4
|
|
|
|
#define WMI_MINIPORT_EVENT_ITEM_MAX_SIZE 128
|
|
|
|
//
|
|
// Define the mimimum and maximum number of srb extensions which will be allocated.
|
|
//
|
|
|
|
#define MINIMUM_SRB_EXTENSIONS 16
|
|
#define MAXIMUM_SRB_EXTENSIONS 255
|
|
|
|
//
|
|
// Size of the buffer used for registry operations.
|
|
//
|
|
|
|
#define SP_REG_BUFFER_SIZE 512
|
|
|
|
//
|
|
// Number of times to retry when a BUSY status is returned.
|
|
//
|
|
|
|
#define BUSY_RETRY_COUNT 20
|
|
|
|
//
|
|
// Number of times to retry an INQUIRY request.
|
|
//
|
|
|
|
#define INQUIRY_RETRY_COUNT 2
|
|
|
|
//
|
|
// Number of irp stack locations to allocate for an INQUIRY command.
|
|
//
|
|
|
|
#define INQUIRY_STACK_LOCATIONS 1
|
|
|
|
//
|
|
// Default Srb Timeout value
|
|
//
|
|
|
|
#define SRB_DEFAULT_TIMEOUT 10
|
|
|
|
//
|
|
// Bitmask used for aligning values.
|
|
//
|
|
|
|
#define LONG_ALIGN (sizeof(LONG) - 1)
|
|
|
|
//
|
|
// Size of the ADAPTER_EXTENSION
|
|
//
|
|
|
|
#define ADAPTER_EXTENSION_SIZE sizeof(ADAPTER_EXTENSION)
|
|
|
|
//
|
|
// Size of the buffer used for inquiry operations. This is one more than the
|
|
// max bytes which can be requested from an inquiry operation so that we can
|
|
// zero out the buffer and be sure that the last string is null terminated.
|
|
//
|
|
|
|
#define SP_INQUIRY_BUFFER_SIZE (VPD_MAX_BUFFER_SIZE + 1)
|
|
|
|
//
|
|
// Assorted macros.
|
|
//
|
|
|
|
#define NEED_REQUEST_SENSE(Srb) (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION \
|
|
&& !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && \
|
|
Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength )
|
|
|
|
#define GET_FDO_EXTENSION(HwExt) ((CONTAINING_RECORD(HwExt, HW_DEVICE_EXTENSION, HwDeviceExtension))->FdoExtension)
|
|
|
|
#define ADDRESS_TO_HASH(PathId, TargetId, Lun) (((TargetId) + (Lun)) % NUMBER_LOGICAL_UNIT_BINS)
|
|
|
|
#define IS_CLEANUP_REQUEST(irpStack) \
|
|
(((irpStack)->MajorFunction == IRP_MJ_CLOSE) || \
|
|
((irpStack)->MajorFunction == IRP_MJ_CLEANUP) || \
|
|
((irpStack)->MajorFunction == IRP_MJ_SHUTDOWN) || \
|
|
(((irpStack)->MajorFunction == IRP_MJ_SCSI) && \
|
|
(((irpStack)->Parameters.Scsi.Srb->Function == SRB_FUNCTION_RELEASE_DEVICE) || \
|
|
((irpStack)->Parameters.Scsi.Srb->Function == SRB_FUNCTION_FLUSH_QUEUE) || \
|
|
(TEST_FLAG((irpStack)->Parameters.Scsi.Srb->SrbFlags, SRB_FLAGS_BYPASS_FROZEN_QUEUE | \
|
|
SRB_FLAGS_BYPASS_LOCKED_QUEUE)))))
|
|
|
|
|
|
#define IS_INQUIRY(Srb) \
|
|
((Srb)->Cdb[0] == SCSIOP_INQUIRY)
|
|
#define IS_REQUEST_SENSE(Srb) \
|
|
((Srb)->Cdb[0] == SCSIOP_REQUEST_SENSE)
|
|
#define IS_READ_CAPACITY(Srb) \
|
|
((Srb)->Cdb[0] == SCSIOP_READ_CAPACITY)
|
|
#define IS_READ(Srb) \
|
|
((Srb)->Cdb[0] == SCSIOP_READ)
|
|
#define IS_WRITE(Srb) \
|
|
((Srb)->Cdb[0] == SCSIOP_WRITE)
|
|
#define IS_COPY(Srb) \
|
|
((Srb)->Cdb[0] == SCSIOP_COPY)
|
|
#define IS_COMPARE(Srb) \
|
|
((Srb)->Cdb[0] == SCSIOP_COMPARE)
|
|
#define IS_COPY_COMPARE(Srb) \
|
|
((Srb)->Cdb[0] == SCSIOP_COPY_COMPARE)
|
|
|
|
#define IS_MAPPED_SRB(Srb) \
|
|
(((Srb)->Function == SRB_FUNCTION_IO_CONTROL) || \
|
|
(((Srb)->Function == SRB_FUNCTION_EXECUTE_SCSI) && \
|
|
((IS_INQUIRY((Srb))) || \
|
|
(IS_REQUEST_SENSE((Srb))) || \
|
|
(IS_READ_CAPACITY((Srb))))))
|
|
|
|
#define IS_ILLEGAL_COMMAND(Srb) \
|
|
(IS_COPY((Srb)) || \
|
|
IS_COMPARE((Srb)) || \
|
|
IS_COPY_COMPARE((Srb)))
|
|
|
|
#define LU_OPERATING_IN_DEGRADED_STATE(luFlags) \
|
|
((luFlags) & LU_PERF_MAXQDEPTH_REDUCED)
|
|
|
|
|
|
//
|
|
// SpIsQueuePausedForSrb(lu, srb) -
|
|
// determines if the queue has been paused for this particular type of
|
|
// srb. This can be used with SpSrbIsBypassRequest to determine whether the
|
|
// srb needs to be handled specially.
|
|
//
|
|
|
|
#define SpIsQueuePausedForSrb(luFlags, srbFlags) \
|
|
((BOOLEAN) ((((luFlags) & LU_QUEUE_FROZEN) && !(srbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)) || \
|
|
(((luFlags) & LU_QUEUE_PAUSED) && !(srbFlags & SRB_FLAGS_BYPASS_LOCKED_QUEUE))))
|
|
|
|
#define SpIsQueuePaused(lu) ((lu)->LuFlags & (LU_QUEUE_FROZEN | \
|
|
LU_QUEUE_LOCKED))
|
|
|
|
#define SpSrbRequiresPower(srb) \
|
|
((BOOLEAN) ((srb->Function == SRB_FUNCTION_EXECUTE_SCSI) || \
|
|
(srb->Function == SRB_FUNCTION_IO_CONTROL) || \
|
|
(srb->Function == SRB_FUNCTION_SHUTDOWN) || \
|
|
(srb->Function == SRB_FUNCTION_FLUSH) || \
|
|
(srb->Function == SRB_FUNCTION_ABORT_COMMAND) || \
|
|
(srb->Function == SRB_FUNCTION_RESET_BUS) || \
|
|
(srb->Function == SRB_FUNCTION_RESET_DEVICE) || \
|
|
(srb->Function == SRB_FUNCTION_TERMINATE_IO) || \
|
|
(srb->Function == SRB_FUNCTION_REMOVE_DEVICE) || \
|
|
(srb->Function == SRB_FUNCTION_WMI)))
|
|
|
|
//
|
|
// Forward declarations of data structures
|
|
//
|
|
|
|
typedef struct _SRB_DATA SRB_DATA, *PSRB_DATA;
|
|
|
|
typedef struct _REMOVE_TRACKING_BLOCK
|
|
REMOVE_TRACKING_BLOCK,
|
|
*PREMOVE_TRACKING_BLOCK;
|
|
|
|
typedef struct _LOGICAL_UNIT_EXTENSION LOGICAL_UNIT_EXTENSION, *PLOGICAL_UNIT_EXTENSION;
|
|
typedef struct _ADAPTER_EXTENSION ADAPTER_EXTENSION, *PADAPTER_EXTENSION;
|
|
|
|
typedef struct _SP_INIT_CHAIN_ENTRY SP_INIT_CHAIN_ENTRY, *PSP_INIT_CHAIN_ENTRY;
|
|
|
|
typedef struct _HW_DEVICE_EXTENSION HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
|
|
//
|
|
// Macros for using the DMA functions.
|
|
//
|
|
|
|
#define AllocateCommonBuffer(DmaAdapter, Length, \
|
|
LogicalAddress, CacheEnabled) \
|
|
((DmaAdapter)->DmaOperations->AllocateCommonBuffer)( \
|
|
(DmaAdapter), \
|
|
(Length), \
|
|
(LogicalAddress), \
|
|
(CacheEnabled))
|
|
#define FreeCommonBuffer(DmaAdapter, Length, LogicalAddress, \
|
|
VirtualAddress, CacheEnabled) \
|
|
((DmaAdapter)->DmaOperations->FreeCommonBuffer)( \
|
|
(DmaAdapter), \
|
|
(Length), \
|
|
(LogicalAddress), \
|
|
(VirtualAddress), \
|
|
(CacheEnabled))
|
|
|
|
#define GetScatterGatherList(DmaAdapter, DeviceObject, Mdl, CurrentVa, \
|
|
Length, ExecutionRoutine, Context, \
|
|
WriteToDevice) \
|
|
((DmaAdapter)->DmaOperations->GetScatterGatherList)( \
|
|
(DmaAdapter), \
|
|
(DeviceObject), \
|
|
(Mdl), \
|
|
(CurrentVa), \
|
|
(Length), \
|
|
(ExecutionRoutine), \
|
|
(Context), \
|
|
(WriteToDevice))
|
|
|
|
#define PutScatterGatherList(DmaAdapter, ScatterGather, WriteToDevice) \
|
|
((DmaAdapter)->DmaOperations->PutScatterGatherList)( \
|
|
(DmaAdapter), \
|
|
(ScatterGather), \
|
|
(WriteToDevice))
|
|
|
|
#define AllocateAdapterChannel(DmaAdapter, DeviceObject, \
|
|
NumberOfMapRegisters, ExecutionRoutine, \
|
|
Context) \
|
|
((DmaAdapter)->DmaOperations->AllocateAdapterChannel)( \
|
|
(DmaAdapter), \
|
|
(DeviceObject), \
|
|
(NumberOfMapRegisters), \
|
|
(ExecutionRoutine), \
|
|
(Context))
|
|
|
|
#define FlushAdapterBuffers(DmaAdapter, Mdl, MapRegisterBase, CurrentVa, \
|
|
Length, WriteToDevice) \
|
|
((DmaAdapter)->DmaOperations->FlushAdapterBuffers)( \
|
|
(DmaAdapter), \
|
|
(Mdl), \
|
|
(MapRegisterBase), \
|
|
(CurrentVa), \
|
|
(Length), \
|
|
(WriteToDevice))
|
|
|
|
#define MapTransfer(DmaAdapter, Mdl, MapRegisterBase, CurrentVa, Length, \
|
|
WriteToDevice) \
|
|
((DmaAdapter)->DmaOperations->MapTransfer)( \
|
|
(DmaAdapter), \
|
|
(Mdl), \
|
|
(MapRegisterBase), \
|
|
(CurrentVa), \
|
|
(Length), \
|
|
(WriteToDevice))
|
|
|
|
#define FreeAdapterChannel(DmaAdapter) \
|
|
((DmaAdapter)->DmaOperations->FreeAdapterChannel)((DmaAdapter))
|
|
|
|
#define FreeMapRegisters(DmaAdapter, MapRegisterBase, NumberOfMapRegisters) \
|
|
((DmaAdapter)->DmaOperations->FreeMapRegisters)( \
|
|
(DmaAdapter), \
|
|
(MapRegisterBase), \
|
|
(NumberOfMapRegisters))
|
|
|
|
#define PutDmaAdapter(DmaAdapter) \
|
|
((DmaAdapter)->DmaOperations->PutDmaAdapter)((DmaAdapter))
|
|
|
|
|
|
#define BuildScatterGatherList(DmaAdapter, DevObj, Mdl, DataBuffer, \
|
|
DataTransferLength, ExecutionRoutine, \
|
|
Context, Write, Buffer, BufSize) \
|
|
((DmaAdapter)->DmaOperations->BuildScatterGatherList)( \
|
|
(DmaAdapter), \
|
|
(DevObj), \
|
|
(Mdl), \
|
|
(DataBuffer), \
|
|
(DataTransferLength), \
|
|
(ExecutionRoutine), \
|
|
(Context), \
|
|
(Write), \
|
|
(Buffer), \
|
|
(BufSize))
|
|
|
|
#define CalculateScatterGatherList(DmaAdapter, Mdl, CurrentVa, Length, \
|
|
SGListSize, NumberOfMapRegs) \
|
|
((DmaAdapter)->DmaOperations->CalculateScatterGatherList)( \
|
|
(DmaAdapter), \
|
|
(Mdl), \
|
|
(CurrentVa), \
|
|
(Length), \
|
|
(SGListSize), \
|
|
(NumberOfMapRegs))
|
|
|
|
//
|
|
// Type Definitions
|
|
//
|
|
|
|
//
|
|
// Structure used for tracking remove lock allocations in checked builds
|
|
//
|
|
|
|
struct _REMOVE_TRACKING_BLOCK {
|
|
PREMOVE_TRACKING_BLOCK NextBlock;
|
|
PVOID Tag;
|
|
LARGE_INTEGER TimeLocked;
|
|
PCSTR File;
|
|
ULONG Line;
|
|
};
|
|
|
|
#if DBG
|
|
#define SpAcquireRemoveLock(devobj, tag) \
|
|
SpAcquireRemoveLockEx(devobj, tag, __file__, __LINE__)
|
|
#endif
|
|
|
|
typedef struct _RESET_COMPLETION_CONTEXT {
|
|
PIRP OriginalIrp;
|
|
PDEVICE_OBJECT SafeLogicalUnit;
|
|
PDEVICE_OBJECT AdapterDeviceObject;
|
|
|
|
SCSI_REQUEST_BLOCK Srb;
|
|
} RESET_COMPLETION_CONTEXT, *PRESET_COMPLETION_CONTEXT;
|
|
|
|
//
|
|
// Define a pointer to the synchonize execution routine.
|
|
//
|
|
|
|
typedef
|
|
BOOLEAN
|
|
(*PSYNCHRONIZE_ROUTINE) (
|
|
IN PKINTERRUPT Interrupt,
|
|
IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
|
|
IN PVOID SynchronizeContext
|
|
);
|
|
|
|
typedef
|
|
VOID
|
|
(*PSP_ENABLE_DISABLE_COMPLETION_ROUTINE) (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN NTSTATUS Status,
|
|
IN PVOID Context
|
|
);
|
|
|
|
typedef
|
|
VOID
|
|
(*PSP_POWER_COMPLETION_ROUTINE) (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context
|
|
);
|
|
|
|
//
|
|
// device type table to build id's from
|
|
//
|
|
|
|
typedef const struct _SCSIPORT_DEVICE_TYPE {
|
|
|
|
const PCSTR DeviceTypeString;
|
|
|
|
const PCSTR GenericTypeString;
|
|
|
|
const PCWSTR DeviceMapString;
|
|
|
|
const BOOLEAN IsStorage;
|
|
|
|
} SCSIPORT_DEVICE_TYPE, *PSCSIPORT_DEVICE_TYPE;
|
|
|
|
//
|
|
// SCSI Get Configuration Information
|
|
//
|
|
// LUN Information
|
|
//
|
|
|
|
typedef struct _LOGICAL_UNIT_INFO {
|
|
UCHAR PathId;
|
|
UCHAR TargetId;
|
|
UCHAR Lun;
|
|
BOOLEAN DeviceClaimed;
|
|
struct _LOGICAL_UNIT_INFO *NextLunInfo;
|
|
UCHAR InquiryData[INQUIRYDATABUFFERSIZE];
|
|
} LOGICAL_UNIT_INFO, *PLOGICAL_UNIT_INFO;
|
|
|
|
typedef struct _SCSI_BUS_SCAN_DATA {
|
|
USHORT Length;
|
|
UCHAR InitiatorBusId;
|
|
UCHAR NumberOfLogicalUnits;
|
|
PLOGICAL_UNIT_INFO LunInfoList;
|
|
} SCSI_BUS_SCAN_DATA, *PSCSI_BUS_SCAN_DATA;
|
|
|
|
typedef struct _SCSI_CONFIGURATION_INFO {
|
|
UCHAR NumberOfBuses;
|
|
PSCSI_BUS_SCAN_DATA BusScanData[1];
|
|
} SCSI_CONFIGURATION_INFO, *PSCSI_CONFIGURATION_INFO;
|
|
|
|
//
|
|
// Adapter object transfer information.
|
|
//
|
|
|
|
typedef struct _ADAPTER_TRANSFER {
|
|
PSRB_DATA SrbData;
|
|
ULONG SrbFlags;
|
|
PVOID LogicalAddress;
|
|
ULONG Length;
|
|
}ADAPTER_TRANSFER, *PADAPTER_TRANSFER;
|
|
|
|
//
|
|
// NOTE: When the hal is performing double buffering (e.g. a 32-bit HBA on a
|
|
// 64-bit machine) the HalContext (below) is necessary. Otherwise, this is
|
|
// wasted space. It would be nice to detect this and only allocate the
|
|
// extra memory when necessary.
|
|
//
|
|
|
|
typedef struct _SRB_SCATTER_GATHER_LIST {
|
|
ULONG NumberOfElements;
|
|
ULONG_PTR Reserved;
|
|
SCATTER_GATHER_ELEMENT Elements[SP_SMALL_PHYSICAL_BREAK_VALUE];
|
|
UCHAR HalContext[sizeof (INTERNAL_WAIT_CONTEXT_BLOCK)];
|
|
} SRB_SCATTER_GATHER_LIST, *PSRB_SCATTER_GATHER_LIST;
|
|
|
|
typedef SCATTER_GATHER_ELEMENT SRB_SCATTER_GATHER, *PSRB_SCATTER_GATHER;
|
|
|
|
//
|
|
// Port driver error logging
|
|
//
|
|
|
|
typedef struct _ERROR_LOG_ENTRY {
|
|
UCHAR MajorFunctionCode;
|
|
UCHAR PathId;
|
|
UCHAR TargetId;
|
|
UCHAR Lun;
|
|
ULONG ErrorCode;
|
|
ULONG UniqueId;
|
|
ULONG ErrorLogRetryCount;
|
|
ULONG SequenceNumber;
|
|
} ERROR_LOG_ENTRY, *PERROR_LOG_ENTRY;
|
|
|
|
typedef struct _SP_LUN_IO_LOG {
|
|
UCHAR SrbStatus; // +0
|
|
UCHAR ScsiStatus; // +1
|
|
UCHAR CdbLength; // +2
|
|
UCHAR Tag; // +3
|
|
UCHAR Cdb[16]; // +4
|
|
UCHAR SenseData[18]; // +20
|
|
UCHAR SenseDataLength; // +38
|
|
union { // +40
|
|
ULONG InternalStatus;
|
|
ULONG QueueSortKey;
|
|
};
|
|
ULONG TickCount; // +44
|
|
} SP_LUN_IO_LOG, *PSP_LUN_IO_LOG;
|
|
|
|
//
|
|
// Context item for asynchronous enumerators.
|
|
//
|
|
|
|
typedef struct _SP_ENUMERATION_REQUEST SP_ENUMERATION_REQUEST, *PSP_ENUMERATION_REQUEST;
|
|
|
|
typedef
|
|
VOID
|
|
(*PSP_ENUMERATION_COMPLETION_ROUTINE) (
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN PSP_ENUMERATION_REQUEST Request,
|
|
IN NTSTATUS Status
|
|
);
|
|
|
|
struct _SP_ENUMERATION_REQUEST {
|
|
|
|
//
|
|
// A pointer to the next enumeration request on the list.
|
|
//
|
|
|
|
PSP_ENUMERATION_REQUEST NextRequest;
|
|
|
|
//
|
|
// The completion routine to be run. This routine will be run regardless
|
|
// of whether the enumeration actually succeeds. The
|
|
// EnumerationDeviceMutex and the EnumerationWorklistMutex will both be
|
|
// held when this is called. The completion routine should free the Request
|
|
// structure if necessary.
|
|
//
|
|
|
|
PSP_ENUMERATION_COMPLETION_ROUTINE CompletionRoutine;
|
|
|
|
//
|
|
// If this filed contains a pointer to an IO_STATUS_BLOCK then the
|
|
// completion routine should write it's status value out. This is so a
|
|
// synchronous waiter can return something other than STATUS_PENDING to the
|
|
// caller. If this field is NULL then there is no consumer for the status
|
|
// value.
|
|
//
|
|
|
|
PNTSTATUS OPTIONAL CompletionStatus;
|
|
|
|
//
|
|
// Arbitrary context value for the completion routine to use. In most cases
|
|
// this will be an IRP or an event.
|
|
//
|
|
|
|
PVOID Context;
|
|
|
|
//
|
|
// Indicates whether this request is being handled synchronously.
|
|
//
|
|
|
|
BOOLEAN Synchronous;
|
|
};
|
|
|
|
//
|
|
// SCSI request extension for port driver.
|
|
//
|
|
|
|
typedef
|
|
VOID
|
|
(FASTCALL *PSRB_DATA_FREE_ROUTINE) (
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN PSRB_DATA SrbData
|
|
);
|
|
|
|
struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _SRB_DATA {
|
|
|
|
//
|
|
// Single list entry. The lookaside list will be maintained in this
|
|
// memory.
|
|
//
|
|
|
|
SLIST_ENTRY Reserved;
|
|
|
|
//
|
|
// Header for debugging purposes.
|
|
//
|
|
|
|
CSHORT Type;
|
|
USHORT Size;
|
|
|
|
//
|
|
// The free routine for this srb data block.
|
|
//
|
|
|
|
PSRB_DATA_FREE_ROUTINE FreeRoutine;
|
|
|
|
//
|
|
// The list of requests for a particular logical unit.
|
|
//
|
|
|
|
LIST_ENTRY RequestList;
|
|
|
|
//
|
|
// The logical unit this request is intended for.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION LogicalUnit;
|
|
|
|
//
|
|
// The irp for the CurrentSrb.
|
|
//
|
|
|
|
PIRP CurrentIrp;
|
|
|
|
//
|
|
// The srb this is block is tracking.
|
|
//
|
|
|
|
PSCSI_REQUEST_BLOCK CurrentSrb;
|
|
|
|
//
|
|
// The chain of requests which have been completed by the miniport and are
|
|
// waiting for the CompletionDpc to be run.
|
|
//
|
|
|
|
struct _SRB_DATA *CompletedRequests;
|
|
ULONG ErrorLogRetryCount;
|
|
ULONG SequenceNumber;
|
|
|
|
PSCATTER_GATHER_LIST MapRegisterBase;
|
|
|
|
ULONG NumberOfMapRegisters;
|
|
|
|
//
|
|
// The offset between the data buffer for this request and the data
|
|
// buffer described by the MDL in the irp.
|
|
//
|
|
|
|
ULONG_PTR DataOffset;
|
|
|
|
PVOID RequestSenseSave;
|
|
|
|
//
|
|
// These data values will be restored to the SRB when it is retried within
|
|
// the port driver.
|
|
//
|
|
|
|
ULONG OriginalDataTransferLength;
|
|
|
|
//
|
|
// SRB Data flags.
|
|
//
|
|
|
|
ULONG Flags;
|
|
|
|
//
|
|
// Pointer to the adapter this block was allocated from. This is used
|
|
// when freeing srbdata blocks from the lookaside list back to pool.
|
|
//
|
|
|
|
PADAPTER_EXTENSION Adapter;
|
|
|
|
//
|
|
// The queue tag which was initially allocated for this srb_data block.
|
|
// This tag will be used for any tagged srb's which are associated with
|
|
// this block.
|
|
//
|
|
|
|
ULONG QueueTag;
|
|
|
|
//
|
|
// Internal status value - only returned if srb->SrbStatus is set to
|
|
// SRBP_STATUS_INTERNAL_ERROR.
|
|
//
|
|
|
|
NTSTATUS InternalStatus;
|
|
|
|
//
|
|
// The tick count when this request was last touched.
|
|
//
|
|
|
|
ULONG TickCount;
|
|
|
|
//
|
|
// The MDL of the remapped buffer (per IoMapTransfer or GET_SCATTER_GATHER)
|
|
//
|
|
|
|
PMDL RemappedMdl;
|
|
|
|
//
|
|
// The original data buffer pointer for this request - this will be
|
|
// restored when the request is completed.
|
|
//
|
|
|
|
PVOID OriginalDataBuffer;
|
|
|
|
//
|
|
// Pointer to the scatter gather list for this request
|
|
//
|
|
|
|
PSRB_SCATTER_GATHER ScatterGatherList;
|
|
|
|
//
|
|
// The original length of the sense data buffer supplied by the above
|
|
// driver.
|
|
//
|
|
|
|
UCHAR RequestSenseLengthSave;
|
|
|
|
//
|
|
// Pointer to the orignal SRB DataBuffer. We use this to store
|
|
// the original when we replace it with our buffer to unmapped
|
|
// memory in the case where the MapBuffer is FALSE.
|
|
//
|
|
|
|
PVOID UnmappedDataBuffer;
|
|
|
|
//
|
|
// The "small" scatter gather list for this request. Small
|
|
// by the constant SP_SMALL_PHYSICAL_BREAK_VALUE - small lists contain
|
|
// this many entries or less.
|
|
//
|
|
|
|
SRB_SCATTER_GATHER_LIST SmallScatterGatherList;
|
|
|
|
};
|
|
|
|
typedef struct _LOGICAL_UNIT_BIN {
|
|
KSPIN_LOCK Lock;
|
|
PLOGICAL_UNIT_EXTENSION List;
|
|
} LOGICAL_UNIT_BIN, *PLOGICAL_UNIT_BIN;
|
|
|
|
//
|
|
// WMI request item, queued on a miniport request.
|
|
//
|
|
|
|
typedef struct _WMI_MINIPORT_REQUEST_ITEM {
|
|
//
|
|
// WnodeEventItem MUST be the first field in WMI_MINIPORT_REQUEST_ITEM, in
|
|
// order to accommodate a copy optimization in ScsiPortCompletionDpc().
|
|
//
|
|
UCHAR WnodeEventItem[WMI_MINIPORT_EVENT_ITEM_MAX_SIZE];
|
|
UCHAR TypeOfRequest; // [Event/Reregister]
|
|
UCHAR PathId; // [0xFF for adapter]
|
|
UCHAR TargetId;
|
|
UCHAR Lun;
|
|
struct _WMI_MINIPORT_REQUEST_ITEM * NextRequest;
|
|
} WMI_MINIPORT_REQUEST_ITEM, *PWMI_MINIPORT_REQUEST_ITEM;
|
|
|
|
//
|
|
// WMI parameters.
|
|
//
|
|
|
|
typedef struct _WMI_PARAMETERS {
|
|
ULONG_PTR ProviderId; // ProviderId parameter from IRP
|
|
PVOID DataPath; // DataPath parameter from IRP
|
|
ULONG BufferSize; // BufferSize parameter from IRP
|
|
PVOID Buffer; // Buffer parameter from IRP
|
|
} WMI_PARAMETERS, *PWMI_PARAMETERS;
|
|
|
|
//
|
|
// SpInsertFreeWmiMiniPortItem context structure.
|
|
//
|
|
|
|
typedef struct _WMI_INSERT_CONTEXT {
|
|
PDEVICE_OBJECT DeviceObject; // [FDO or PDO]
|
|
PWMI_MINIPORT_REQUEST_ITEM ItemsToInsert;
|
|
} WMI_INSERT_CONTEXT, *PWMI_INSERT_CONTEXT;
|
|
|
|
//
|
|
// SpRemoveFreeWmiMiniPortItem context structure.
|
|
//
|
|
|
|
typedef struct _WMI_REMOVE_CONTEXT {
|
|
PDEVICE_OBJECT DeviceObject; // [FDO or PDO]
|
|
USHORT NumberToRemove;
|
|
} WMI_REMOVE_CONTEXT, *PWMI_REMOVE_CONTEXT;
|
|
|
|
//
|
|
// Define data storage for access at interrupt Irql.
|
|
//
|
|
|
|
typedef struct _INTERRUPT_DATA {
|
|
|
|
//
|
|
// SCSI port interrupt flags
|
|
//
|
|
|
|
ULONG InterruptFlags;
|
|
|
|
//
|
|
// List head for singlely linked list of complete IRPs.
|
|
//
|
|
|
|
PSRB_DATA CompletedRequests;
|
|
|
|
//
|
|
// Adapter object transfer parameters.
|
|
//
|
|
|
|
ADAPTER_TRANSFER MapTransferParameters;
|
|
|
|
//
|
|
// Error log information.
|
|
//
|
|
|
|
ERROR_LOG_ENTRY LogEntry;
|
|
|
|
//
|
|
// Logical unit to start next.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION ReadyLogicalUnit;
|
|
|
|
//
|
|
// List of completed abort reqeusts.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION CompletedAbort;
|
|
|
|
//
|
|
// Miniport timer request routine.
|
|
//
|
|
|
|
PHW_INTERRUPT HwTimerRequest;
|
|
|
|
//
|
|
// Mini port timer request time in micro seconds.
|
|
//
|
|
|
|
ULONG MiniportTimerValue;
|
|
|
|
//
|
|
// Queued WMI request items.
|
|
//
|
|
|
|
PWMI_MINIPORT_REQUEST_ITEM WmiMiniPortRequests;
|
|
|
|
//
|
|
// A couple of counters used to keep track of when the last interrupt
|
|
// occurred on this device.
|
|
//
|
|
|
|
ULONG TickCountAtLastInterruptAck;
|
|
ULONG TickCountAtLastInterruptNak;
|
|
|
|
} INTERRUPT_DATA, *PINTERRUPT_DATA;
|
|
|
|
#define NON_STANDARD_VPD_SUPPORTS_PAGE80 0x00000001
|
|
#define NON_STANDARD_VPD_SUPPORTS_PAGE83 0x00000002
|
|
|
|
typedef struct {
|
|
ULONG SparseLun;
|
|
ULONG OneLun;
|
|
ULONG LargeLuns;
|
|
ULONG SetLunInCdb;
|
|
ULONG NonStandardVPD;
|
|
ULONG BinarySN;
|
|
} SP_SPECIAL_CONTROLLER_FLAGS, *PSP_SPECIAL_CONTROLLER_FLAGS;
|
|
|
|
typedef struct _CONFIGURATION_CONTEXT {
|
|
BOOLEAN DisableTaggedQueueing;
|
|
BOOLEAN DisableMultipleLu;
|
|
ULONG AdapterNumber;
|
|
ULONG BusNumber;
|
|
PVOID Parameter;
|
|
PACCESS_RANGE AccessRanges;
|
|
UNICODE_STRING RegistryPath;
|
|
PORT_CONFIGURATION_INFORMATION PortConfig;
|
|
}CONFIGURATION_CONTEXT, *PCONFIGURATION_CONTEXT;
|
|
|
|
typedef struct _DEVICE_MAP_HANDLES {
|
|
HANDLE BusKey;
|
|
HANDLE InitiatorKey;
|
|
} DEVICE_MAP_HANDLES, *PDEVICE_MAP_HANDLES;
|
|
|
|
typedef struct _COMMON_EXTENSION {
|
|
|
|
//
|
|
// Back pointer to the device object
|
|
//
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
struct {
|
|
|
|
//
|
|
// True if this device object is a physical device object
|
|
//
|
|
|
|
BOOLEAN IsPdo : 1;
|
|
|
|
//
|
|
// True if this device object has processed it's first start and
|
|
// has been initialized.
|
|
//
|
|
|
|
BOOLEAN IsInitialized : 1;
|
|
|
|
//
|
|
// Has WMI been initialized for this device object?
|
|
//
|
|
|
|
BOOLEAN WmiInitialized : 1;
|
|
|
|
//
|
|
// Has the miniport associated with this FDO or PDO indicated WMI
|
|
// support?
|
|
//
|
|
|
|
BOOLEAN WmiMiniPortSupport : 1;
|
|
|
|
//
|
|
// Has the miniport been initialized for WMI.
|
|
//
|
|
|
|
BOOLEAN WmiMiniPortInitialized : 1;
|
|
|
|
};
|
|
|
|
//
|
|
// Current plug and play state or 0xff if no state operations have been
|
|
// sent yet.
|
|
//
|
|
|
|
UCHAR CurrentPnpState;
|
|
|
|
//
|
|
// Previous plug and play state or 0xff if there is no requirement that we
|
|
// be able to roll back in the current state (current state is not a query)
|
|
//
|
|
|
|
UCHAR PreviousPnpState;
|
|
|
|
//
|
|
// Interlocked counter indicating that the device has been removed.
|
|
//
|
|
|
|
ULONG IsRemoved;
|
|
|
|
|
|
//
|
|
// Pointer to the device object this is on top of
|
|
//
|
|
|
|
PDEVICE_OBJECT LowerDeviceObject;
|
|
|
|
//
|
|
// Srb flags to OR into all SRBs coming through this device object.
|
|
//
|
|
|
|
ULONG SrbFlags;
|
|
|
|
//
|
|
// Pointer to the dispatch table for this object
|
|
//
|
|
|
|
PDRIVER_DISPATCH *MajorFunction;
|
|
|
|
|
|
//
|
|
// Current and desired power state for this device and the system.
|
|
//
|
|
|
|
SYSTEM_POWER_STATE CurrentSystemState;
|
|
|
|
DEVICE_POWER_STATE CurrentDeviceState;
|
|
|
|
DEVICE_POWER_STATE DesiredDeviceState;
|
|
|
|
//
|
|
// Idle timer for this device
|
|
//
|
|
|
|
PULONG IdleTimer;
|
|
|
|
//
|
|
// Pointer to the SCSIPORT-provided WMIREGINFO structures registered on
|
|
// behalf of the miniport for this device object. Size is the size of the
|
|
// entire WMIREGINFO buffer in bytes.
|
|
//
|
|
|
|
PWMIREGINFO WmiScsiPortRegInfoBuf;
|
|
ULONG WmiScsiPortRegInfoBufSize;
|
|
|
|
//
|
|
// INTERLOCKED counter of the number of consumers of this device object.
|
|
// When this count goes to zero the RemoveEvent will be set.
|
|
//
|
|
|
|
//
|
|
// This variable is only manipulated by SpAcquireRemoveLock and
|
|
// SpReleaseRemoveLock.
|
|
//
|
|
|
|
LONG RemoveLock;
|
|
|
|
//
|
|
// This event will be signalled when it is safe to remove the device object
|
|
//
|
|
|
|
KEVENT RemoveEvent;
|
|
|
|
//
|
|
// The spinlock and the list are only used in checked builds to track who
|
|
// has acquired the remove lock. Free systems will leave these initialized
|
|
// to 0xff (they are still in the structure to make debugging easier)
|
|
//
|
|
|
|
KSPIN_LOCK RemoveTrackingSpinlock;
|
|
|
|
PVOID RemoveTrackingList;
|
|
|
|
LONG RemoveTrackingUntrackedCount;
|
|
|
|
NPAGED_LOOKASIDE_LIST RemoveTrackingLookasideList;
|
|
|
|
BOOLEAN RemoveTrackingLookasideListInitialized;
|
|
|
|
//
|
|
// Count of different services this device is being used for (ala
|
|
// IRP_MN_DEVICE_USAGE_NOTIFICATION)
|
|
//
|
|
|
|
ULONG PagingPathCount;
|
|
ULONG HibernatePathCount;
|
|
ULONG DumpPathCount;
|
|
|
|
} COMMON_EXTENSION, *PCOMMON_EXTENSION;
|
|
|
|
typedef struct _VERIFIER_EXTENSION {
|
|
|
|
//
|
|
// Miniport routines we verify.
|
|
//
|
|
|
|
PHW_FIND_ADAPTER RealHwFindAdapter;
|
|
PHW_INITIALIZE RealHwInitialize;
|
|
PHW_STARTIO RealHwStartIo;
|
|
PHW_INTERRUPT RealHwInterrupt;
|
|
PHW_RESET_BUS RealHwResetBus;
|
|
PHW_DMA_STARTED RealHwDmaStarted;
|
|
PHW_INTERRUPT RealHwRequestInterrupt;
|
|
PHW_INTERRUPT RealHwTimerRequest;
|
|
PHW_ADAPTER_CONTROL RealHwAdapterControl;
|
|
|
|
//
|
|
// Indicates the number of common buffer blocks that have been allocated.
|
|
//
|
|
|
|
ULONG CommonBufferBlocks;
|
|
|
|
//
|
|
// Points to an array that holds the VAs of all the common blocks.
|
|
//
|
|
|
|
PVOID* CommonBufferVAs;
|
|
|
|
//
|
|
// Points to an array that holds the PAs of all the common blocks.
|
|
//
|
|
|
|
PHYSICAL_ADDRESS* CommonBufferPAs;
|
|
|
|
//
|
|
// Indicates the size of the non-cached extension.
|
|
//
|
|
|
|
ULONG NonCachedBufferSize;
|
|
|
|
//
|
|
// Controls how aggressively we verify.
|
|
//
|
|
|
|
ULONG VrfyLevel;
|
|
|
|
//
|
|
// Pointer to an invalid page of memory. Used to catch miniports
|
|
// that touch memory when they're not supposed to.
|
|
//
|
|
|
|
PVOID InvalidPage;
|
|
|
|
//
|
|
// Indicates whether the common buffer blocks were allocated using
|
|
// DMA common buffer allocation routine.
|
|
//
|
|
|
|
BOOLEAN IsCommonBuffer;
|
|
|
|
} VERIFIER_EXTENSION, *PVERIFIER_EXTENSION;
|
|
|
|
|
|
struct _ADAPTER_EXTENSION {
|
|
|
|
union {
|
|
PDEVICE_OBJECT DeviceObject;
|
|
COMMON_EXTENSION CommonExtension;
|
|
};
|
|
|
|
//
|
|
// Pointer to the PDO we attached to - necessary for PnP routines
|
|
//
|
|
|
|
PDEVICE_OBJECT LowerPdo;
|
|
|
|
#if TEST_LISTS
|
|
|
|
//
|
|
// Some simple performance counters to determine how often we use the
|
|
// small vs. medium vs. large scatter gather lists.
|
|
//
|
|
|
|
ULONGLONG ScatterGatherAllocationCount;
|
|
|
|
//
|
|
// Counters used to calculate the average size of a small medium and
|
|
// large allocation. There are two values for each counter - a total
|
|
// count and an overflow count. The total count will be right-shifted one
|
|
// bit if it overflows on an increment. When this happens the overflow
|
|
// count will also be incremented. This count is used to adjust the
|
|
// allocation count when determining averages.
|
|
//
|
|
|
|
ULONGLONG SmallAllocationSize;
|
|
ULONGLONG MediumAllocationSize;
|
|
ULONGLONG LargeAllocationSize;
|
|
|
|
ULONG SmallAllocationCount;
|
|
ULONG LargeAllocationCount;
|
|
|
|
//
|
|
// Counters to determine how often we can service a request off the
|
|
// srb data list, how often we need to queue a request and how often
|
|
// we can resurrect a free'd srb data to service something off the queue.
|
|
//
|
|
|
|
INTERLOCKED ULONGLONG SrbDataAllocationCount;
|
|
INTERLOCKED ULONGLONG SrbDataQueueInsertionCount;
|
|
INTERLOCKED ULONGLONG SrbDataEmergencyFreeCount;
|
|
INTERLOCKED ULONGLONG SrbDataServicedFromTickHandlerCount;
|
|
INTERLOCKED ULONGLONG SrbDataResurrectionCount;
|
|
|
|
#endif
|
|
|
|
//
|
|
// Device extension for miniport routines.
|
|
//
|
|
|
|
PVOID HwDeviceExtension;
|
|
|
|
//
|
|
// Miniport noncached device extension
|
|
//
|
|
|
|
PVOID NonCachedExtension;
|
|
ULONG NonCachedExtensionSize;
|
|
|
|
ULONG PortNumber;
|
|
|
|
ULONG AdapterNumber;
|
|
|
|
//
|
|
// Active requests count. This count is biased by -1 so a value of -1
|
|
// indicates there are no requests out standing.
|
|
//
|
|
|
|
LONG ActiveRequestCount;
|
|
|
|
//
|
|
// Binary Flags
|
|
//
|
|
|
|
typedef struct {
|
|
|
|
//
|
|
// Did pnp or the port driver detect this device and provide resources
|
|
// to the miniport, or did the miniport detect the device for us. This
|
|
// flag also indicates whether the AllocatedResources list is non-null
|
|
// going into the find adapter routine.
|
|
//
|
|
|
|
BOOLEAN IsMiniportDetected : 1;
|
|
|
|
//
|
|
// Do we need to virtualize this adapter and make it look like the only
|
|
// adapter on it's own bus?
|
|
//
|
|
|
|
BOOLEAN IsInVirtualSlot : 1;
|
|
|
|
//
|
|
// Is this a pnp adapter?
|
|
//
|
|
|
|
BOOLEAN IsPnp : 1;
|
|
|
|
//
|
|
// Was an interrupt assigned to this device by the system?
|
|
//
|
|
|
|
BOOLEAN HasInterrupt : 1;
|
|
|
|
//
|
|
// Can this device be powered off?
|
|
//
|
|
|
|
BOOLEAN DisablePower : 1;
|
|
|
|
//
|
|
// Can this device be stopped?
|
|
//
|
|
|
|
BOOLEAN DisableStop : 1;
|
|
|
|
//
|
|
// Does this device need power notification on shutdown?
|
|
//
|
|
|
|
BOOLEAN NeedsShutdown : 1;
|
|
|
|
};
|
|
|
|
//
|
|
// For most virtual slot devices this will be zero. However for some
|
|
// the real slot/function number is needed by the miniport to access
|
|
// hardware shared by multiple slots/functions.
|
|
//
|
|
|
|
PCI_SLOT_NUMBER VirtualSlotNumber;
|
|
|
|
//
|
|
// The bus and slot number of this device as returned by the PCI driver.
|
|
// This is used when building the ConfigInfo block for crashdump so that
|
|
// the dump drivers can talk directly with the hal. These are only
|
|
// valid if IsInVirtualSlot is TRUE above.
|
|
//
|
|
|
|
ULONG RealBusNumber;
|
|
|
|
ULONG RealSlotNumber;
|
|
|
|
//
|
|
// Number of SCSI buses
|
|
//
|
|
|
|
UCHAR NumberOfBuses;
|
|
UCHAR MaximumTargetIds;
|
|
UCHAR MaxLuCount;
|
|
|
|
//
|
|
// SCSI port driver flags
|
|
//
|
|
|
|
ULONG Flags;
|
|
|
|
INTERLOCKED ULONG DpcFlags;
|
|
|
|
//
|
|
// The number of times this adapter has been disabled.
|
|
//
|
|
|
|
ULONG DisableCount;
|
|
|
|
LONG PortTimeoutCounter;
|
|
|
|
//
|
|
// A pointer to the interrupt object to be used with
|
|
// the SynchronizeExecution routine. If the miniport is
|
|
// using SpSynchronizeExecution then this will actually point
|
|
// back to the adapter extension.
|
|
//
|
|
|
|
PKINTERRUPT InterruptObject;
|
|
|
|
//
|
|
// Second Interrupt object (PCI IDE work-around)
|
|
//
|
|
|
|
PKINTERRUPT InterruptObject2;
|
|
|
|
//
|
|
// Routine to call to synchronize execution for the miniport.
|
|
//
|
|
|
|
PSYNCHRONIZE_ROUTINE SynchronizeExecution;
|
|
|
|
//
|
|
// Global device sequence number.
|
|
//
|
|
|
|
ULONG SequenceNumber;
|
|
KSPIN_LOCK SpinLock;
|
|
|
|
//
|
|
// Second spin lock (PCI IDE work-around). This is only initalized
|
|
// if the miniport has requested multiple interrupts.
|
|
//
|
|
|
|
KSPIN_LOCK MultipleIrqSpinLock;
|
|
|
|
//
|
|
// Dummy interrupt spin lock.
|
|
//
|
|
|
|
KSPIN_LOCK InterruptSpinLock;
|
|
|
|
//
|
|
// Dma Adapter information.
|
|
//
|
|
|
|
PVOID MapRegisterBase;
|
|
PDMA_ADAPTER DmaAdapterObject;
|
|
ADAPTER_TRANSFER FlushAdapterParameters;
|
|
|
|
//
|
|
// miniport's copy of the configuraiton informaiton.
|
|
// Used only during initialization.
|
|
//
|
|
|
|
PPORT_CONFIGURATION_INFORMATION PortConfig;
|
|
|
|
//
|
|
// Resources allocated and translated for this particular adapter.
|
|
//
|
|
|
|
PCM_RESOURCE_LIST AllocatedResources;
|
|
|
|
PCM_RESOURCE_LIST TranslatedResources;
|
|
|
|
//
|
|
// Common buffer size. Used for HalFreeCommonBuffer.
|
|
//
|
|
|
|
ULONG CommonBufferSize;
|
|
ULONG SrbExtensionSize;
|
|
|
|
//
|
|
// Indicates whether the common buffer was allocated using
|
|
// ALLOCATE_COMMON_BUFFER or MmAllocateContiguousMemorySpecifyCache.
|
|
//
|
|
|
|
BOOLEAN UncachedExtensionIsCommonBuffer;
|
|
|
|
//
|
|
// The number of srb extensions which were allocated.
|
|
//
|
|
|
|
ULONG SrbExtensionCount;
|
|
|
|
//
|
|
// Placeholder for the minimum number of requests to allocate for.
|
|
// This can be a registry parameter.
|
|
//
|
|
|
|
ULONG NumberOfRequests;
|
|
|
|
//
|
|
// SrbExtension and non-cached common buffer
|
|
//
|
|
|
|
PVOID SrbExtensionBuffer;
|
|
|
|
//
|
|
// List head of free SRB extentions.
|
|
//
|
|
|
|
PVOID SrbExtensionListHeader;
|
|
|
|
//
|
|
// A bitmap for keeping track of which queue tags are in use.
|
|
//
|
|
|
|
KSPIN_LOCK QueueTagSpinLock;
|
|
PRTL_BITMAP QueueTagBitMap;
|
|
|
|
UCHAR MaxQueueTag;
|
|
|
|
//
|
|
// Hint for allocating queue tags. Value will be the last queue
|
|
// tag allocated + 1.
|
|
//
|
|
|
|
ULONG QueueTagHint;
|
|
|
|
//
|
|
// Logical Unit Extensions
|
|
//
|
|
|
|
ULONG HwLogicalUnitExtensionSize;
|
|
|
|
//
|
|
// List of mapped address entries for use when powering up the adapter
|
|
// or cleaning up its mappings.
|
|
//
|
|
|
|
PMAPPED_ADDRESS MappedAddressList;
|
|
|
|
//
|
|
// List of free mapped address blocks preallocated by scsiport before
|
|
// calling HwFindAdapter. One is allocated for each memory range in the
|
|
// miniport's resource list. As ranges are unmapped their blocks will
|
|
// be placed here for potential reuse by the miniport's HwFindAdapter
|
|
// routine.
|
|
//
|
|
|
|
PMAPPED_ADDRESS FreeMappedAddressList;
|
|
|
|
//
|
|
// Miniport service routine pointers.
|
|
//
|
|
|
|
PHW_FIND_ADAPTER HwFindAdapter;
|
|
PHW_INITIALIZE HwInitialize;
|
|
PHW_STARTIO HwStartIo;
|
|
PHW_INTERRUPT HwInterrupt;
|
|
PHW_RESET_BUS HwResetBus;
|
|
PHW_DMA_STARTED HwDmaStarted;
|
|
PHW_INTERRUPT HwRequestInterrupt;
|
|
PHW_INTERRUPT HwTimerRequest;
|
|
PHW_ADAPTER_CONTROL HwAdapterControl;
|
|
|
|
ULONG InterruptLevel;
|
|
ULONG IoAddress;
|
|
|
|
//
|
|
// BitMap containing the list of supported adapter control types for this
|
|
// adapter/miniport.
|
|
//
|
|
|
|
RTL_BITMAP SupportedControlBitMap;
|
|
ULONG SupportedControlBits[ARRAY_ELEMENTS_FOR_BITMAP(
|
|
(ScsiAdapterControlMax),
|
|
ULONG)];
|
|
|
|
//
|
|
// Array of logical unit extensions.
|
|
//
|
|
|
|
LOGICAL_UNIT_BIN LogicalUnitList[NUMBER_LOGICAL_UNIT_BINS];
|
|
|
|
//
|
|
// The last logical unit for which the miniport completed a request. This
|
|
// will give us a chance to stay out of the LogicalUnitList for the common
|
|
// completion type.
|
|
//
|
|
// This value is set by ScsiPortNotification and will be cleared by
|
|
// SpRemoveLogicalUnitFromBin.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION CachedLogicalUnit;
|
|
|
|
//
|
|
// Interrupt level data storage.
|
|
//
|
|
|
|
INTERRUPT_DATA InterruptData;
|
|
|
|
//
|
|
// Whether or not an interrupt has occured since the last timeout.
|
|
// Used to determine if interrupts may not be getting delivered.
|
|
// This value must be set within KeSynchronizeExecution
|
|
//
|
|
|
|
ULONG WatchdogInterruptCount;
|
|
|
|
//
|
|
// SCSI Capabilities structure
|
|
//
|
|
|
|
IO_SCSI_CAPABILITIES Capabilities;
|
|
|
|
//
|
|
// Miniport timer object.
|
|
//
|
|
|
|
KTIMER MiniPortTimer;
|
|
|
|
//
|
|
// Miniport DPC for timer object.
|
|
//
|
|
|
|
KDPC MiniPortTimerDpc;
|
|
|
|
//
|
|
// Physical address of common buffer
|
|
//
|
|
|
|
PHYSICAL_ADDRESS PhysicalCommonBuffer;
|
|
|
|
//
|
|
// Buffers must be mapped into system space.
|
|
//
|
|
|
|
BOOLEAN MapBuffers;
|
|
|
|
//
|
|
// Buffers must be remapped into system space after IoMapTransfer has been
|
|
// called.
|
|
//
|
|
|
|
BOOLEAN RemapBuffers;
|
|
|
|
//
|
|
// Is this device a bus master and does it require map registers.
|
|
//
|
|
|
|
BOOLEAN MasterWithAdapter;
|
|
|
|
//
|
|
// Supports tagged queuing
|
|
//
|
|
|
|
BOOLEAN TaggedQueuing;
|
|
|
|
//
|
|
// Supports auto request sense.
|
|
//
|
|
|
|
BOOLEAN AutoRequestSense;
|
|
|
|
//
|
|
// Supports multiple requests per logical unit.
|
|
//
|
|
|
|
BOOLEAN MultipleRequestPerLu;
|
|
|
|
//
|
|
// Support receive event function.
|
|
//
|
|
|
|
BOOLEAN ReceiveEvent;
|
|
|
|
//
|
|
// Indicates an srb extension needs to be allocated.
|
|
//
|
|
|
|
BOOLEAN AllocateSrbExtension;
|
|
|
|
//
|
|
// Indicates the contorller caches data.
|
|
//
|
|
|
|
BOOLEAN CachesData;
|
|
|
|
//
|
|
// Indicates that the adapter can handle 64-bit DMA.
|
|
//
|
|
|
|
BOOLEAN Dma64BitAddresses;
|
|
|
|
//
|
|
// Indicates that the adapter can handle 32-bit DMA.
|
|
//
|
|
|
|
BOOLEAN Dma32BitAddresses;
|
|
|
|
//
|
|
// Queued WMI request items that are not in use.
|
|
//
|
|
INTERLOCKED SLIST_HEADER WmiFreeMiniPortRequestList;
|
|
KSPIN_LOCK WmiFreeMiniPortRequestLock;
|
|
INTERLOCKED ULONG WmiFreeMiniPortRequestWatermark;
|
|
INTERLOCKED ULONG WmiFreeMiniPortRequestCount;
|
|
BOOLEAN WmiFreeMiniPortRequestInitialized;
|
|
|
|
//
|
|
// Free WMI request items were exhausted at least once in the lifetime
|
|
// of this adapter (used to log error only once).
|
|
//
|
|
|
|
BOOLEAN WmiFreeMiniPortRequestsExhausted;
|
|
|
|
//
|
|
// This mutex is used to synchronize access & modification of the list
|
|
// of devices during enumeration & reporting.
|
|
//
|
|
|
|
KMUTEX EnumerationDeviceMutex;
|
|
|
|
//
|
|
// This fast-mutex is used to protect the enumeration work-item and
|
|
// the list of completion routines to be run once an enumeration is
|
|
// finished.
|
|
//
|
|
|
|
FAST_MUTEX EnumerationWorklistMutex;
|
|
|
|
//
|
|
// System time of the last bus scan. This is protected by the
|
|
// EnumerationWorkListMutex.
|
|
//
|
|
|
|
LARGE_INTEGER LastBusScanTime;
|
|
|
|
//
|
|
// Indicates that the next rescan which comes in should be "forced", ie.
|
|
// it should rescan no matter how recent the last one was.
|
|
//
|
|
|
|
INTERLOCKED LONG ForceNextBusScan;
|
|
|
|
//
|
|
// A work item to use in enumerating the bus.
|
|
//
|
|
|
|
WORK_QUEUE_ITEM EnumerationWorkItem;
|
|
|
|
//
|
|
// A pointer to the thread the workitem is running on. This is for
|
|
// debugging purposes.
|
|
//
|
|
|
|
PKTHREAD EnumerationWorkThread;
|
|
|
|
//
|
|
// If this is TRUE then there is already an enumeration worker thread
|
|
// running. If FALSE then the work item must be requeued. This flag is
|
|
// protected by the EnumerationWorklistMutex
|
|
//
|
|
|
|
BOOLEAN EnumerationRunning;
|
|
|
|
//
|
|
// A list of enumeration requests. When an bus scan is completed the
|
|
// scanner should run through the list of enumeration requests and complete
|
|
// each one. This list is protected by the EnumerationWorklistMutex.
|
|
//
|
|
|
|
PSP_ENUMERATION_REQUEST EnumerationWorkList;
|
|
|
|
//
|
|
// A pointer to the PNP enumeration request object. This is used so
|
|
// so we can use interlocked exchange to determine if the block is
|
|
// in use.
|
|
//
|
|
|
|
PSP_ENUMERATION_REQUEST PnpEnumRequestPtr;
|
|
|
|
//
|
|
// An enumeration request to use for PNP enumeration requests. Since there
|
|
// will only be one of these outstanding at any time we can statically
|
|
// allocate one for that case.
|
|
//
|
|
|
|
SP_ENUMERATION_REQUEST PnpEnumerationRequest;
|
|
|
|
//
|
|
// A lookaside list to pull SRB_DATA blocks off of.
|
|
//
|
|
|
|
NPAGED_LOOKASIDE_LIST SrbDataLookasideList;
|
|
|
|
//
|
|
// The following members are used to keep an SRB_DATA structure allocated
|
|
// for emergency use and to queue requests which need to use it. The
|
|
// structures are synchronized with the EmergencySrbDataSpinLock.
|
|
// The routines Sp[Allocate|Free]SrbData & ScsiPortTickHandler will
|
|
// handle queueing and eventual restarting of these requests.
|
|
//
|
|
|
|
//
|
|
// This spinlock protects the blocked request list.
|
|
//
|
|
|
|
KSPIN_LOCK EmergencySrbDataSpinLock;
|
|
|
|
//
|
|
// Contains a queue of irps which could not be dispatched because of
|
|
// low memory conditions and because the EmergencySrbData block is already
|
|
// allocated.
|
|
//
|
|
|
|
LIST_ENTRY SrbDataBlockedRequests;
|
|
|
|
//
|
|
// The SRB_DATA reserved for "emergency" use. This pointer should be set
|
|
// to NULL if the SRB_DATA is in use. Any SRB_DATA block may be used
|
|
// for the emergency request.
|
|
//
|
|
|
|
INTERLOCKED PSRB_DATA EmergencySrbData;
|
|
|
|
//
|
|
// Flags to indicate whether the srbdata and scatter gather lookaside
|
|
// lists have been allocated already.
|
|
//
|
|
|
|
BOOLEAN SrbDataListInitialized;
|
|
|
|
//
|
|
// Bus standard interface. Retrieved from the lower driver immediately
|
|
// after it completes the start irp.
|
|
//
|
|
|
|
BOOLEAN LowerBusInterfaceStandardRetrieved;
|
|
BUS_INTERFACE_STANDARD LowerBusInterfaceStandard;
|
|
|
|
//
|
|
// Handles into the device map for the various entries this adapter will
|
|
// have created.
|
|
//
|
|
|
|
//
|
|
// An array of handles for each
|
|
|
|
HANDLE PortDeviceMapKey;
|
|
|
|
PDEVICE_MAP_HANDLES BusDeviceMapKeys;
|
|
|
|
//
|
|
// Unicode string containing the device name of this object
|
|
//
|
|
|
|
PWSTR DeviceName;
|
|
|
|
//
|
|
// The guid for the underlying bus. Saved here so we don't have to
|
|
// retrieve it so often.
|
|
//
|
|
|
|
GUID BusTypeGuid;
|
|
|
|
//
|
|
// The pnp interface name for this device.
|
|
//
|
|
|
|
UNICODE_STRING InterfaceName;
|
|
|
|
//
|
|
// The device state for this adapter.
|
|
//
|
|
|
|
PNP_DEVICE_STATE DeviceState;
|
|
|
|
//
|
|
// The number of calls to ScsiPortTickHandler for this adapter since
|
|
// the machine was booted.
|
|
//
|
|
|
|
INTERLOCKED ULONG TickCount;
|
|
|
|
//
|
|
// Preallocated memory to use for IssueInquiry. The InquiryBuffer is used
|
|
// to retreive the inquiry data and the serial number for the device.
|
|
//
|
|
|
|
PVOID InquiryBuffer;
|
|
PSENSE_DATA InquirySenseBuffer;
|
|
PIRP InquiryIrp;
|
|
PMDL InquiryMdl;
|
|
|
|
//
|
|
// Mutex used to synchronize multiple threads all synchronously waiting for
|
|
// a power up to occur.
|
|
//
|
|
|
|
FAST_MUTEX PowerMutex;
|
|
|
|
//
|
|
// A pointer to a logical unit which is used to scan empty locations on the
|
|
// bus.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION RescanLun;
|
|
|
|
//
|
|
// The number of additional sense bytes supported by this adapter.
|
|
//
|
|
|
|
UCHAR AdditionalSenseBytes;
|
|
|
|
//
|
|
// Indicates whether the SenseData WMI event is enabled.
|
|
//
|
|
|
|
BOOLEAN EnableSenseDataEvent;
|
|
|
|
//
|
|
// Identifies the event class used to generate sense data wmi events.
|
|
//
|
|
|
|
GUID SenseDataEventClass;
|
|
|
|
//
|
|
// Pointer to verifier state that gets allocated and initialized when
|
|
// scsiport's verifier is enabled.
|
|
//
|
|
|
|
PVERIFIER_EXTENSION VerifierExtension;
|
|
|
|
//
|
|
// The minimum & maximum addresses for common buffer. These are loaded
|
|
// from [Minimum|Maximum]UCXAddress in the registry.
|
|
//
|
|
|
|
PHYSICAL_ADDRESS MinimumCommonBufferBase;
|
|
PHYSICAL_ADDRESS MaximumCommonBufferBase;
|
|
|
|
#if defined(FORWARD_PROGRESS)
|
|
//
|
|
// Pointer to a block of reserved pages we use to make forward progress
|
|
// in low memory conditons.
|
|
//
|
|
|
|
PVOID ReservedPages;
|
|
|
|
//
|
|
// Pointer to an emergency MDL we can use if we cannot allocate one
|
|
//
|
|
|
|
PMDL ReservedMdl;
|
|
#endif
|
|
|
|
//
|
|
// Identified how many successfully completed requests are required to
|
|
// restore a LUN on this adapter from a degraded performation state
|
|
// with respect to MaxQueueDepth.
|
|
//
|
|
|
|
ULONG RemainInReducedMaxQueueState;
|
|
|
|
//
|
|
// This value dictates on what type of boundary an adapter's uncached extension
|
|
// must be aligned.
|
|
//
|
|
|
|
ULONG UncachedExtAlignment;
|
|
|
|
//
|
|
// This value is used to keep track of the number of instances of the
|
|
// SRB_DATA free routine is running. This helps us avoid a nasty recursion
|
|
// brought on by synchronously completing requests and starting blocked
|
|
// requests waiting for SRB_DATA objects.
|
|
//
|
|
|
|
LONG SrbDataFreeRunning;
|
|
|
|
//
|
|
// This is the timeout value we put into INQUIRY SRBs. Some devices are
|
|
// known to take longer than the default 4 seconds to respond.
|
|
//
|
|
|
|
ULONG SrbTimeout;
|
|
|
|
//
|
|
// This boolean indicates whether the adapter supports multiple concurrent
|
|
// requests. This means it either supports tagged queuing or multiple
|
|
// requests per logical unit.
|
|
//
|
|
|
|
BOOLEAN SupportsMultipleRequests;
|
|
|
|
//
|
|
// This is the size of the preallocated SG buffer contained in each
|
|
// SRB_DATA structure allocated for this adapter. We pass this value to
|
|
// the HAL when we supply our own SG buffer.
|
|
//
|
|
|
|
ULONG SgBufferLen;
|
|
|
|
//
|
|
// This is the number of seconds we hold requests for following a bus
|
|
// reset.
|
|
//
|
|
|
|
ULONG ResetHoldTime;
|
|
|
|
//
|
|
// Array of LU extensions representing the initiator for each bus.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION InitiatorLU[8];
|
|
|
|
//
|
|
// Inidicates whether the adapter is configured to have a logical unit
|
|
// created for the initiator on each supported bus.
|
|
//
|
|
|
|
BOOLEAN CreateInitiatorLU;
|
|
|
|
//
|
|
// Used to chain Logical units having blocked requests.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION BlockedLogicalUnit;
|
|
};
|
|
|
|
struct _LOGICAL_UNIT_EXTENSION {
|
|
|
|
union {
|
|
PDEVICE_OBJECT DeviceObject;
|
|
COMMON_EXTENSION CommonExtension;
|
|
};
|
|
|
|
//
|
|
// Logical Unit flags
|
|
//
|
|
|
|
ULONG LuFlags;
|
|
|
|
//
|
|
// The adapter number this device is attached to
|
|
//
|
|
|
|
ULONG PortNumber;
|
|
|
|
//
|
|
// Has this device been claimed by a driver (legacy or pnp)
|
|
//
|
|
|
|
BOOLEAN IsClaimed;
|
|
|
|
BOOLEAN IsLegacyClaim;
|
|
|
|
//
|
|
// Has this device been enumerated yet? If so then we cannot actually
|
|
// delete it until we've explicitly told the PNP system that it's gone
|
|
// (by not enumerating it)
|
|
//
|
|
|
|
BOOLEAN IsEnumerated;
|
|
|
|
//
|
|
// Has this device gone missing?
|
|
//
|
|
|
|
BOOLEAN IsMissing;
|
|
|
|
//
|
|
// Is this device visible - should it be exposed to PNP?
|
|
//
|
|
|
|
BOOLEAN IsVisible;
|
|
|
|
//
|
|
// Was this device marked missing because we found something different at
|
|
// it's bus location? If so then the removal of this device from the
|
|
// logical unit bins will trigger a new bus scan.
|
|
//
|
|
|
|
BOOLEAN IsMismatched;
|
|
|
|
//
|
|
// Is this lun temporary? Temporary luns are used to scan bus locations
|
|
// which are believed to be empty. They are the only luns which can be
|
|
// swapped out of the logical unit list.
|
|
//
|
|
|
|
BOOLEAN IsTemporary;
|
|
|
|
//
|
|
// Indicates that this device needs to have an inquiry sent to it to
|
|
// determine if it's still present. This flag is cleared if the inquiry
|
|
// succeeds and the inquiry data matches what was previously read at that
|
|
// address. If this flag is set when SpPurgeTarget is called then the
|
|
// lun will be marked as missing.
|
|
//
|
|
|
|
ULONG NeedsVerification;
|
|
|
|
//
|
|
// The bus address of this device.
|
|
//
|
|
|
|
UCHAR PathId;
|
|
UCHAR TargetId;
|
|
UCHAR Lun;
|
|
|
|
//
|
|
// The number of times the current busy request has been retried
|
|
//
|
|
|
|
UCHAR RetryCount;
|
|
|
|
//
|
|
// The current queue sort key
|
|
//
|
|
|
|
ULONG CurrentKey;
|
|
|
|
//
|
|
// A pointer to the miniport's logical unit extension.
|
|
//
|
|
|
|
PVOID HwLogicalUnitExtension;
|
|
|
|
//
|
|
// A pointer to the device extension for the adapter.
|
|
//
|
|
|
|
PADAPTER_EXTENSION AdapterExtension;
|
|
|
|
//
|
|
// The number of unreleased queue locks on this device
|
|
//
|
|
|
|
ULONG QueueLockCount;
|
|
|
|
//
|
|
// Reference counts for pausing & unpausing the queue (see LU_QUEUE_PAUSED)
|
|
//
|
|
|
|
ULONG QueuePauseCount;
|
|
|
|
//
|
|
// List of lock & unlock requests which are waiting to be dispatched.
|
|
//
|
|
|
|
KDEVICE_QUEUE LockRequestQueue;
|
|
|
|
//
|
|
// The currently operating lock request.
|
|
//
|
|
|
|
PSRB_DATA CurrentLockRequest;
|
|
|
|
//
|
|
// A pointer to the next logical unit extension in the logical unit bin.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION NextLogicalUnit;
|
|
|
|
//
|
|
// Used to chain logical units in the interrupt data block.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION ReadyLogicalUnit;
|
|
|
|
//
|
|
// Used to chain completed abort requests in the interrupt data block.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION CompletedAbort;
|
|
|
|
//
|
|
// The current abort request for this logical unit
|
|
//
|
|
|
|
PSCSI_REQUEST_BLOCK AbortSrb;
|
|
|
|
//
|
|
// Timeout counter for this logical unit
|
|
//
|
|
|
|
LONG RequestTimeoutCounter;
|
|
|
|
//
|
|
// The list of requests for this logical unit.
|
|
//
|
|
|
|
LIST_ENTRY RequestList;
|
|
|
|
//
|
|
// The next request to be executed.
|
|
//
|
|
|
|
PSRB_DATA PendingRequest;
|
|
|
|
//
|
|
// This irp could not be executed before because the
|
|
// device returned BUSY.
|
|
//
|
|
|
|
PSRB_DATA BusyRequest;
|
|
|
|
//
|
|
// The current untagged request for this logical unit.
|
|
//
|
|
|
|
PSRB_DATA CurrentUntaggedRequest;
|
|
|
|
//
|
|
// The maximum number of request which we will issue to the device
|
|
//
|
|
|
|
UCHAR MaxQueueDepth;
|
|
|
|
//
|
|
// The current number of outstanding requests.
|
|
//
|
|
|
|
UCHAR QueueCount;
|
|
|
|
//
|
|
// The inquiry data for this logical unit.
|
|
//
|
|
|
|
INQUIRYDATA InquiryData;
|
|
|
|
//
|
|
// The handles for the target & logical unit keys in the device map.
|
|
//
|
|
|
|
HANDLE TargetDeviceMapKey;
|
|
HANDLE LunDeviceMapKey;
|
|
|
|
//
|
|
// Our fixed set of SRB_DATA blocks for use when processing bypass requests.
|
|
// If this set is exhausted then scsiport will bugcheck - this should be
|
|
// okay since bypass requests are only sent in certain extreme conditions
|
|
// and should never be overlapped (we should only see one bypass request
|
|
// at a time).
|
|
//
|
|
|
|
SRB_DATA BypassSrbDataBlocks[NUMBER_BYPASS_SRB_DATA_BLOCKS];
|
|
|
|
//
|
|
// A list of the free bypass SRB_DATA blocks.
|
|
//
|
|
|
|
KSPIN_LOCK BypassSrbDataSpinLock;
|
|
SLIST_HEADER BypassSrbDataList;
|
|
|
|
//
|
|
// A pointer to the request for which we have issued a request-sense irp
|
|
// (if any). This field is protected by the port spinlock.
|
|
//
|
|
|
|
PSRB_DATA ActiveFailedRequest;
|
|
|
|
//
|
|
// A pointer to the request for which we need to issue a request-sense irp
|
|
// (if any). RequestSenseCompletion will promote this to the active
|
|
// failed request and issue a new RS operation when it runs.
|
|
// This field is protected by the port spinlock.
|
|
//
|
|
|
|
PSRB_DATA BlockedFailedRequest;
|
|
|
|
//
|
|
// Resources for issuing request-sense commands.
|
|
//
|
|
|
|
PIRP RequestSenseIrp;
|
|
SCSI_REQUEST_BLOCK RequestSenseSrb;
|
|
|
|
struct {
|
|
MDL RequestSenseMdl;
|
|
PFN_NUMBER RequestSenseMdlPfn1;
|
|
PFN_NUMBER RequestSenseMdlPfn2;
|
|
};
|
|
|
|
//
|
|
// The "lun-list" associated with this target. SpIssueReportLuns will
|
|
// store this value in the logical unit extension for LUN 0 of each target
|
|
// for use in the event that we are unable to retrieve it from the LUN.
|
|
//
|
|
|
|
PLUN_LIST TargetLunList;
|
|
|
|
//
|
|
// The special controller flags for this target. These flags are valid
|
|
// for LUN 0 only.
|
|
//
|
|
|
|
SP_SPECIAL_CONTROLLER_FLAGS SpecialFlags;
|
|
|
|
//
|
|
// Flags to keep track of what EVPD pages this device supports.
|
|
//
|
|
|
|
BOOLEAN DeviceIdentifierPageSupported : 1;
|
|
BOOLEAN SerialNumberPageSupported : 1;
|
|
|
|
//
|
|
// The vital product data for this device - this buffer contains the
|
|
// device serial number. The other fields contain the length of the
|
|
// data in the buffer and the page code used to retrieve this buffer.
|
|
//
|
|
|
|
ANSI_STRING SerialNumber;
|
|
|
|
//
|
|
// The device identifier page retreived from the device's vital product
|
|
// data.
|
|
//
|
|
|
|
PVPD_IDENTIFICATION_PAGE DeviceIdentifierPage;
|
|
ULONG DeviceIdentifierPageLength;
|
|
|
|
//
|
|
// If we reduce the MaxQueueDepth, track how long we remain in the degraded
|
|
// state. If we reach a configurable number of ticks we restore ourselves
|
|
// to full power.
|
|
//
|
|
|
|
ULONG TicksInReducedMaxQueueDepthState;
|
|
|
|
#if defined(NEWQUEUE)
|
|
//
|
|
// Capacity of this LU in sectors.
|
|
//
|
|
|
|
ULONG Capacity;
|
|
|
|
//
|
|
// The number of zones we divide the LU into.
|
|
//
|
|
|
|
ULONG Zones;
|
|
|
|
//
|
|
// The number of sectors per zone.
|
|
//
|
|
|
|
ULONG ZoneLength;
|
|
|
|
//
|
|
// This array holds each zone's first sector.
|
|
//
|
|
|
|
ULONG FirstSector[4];
|
|
|
|
//
|
|
// This array holds each zone's last sector.
|
|
//
|
|
|
|
ULONG LastSector[4];
|
|
|
|
//
|
|
// Tracks the number of requests per zone.
|
|
//
|
|
|
|
ULONG64 RequestCount[4];
|
|
|
|
//
|
|
// The media is divided into a number of zones. This value identifies
|
|
// which zone the port driver is currently servicing.
|
|
//
|
|
|
|
ULONG CurrentZone;
|
|
|
|
//
|
|
// The value tracks the number of requests we perform in each zone.
|
|
//
|
|
|
|
ULONG ZoneCount;
|
|
|
|
//
|
|
// Tracks the current location in each zone.
|
|
//
|
|
|
|
ULONG ZonePointer[4];
|
|
|
|
//
|
|
// Tracks the number of consecutive requests for the same sector.
|
|
//
|
|
|
|
UCHAR RedundantRequests[4];
|
|
|
|
//
|
|
// Table mapping current zone to next zone.
|
|
//
|
|
|
|
ULONG NextSequentialZone[4];
|
|
#endif // NEWQUEUE
|
|
|
|
//
|
|
// Maintain a circular buffer of the last 10 IO requests.
|
|
//
|
|
|
|
ULONG IoLogIndex;
|
|
ULONG IoLogEntries;
|
|
SP_LUN_IO_LOG IoLog[10];
|
|
|
|
//
|
|
// Used to chain Logical units having blocked requests.
|
|
//
|
|
|
|
PLOGICAL_UNIT_EXTENSION BlockedLogicalUnit;
|
|
|
|
//
|
|
// Contains a queue of irps which could not be dispatched because of
|
|
// low memory conditions and because the EmergencySrbData block is already
|
|
// allocated.
|
|
//
|
|
|
|
LIST_ENTRY SrbDataBlockedRequests;
|
|
};
|
|
|
|
#if defined(NEWQUEUE)
|
|
ULONG
|
|
INLINE
|
|
GetZone(
|
|
IN PLOGICAL_UNIT_EXTENSION Lun,
|
|
IN ULONG Sector
|
|
)
|
|
{
|
|
ULONG i;
|
|
for (i = 0; i < Lun->Zones; i++) {
|
|
if (Sector <= Lun->LastSector[i]) {
|
|
return i;
|
|
}
|
|
}
|
|
ASSERT(FALSE);
|
|
return (Lun->Zones - 1);
|
|
}
|
|
#endif // NEWQUEUE
|
|
|
|
//
|
|
// Miniport specific device extension wrapper
|
|
//
|
|
|
|
struct _HW_DEVICE_EXTENSION {
|
|
PADAPTER_EXTENSION FdoExtension;
|
|
UCHAR HwDeviceExtension[0];
|
|
};
|
|
|
|
typedef struct _INTERRUPT_CONTEXT {
|
|
PADAPTER_EXTENSION DeviceExtension;
|
|
PINTERRUPT_DATA SavedInterruptData;
|
|
}INTERRUPT_CONTEXT, *PINTERRUPT_CONTEXT;
|
|
|
|
typedef struct _RESET_CONTEXT {
|
|
PADAPTER_EXTENSION DeviceExtension;
|
|
UCHAR PathId;
|
|
}RESET_CONTEXT, *PRESET_CONTEXT;
|
|
|
|
//
|
|
// Used in LUN rescan determination.
|
|
//
|
|
|
|
typedef struct _UNICODE_LUN_LIST {
|
|
UCHAR TargetId;
|
|
struct _UNICODE_LUN_LIST *Next;
|
|
UNICODE_STRING UnicodeInquiryData;
|
|
} UNICODE_LUN_LIST, *PUNICODE_LUN_LIST;
|
|
|
|
typedef struct _POWER_CHANGE_CONTEXT {
|
|
PDEVICE_OBJECT DeviceObject;
|
|
POWER_STATE_TYPE Type;
|
|
POWER_STATE State;
|
|
PIRP OriginalIrp;
|
|
PSCSI_REQUEST_BLOCK Srb;
|
|
} POWER_CHANGE_CONTEXT, *PPOWER_CHANGE_CONTEXT;
|
|
|
|
//
|
|
// Driver extension
|
|
//
|
|
|
|
struct _SP_INIT_CHAIN_ENTRY {
|
|
HW_INITIALIZATION_DATA InitData;
|
|
PSP_INIT_CHAIN_ENTRY NextEntry;
|
|
};
|
|
|
|
typedef struct _SCSIPORT_INTERFACE_TYPE_DATA {
|
|
INTERFACE_TYPE InterfaceType;
|
|
ULONG Flags;
|
|
} SCSIPORT_INTERFACE_TYPE_DATA, *PSCSIPORT_INTERFACE_TYPE_DATA;
|
|
|
|
typedef struct _SCSIPORT_DRIVER_EXTENSION {
|
|
|
|
//
|
|
// Pointer back to the driver object
|
|
//
|
|
|
|
PDRIVER_OBJECT DriverObject;
|
|
|
|
//
|
|
// Unicode string containing the registry path information
|
|
// for this driver
|
|
//
|
|
|
|
UNICODE_STRING RegistryPath;
|
|
|
|
UNICODE_STRING MPIOSupportedDeviceList;
|
|
|
|
//
|
|
// the chain of HwInitializationData structures that were passed in during
|
|
// the miniport's initialization
|
|
//
|
|
|
|
PSP_INIT_CHAIN_ENTRY InitChain;
|
|
|
|
//
|
|
// A count of the number of adapter which are using scsiport. This is
|
|
// used for generating unique Id's
|
|
//
|
|
|
|
ULONG AdapterCount;
|
|
|
|
//
|
|
// The bus type for this driver.
|
|
//
|
|
|
|
STORAGE_BUS_TYPE BusType;
|
|
|
|
//
|
|
// Flag indicating whether this miniport is set to do device detection.
|
|
// This flag will be initialized out of the registry when the driver
|
|
// extension is setup.
|
|
//
|
|
|
|
BOOLEAN LegacyAdapterDetection;
|
|
|
|
//
|
|
// The list of pnp interface values we read out of the registry for this
|
|
// device. The number of entries here can vary.
|
|
//
|
|
|
|
ULONG PnpInterfaceCount;
|
|
|
|
//
|
|
// The number of interfaces which are safe for pnp.
|
|
//
|
|
|
|
ULONG SafeInterfaceCount;
|
|
|
|
//
|
|
// A pointer to a reserve error log entry for the driver. This entry will
|
|
// be used to log an allocation failure if the logging routine cannot
|
|
// allocate the necessary memory for an error log entry.
|
|
//
|
|
|
|
PVOID ReserveAllocFailureLogEntry;
|
|
|
|
//
|
|
// Indicates whether the driver is being verified.
|
|
//
|
|
|
|
ULONG Verifying;
|
|
|
|
//
|
|
// When verifying, we occasionally set pointers so they point to a page
|
|
// of invalid memory so the system will bugcheck if a miniport attempts
|
|
// to access the memory. The following 3 variables are used to maintain
|
|
// this invalid page.
|
|
//
|
|
|
|
PVOID UnusedPage;
|
|
PMDL UnusedPageMdl;
|
|
PVOID InvalidPage;
|
|
|
|
SCSIPORT_INTERFACE_TYPE_DATA PnpInterface[0];
|
|
|
|
//
|
|
// The remaining pnp interface flags trail the defined structure
|
|
//
|
|
|
|
} SCSIPORT_DRIVER_EXTENSION, *PSCSIPORT_DRIVER_EXTENSION;
|
|
|
|
|
|
//
|
|
// Port driver extension flags.
|
|
// These flags are protected by the adapter spinlock.
|
|
//
|
|
|
|
//
|
|
// This flag indicates that a request has been passed to the miniport and the
|
|
// miniport has not indicated it is ready for another request. It is set by
|
|
// SpStartIoSynchronized. It is cleared by ScsiPortCompletionDpc when the
|
|
// miniport asks for another request. Note the port driver will defer giving
|
|
// the miniport driver a new request if the current request disabled disconnects.
|
|
//
|
|
|
|
#define PD_DEVICE_IS_BUSY 0X00001
|
|
|
|
//
|
|
// Indicates there is a pending request for which resources
|
|
// could not be allocated. This flag is set by SpAllocateRequestStructures
|
|
// which is called from ScsiPortStartIo. It is cleared by
|
|
// SpProcessCompletedRequest when a request completes which then calls
|
|
// ScsiPortStartIo to try the request again.
|
|
//
|
|
|
|
#define PD_PENDING_DEVICE_REQUEST 0X00800
|
|
|
|
//
|
|
// This flag indicates that there are currently no requests executing with
|
|
// disconnects disabled. This flag is normally on. It is cleared by
|
|
// SpStartIoSynchronized when a request with disconnect disabled is started
|
|
// and is set when that request completes. SpProcessCompletedRequest will
|
|
// start the next request for the miniport if PD_DEVICE_IS_BUSY is clear.
|
|
//
|
|
|
|
#define PD_DISCONNECT_RUNNING 0X01000
|
|
|
|
//
|
|
// Indicates the miniport wants the system interrupts disabled. Set by
|
|
// ScsiPortNofitication and cleared by ScsiPortCompletionDpc. This flag is
|
|
// NOT stored in the interrupt data structure. The parameters are stored in
|
|
// the device extension.
|
|
//
|
|
|
|
#define PD_DISABLE_CALL_REQUEST 0X02000
|
|
|
|
//
|
|
// Indicates that the miniport is being reinitialized. This is set and
|
|
// cleared by SpReinitializeAdapter is is tested by some of the ScsiPort APIs.
|
|
//
|
|
|
|
#define PD_MINIPORT_REINITIALIZING 0x40000
|
|
#define PD_UNCACHED_EXTENSION_RETURNED 0x80000
|
|
|
|
//
|
|
// Interrupt Data Flags
|
|
// These flags are protected by the interrupt spinlock.
|
|
//
|
|
|
|
//
|
|
// Indicates that ScsiPortCompletionDpc needs to be run. This is set when
|
|
// A miniport makes a request which must be done at DPC and is cleared when
|
|
// when the request information is gotten by SpGetInterruptState.
|
|
//
|
|
|
|
#define PD_NOTIFICATION_REQUIRED 0X00004
|
|
|
|
//
|
|
// Indicates the miniport is ready for another request. Set by
|
|
// ScsiPortNotification and cleared by SpGetInterruptState. This flag is
|
|
// stored in the interrupt data structure.
|
|
//
|
|
|
|
#define PD_READY_FOR_NEXT_REQUEST 0X00008
|
|
|
|
//
|
|
// Indicates the miniport wants the adapter channel flushed. Set by
|
|
// ScsiPortFlushDma and cleared by SpGetInterruptState. This flag is
|
|
// stored in the data interrupt structure. The flush adapter parameters
|
|
// are saved in the device object.
|
|
//
|
|
|
|
#define PD_FLUSH_ADAPTER_BUFFERS 0X00010
|
|
|
|
//
|
|
// Indicates the miniport wants the adapter channel programmed. Set by
|
|
// ScsiPortIoMapTransfer and cleared by SpGetInterruptState or
|
|
// ScsiPortFlushDma. This flag is stored in the interrupt data structure.
|
|
// The I/O map transfer parameters are saved in the interrupt data structure.
|
|
//
|
|
|
|
#define PD_MAP_TRANSFER 0X00020
|
|
|
|
//
|
|
// Indicates the miniport wants to log an error. Set by
|
|
// ScsiPortLogError and cleared by SpGetInterruptState. This flag is
|
|
// stored in the interrupt data structure. The error log parameters
|
|
// are saved in the interrupt data structure. Note at most one error per DPC
|
|
// can be logged.
|
|
//
|
|
|
|
#define PD_LOG_ERROR 0X00040
|
|
|
|
//
|
|
// Indicates that no request should be sent to the miniport after
|
|
// a bus reset. Set when the miniport reports a reset or the port driver
|
|
// resets the bus. It is cleared by SpTimeoutSynchronized. The
|
|
// PortTimeoutCounter is used to time the length of the reset hold. This flag
|
|
// is stored in the interrupt data structure.
|
|
//
|
|
|
|
#define PD_RESET_HOLD 0X00080
|
|
|
|
//
|
|
// Indicates a request was stopped due to a reset hold. The held request is
|
|
// stored in the current request of the device object. This flag is set by
|
|
// SpStartIoSynchronized and cleared by SpTimeoutSynchronized which also
|
|
// starts the held request when the reset hold has ended. This flag is stored
|
|
// in the interrupt data structure.
|
|
//
|
|
|
|
#define PD_HELD_REQUEST 0X00100
|
|
|
|
//
|
|
// Indicates the miniport has reported a bus reset. Set by
|
|
// ScsiPortNotification and cleared by SpGetInterruptState. This flag is
|
|
// stored in the interrupt data structure.
|
|
//
|
|
|
|
#define PD_RESET_REPORTED 0X00200
|
|
|
|
//
|
|
// Indicates that system interrupts have been enabled and that the miniport
|
|
// has disabled its adapter from interruptint. The miniport's interrupt
|
|
// routine is not called while this flag is set. This flag is set by
|
|
// ScsiPortNotification when a CallEnableInterrupts request is made and
|
|
// cleared by SpEnableInterruptSynchronized when the miniport requests that
|
|
// system interrupts be disabled. This flag is stored in the interrupt data
|
|
// structure.
|
|
//
|
|
|
|
#define PD_DISABLE_INTERRUPTS 0X04000
|
|
|
|
//
|
|
// Indicates the miniport wants the system interrupt enabled. Set by
|
|
// ScsiPortNotification and cleared by SpGetInterruptState. This flag is
|
|
// stored in the interrupt data structure. The call enable interrupts
|
|
// parameters are saved in the device extension.
|
|
//
|
|
|
|
#define PD_ENABLE_CALL_REQUEST 0X08000
|
|
|
|
//
|
|
// Indicates the miniport is wants a timer request. Set by
|
|
// ScsiPortNotification and cleared by SpGetInterruptState. This flag is
|
|
// stored in the interrupt data structure. The timer request parameters are
|
|
// stored in the interrupt data structure.
|
|
//
|
|
|
|
#define PD_TIMER_CALL_REQUEST 0X10000
|
|
|
|
//
|
|
// Indicates the miniport has a WMI request. Set by ScsiPortNotification
|
|
// and cleared by SpGetInterruptState. This flag is stored in the interrupt
|
|
// data structure. The WMI request parameters are stored in the interrupt
|
|
// data structure.
|
|
//
|
|
|
|
#define PD_WMI_REQUEST 0X20000
|
|
|
|
//
|
|
// Indicates that the miniport has detected some sort of change on the bus -
|
|
// usually device arrival or removal - and wishes the port driver to rescan
|
|
// the bus.
|
|
//
|
|
|
|
#define PD_BUS_CHANGE_DETECTED 0x40000
|
|
|
|
//
|
|
// Indicates that the adapter has disappeared. If this flag is set then no
|
|
// calls should be made into the miniport.
|
|
//
|
|
|
|
#define PD_ADAPTER_REMOVED 0x80000
|
|
|
|
//
|
|
// Indicates that interrupts from the miniport do not appear to be getting
|
|
// delivered to scsiport. This flag is set by SpTimeoutSynchronized and
|
|
// will cause the DPC routine to log an error to this effect.
|
|
//
|
|
|
|
#define PD_INTERRUPT_FAILURE 0x100000
|
|
|
|
#if defined(FORWARD_PROGRESS)
|
|
//
|
|
// Indicates that the adapter's reserved pages are currently in use. The
|
|
// reserved pages is a special VA range set aside by MM in order for devices
|
|
// to make forward progress in low memory conditions.
|
|
//
|
|
|
|
#define PD_RESERVED_PAGES_IN_USE 0x200000
|
|
|
|
//
|
|
// Indicates that the adapter's reserved MDL is currently in use.
|
|
//
|
|
#define PD_RESERVED_MDL_IN_USE 0x400000
|
|
#endif
|
|
|
|
//
|
|
// Indicates that the adapter is in the process of shutting down. Certain
|
|
// operations must not be started when this is the case.
|
|
//
|
|
#define PD_SHUTDOWN_IN_PROGRESS 0x800000
|
|
|
|
//
|
|
// The following flags should not be cleared from the interrupt data structure
|
|
// by SpGetInterruptState.
|
|
//
|
|
|
|
#define PD_INTERRUPT_FLAG_MASK (PD_RESET_HOLD | PD_HELD_REQUEST | PD_DISABLE_INTERRUPTS | PD_ADAPTER_REMOVED)
|
|
|
|
//
|
|
// Adapter extension flags for DPC routine.
|
|
//
|
|
|
|
//
|
|
// Indicates that the completion DPC is either already running or has been
|
|
// queued to service completed requests. This flag is checked when the
|
|
// completion DPC needs to be run - the DPC should only be started if this
|
|
// flag is already clear. It will be cleared when the DPC has completed
|
|
// processing any work items.
|
|
//
|
|
|
|
#define PD_DPC_RUNNING 0x20000
|
|
|
|
//
|
|
// Logical unit extension flags.
|
|
//
|
|
|
|
//
|
|
// Indicates the logical unit queue is frozen. Set by
|
|
// SpProcessCompletedRequest when an error occurs and is cleared by the class
|
|
// driver.
|
|
//
|
|
|
|
#define LU_QUEUE_FROZEN 0X0001
|
|
|
|
//
|
|
// Indicates that the miniport has an active request for this logical unit.
|
|
// Set by SpStartIoSynchronized when the request is started and cleared by
|
|
// GetNextLuRequest. This flag is used to track when it is ok to start another
|
|
// request from the logical unit queue for this device.
|
|
//
|
|
|
|
#define LU_LOGICAL_UNIT_IS_ACTIVE 0X0002
|
|
|
|
//
|
|
// Indicates that a request for this logical unit has failed and a REQUEST
|
|
// SENSE command needs to be done. This flag prevents other requests from
|
|
// being started until an untagged, by-pass queue command is started. This
|
|
// flag is cleared in SpStartIoSynchronized. It is set by
|
|
// SpGetInterruptState.
|
|
//
|
|
|
|
#define LU_NEED_REQUEST_SENSE 0X0004
|
|
|
|
//
|
|
// Indicates that a request for this logical unit has completed with a status
|
|
// of BUSY or QUEUE FULL. This flag is set by SpProcessCompletedRequest and
|
|
// the busy request is saved in the logical unit structure. This flag is
|
|
// cleared by ScsiPortTickHandler which also restarts the request. Busy
|
|
// request may also be requeued to the logical unit queue if an error occurs
|
|
// on the device (This will only occur with command queueing.). Not busy
|
|
// requests are nasty because they are restarted asynchronously by
|
|
// ScsiPortTickHandler rather than GetNextLuRequest. This makes error recovery
|
|
// more complex.
|
|
//
|
|
|
|
#define LU_LOGICAL_UNIT_IS_BUSY 0X0008
|
|
|
|
//
|
|
// This flag indicates a queue full has been returned by the device. It is
|
|
// similar to PD_LOGICAL_UNIT_IS_BUSY but is set in SpGetInterruptState when
|
|
// a QUEUE FULL status is returned. This flag is used to prevent other
|
|
// requests from being started for the logical unit before
|
|
// SpProcessCompletedRequest has a chance to set the busy flag.
|
|
//
|
|
|
|
#define LU_QUEUE_IS_FULL 0X0010
|
|
|
|
//
|
|
// Indicates that there is a request for this logical unit which cannot be
|
|
// executed for now. This flag is set by SpAllocateRequestStructures. It is
|
|
// cleared by GetNextLuRequest when it detects that the pending request
|
|
// can now be executed. The pending request is stored in the logical unit
|
|
// structure. A new single non-queued reqeust cannot be executed on a logical
|
|
// that is currently executing queued requests. Non-queued requests must wait
|
|
// unit for all queued requests to complete. A non-queued requests is one
|
|
// which is not tagged and does not have SRB_FLAGS_NO_QUEUE_FREEZE set.
|
|
// Normally only read and write commands can be queued.
|
|
//
|
|
|
|
#define LU_PENDING_LU_REQUEST 0x0020
|
|
|
|
//
|
|
// Indicates that the logical unit queue has been paused due to an error. Set
|
|
// by SpProcessCompletedRequest when an error occurs and is cleared by the
|
|
// class driver either by unfreezing or flushing the queue. This flag is used
|
|
// with the following one to determine why the logical unit queue is paused.
|
|
//
|
|
|
|
#define LU_QUEUE_LOCKED 0x0040
|
|
|
|
//
|
|
// Indicates that this LUN has been "paused". This flag is set and cleared by
|
|
// the power management code while changing the power state. It causes
|
|
// GetNextLuRequest to return without starting another request and is used
|
|
// by SpSrbIsBypassRequest to determine that a bypass request should get
|
|
// shoved to the front of the line.
|
|
//
|
|
|
|
#define LU_QUEUE_PAUSED 0x0080
|
|
|
|
//
|
|
// Indicates that the LUN is operating in a degraded state. The maximum queue
|
|
// depth has been reduced because the LUN has returned QUEUE FULL status. We
|
|
// track this because in the event that the QUEUE FULL was transient, we want
|
|
// to restore the queue depth to it's original maximum.
|
|
|
|
#define LU_PERF_MAXQDEPTH_REDUCED 0x0100
|
|
|
|
//
|
|
// SRB_DATA flags.
|
|
//
|
|
|
|
//
|
|
// Indicates that the srb_data block was for a bypass request
|
|
//
|
|
|
|
#define SRB_DATA_BYPASS_REQUEST 0x10000000
|
|
|
|
#if defined(FORWARD_PROGRESS)
|
|
//
|
|
// Indicates that the request is using reserved pages that enable
|
|
// forward progress in low-memory condition.
|
|
//
|
|
|
|
#define SRB_DATA_RESERVED_PAGES 0x20000000
|
|
|
|
//
|
|
// Indicates that the request is using a reserved MDL that enables
|
|
// forward progress in low-memory conditions.
|
|
//
|
|
#define SRB_DATA_RESERVED_MDL 0x40000000
|
|
#endif
|
|
|
|
//
|
|
// Port Timeout Counter values.
|
|
//
|
|
|
|
#define PD_TIMER_STOPPED -1
|
|
|
|
//
|
|
// Possible registry flags for pnp interface key
|
|
//
|
|
|
|
//
|
|
// The absence of any information about a particular interface in the
|
|
// PnpInterface key in the registry indicates that pnp is not safe for this
|
|
// particular card.
|
|
//
|
|
|
|
#define SP_PNP_NOT_SAFE 0x00000000
|
|
|
|
//
|
|
// Indicates that pnp is a safe operation for this device. If this flag is
|
|
// set then the miniport will not be allowed to do detection and will always
|
|
// be handed resources provided by the pnp system. This flag may or may not
|
|
// be set in the registry - the fact that a value for a particular interface
|
|
// exists is enough to indicate that pnp is safe and this flag will always
|
|
// be set.
|
|
//
|
|
|
|
#define SP_PNP_IS_SAFE 0x00000001
|
|
|
|
//
|
|
// Indicates that we should take advantage of a chance to enumerate a particular
|
|
// bus type using the miniport. This flag is set for all non-enumerable legacy
|
|
// buses (ISA, EISA, etc...) and is cleared for the non-legacy ones and for the
|
|
// PnpBus type.
|
|
//
|
|
|
|
#define SP_PNP_NON_ENUMERABLE 0x00000002
|
|
|
|
//
|
|
// Indicates that we need to include some sort of location information in the
|
|
// config data to discern this adapter from any others.
|
|
//
|
|
|
|
#define SP_PNP_NEEDS_LOCATION 0x00000004
|
|
|
|
//
|
|
// Indicates that this type of adapter must have an interrupt for us to try
|
|
// and start it. If PNP doesn't provide an interrupt then scsiport will
|
|
// log an error and fail the start operation. If this flag is set then
|
|
// SP_PNP_IS_SAFE must also be set.
|
|
//
|
|
|
|
#define SP_PNP_INTERRUPT_REQUIRED 0x00000008
|
|
|
|
//
|
|
// Indicates that legacy detection should not be done.
|
|
//
|
|
|
|
#define SP_PNP_NO_LEGACY_DETECTION 0x00000010
|
|
|
|
//
|
|
// Internal scsiport srb status codes.
|
|
// these must be between 0x38 and 0x3f (inclusive) and should never get
|
|
// returned to a class driver.
|
|
//
|
|
// These values are used after the srb has been put on the adapter's
|
|
// startio queue and thus cannot be completed without running it through the
|
|
// completion DPC.
|
|
//
|
|
|
|
#ifndef KDBG_EXT
|
|
//
|
|
// Function declarations
|
|
//
|
|
|
|
NTSTATUS
|
|
ScsiPortGlobalDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortFdoCreateClose (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortFdoDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortPdoScsi(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortScsi1PdoScsi(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
ScsiPortStartIo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
BOOLEAN
|
|
ScsiPortInterrupt(
|
|
IN PKINTERRUPT InterruptObject,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortFdoDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortPdoDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortPdoCreateClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortPdoPnp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
ScsiPortTickHandler(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
IssueRequestSense(
|
|
IN PADAPTER_EXTENSION deviceExtension,
|
|
IN PSCSI_REQUEST_BLOCK FailingSrb
|
|
);
|
|
|
|
BOOLEAN
|
|
SpStartIoSynchronized (
|
|
PVOID ServiceContext
|
|
);
|
|
|
|
BOOLEAN
|
|
SpResetBusSynchronized (
|
|
PVOID ServiceContext
|
|
);
|
|
|
|
BOOLEAN
|
|
SpTimeoutSynchronized (
|
|
PVOID ServiceContext
|
|
);
|
|
|
|
BOOLEAN
|
|
SpEnableInterruptSynchronized (
|
|
PVOID ServiceContext
|
|
);
|
|
|
|
VOID
|
|
IssueAbortRequest(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
BOOLEAN
|
|
SpGetInterruptState(
|
|
IN PVOID ServiceContext
|
|
);
|
|
|
|
#if DBG
|
|
|
|
#define GetLogicalUnitExtension(fdo, path, target, lun, lock, getlock) \
|
|
GetLogicalUnitExtensionEx(fdo, path, target, lun, lock, getlock, __file__, __LINE__)
|
|
|
|
PLOGICAL_UNIT_EXTENSION
|
|
GetLogicalUnitExtensionEx(
|
|
PADAPTER_EXTENSION DeviceExtension,
|
|
UCHAR PathId,
|
|
UCHAR TargetId,
|
|
UCHAR Lun,
|
|
PVOID LockTag,
|
|
BOOLEAN AcquireBinLock,
|
|
PCSTR File,
|
|
ULONG Line
|
|
);
|
|
|
|
#else
|
|
|
|
PLOGICAL_UNIT_EXTENSION
|
|
GetLogicalUnitExtension(
|
|
PADAPTER_EXTENSION DeviceExtension,
|
|
UCHAR PathId,
|
|
UCHAR TargetId,
|
|
UCHAR Lun,
|
|
PVOID LockTag,
|
|
BOOLEAN AcquireBinLock
|
|
);
|
|
|
|
#endif
|
|
|
|
IO_ALLOCATION_ACTION
|
|
ScsiPortAllocationRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID MapRegisterBase,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
LogErrorEntry(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN PERROR_LOG_ENTRY LogEntry
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
GetNextLuRequest(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
VOID
|
|
GetNextLuRequestWithoutLock(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
VOID
|
|
SpLogPortTimeoutError(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN ULONG UniqueId
|
|
);
|
|
|
|
VOID
|
|
SpProcessCompletedRequest(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN PSRB_DATA SrbData,
|
|
OUT PBOOLEAN CallStartIo
|
|
);
|
|
|
|
PSRB_DATA
|
|
SpGetSrbData(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
UCHAR PathId,
|
|
UCHAR TargetId,
|
|
UCHAR Lun,
|
|
UCHAR QueueTag,
|
|
BOOLEAN AcquireBinLock
|
|
);
|
|
|
|
VOID
|
|
SpCompleteSrb(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN PSRB_DATA SrbData,
|
|
IN UCHAR SrbStatus
|
|
);
|
|
|
|
BOOLEAN
|
|
SpAllocateSrbExtension(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
|
IN PSCSI_REQUEST_BLOCK Srb,
|
|
OUT BOOLEAN *StartNextRequest,
|
|
OUT BOOLEAN *Tagged
|
|
);
|
|
|
|
NTSTATUS
|
|
SpSendMiniPortIoctl(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN PIRP RequestIrp
|
|
);
|
|
|
|
NTSTATUS
|
|
SpGetInquiryData(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SpClaimLogicalUnit(
|
|
IN PADAPTER_EXTENSION AdapterExtension,
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnitExtension,
|
|
IN PIRP Irp,
|
|
IN BOOLEAN StartDevice
|
|
);
|
|
|
|
VOID
|
|
SpMiniPortTimerDpc(
|
|
IN struct _KDPC *Dpc,
|
|
IN PVOID DeviceObject,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
);
|
|
|
|
BOOLEAN
|
|
SpSynchronizeExecution (
|
|
IN PKINTERRUPT Interrupt,
|
|
IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
|
|
IN PVOID SynchronizeContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SpGetCommonBuffer(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN ULONG NonCachedExtensionSize
|
|
);
|
|
|
|
VOID
|
|
SpDestroyAdapter(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN BOOLEAN Surprise
|
|
);
|
|
|
|
VOID
|
|
SpReleaseAdapterResources(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN BOOLEAN Stop,
|
|
IN BOOLEAN Surprise
|
|
);
|
|
|
|
NTSTATUS
|
|
SpInitializeConfiguration(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PHW_INITIALIZATION_DATA HwInitData,
|
|
IN PCONFIGURATION_CONTEXT Context
|
|
);
|
|
|
|
VOID
|
|
SpParseDevice(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN HANDLE Key,
|
|
IN PCONFIGURATION_CONTEXT Context,
|
|
IN PUCHAR Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
SpConfigurationCallout(
|
|
IN PVOID Context,
|
|
IN PUNICODE_STRING PathName,
|
|
IN INTERFACE_TYPE BusType,
|
|
IN ULONG BusNumber,
|
|
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
|
IN CONFIGURATION_TYPE ControllerType,
|
|
IN ULONG ControllerNumber,
|
|
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
|
IN CONFIGURATION_TYPE PeripheralType,
|
|
IN ULONG PeripheralNumber,
|
|
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
|
);
|
|
|
|
PCM_RESOURCE_LIST
|
|
SpBuildResourceList(
|
|
PADAPTER_EXTENSION DeviceExtension,
|
|
PPORT_CONFIGURATION_INFORMATION MiniportConfigInfo
|
|
);
|
|
|
|
BOOLEAN
|
|
GetPciConfiguration(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN OUT PDEVICE_OBJECT DeviceObject,
|
|
IN PHW_INITIALIZATION_DATA HwInitializationData,
|
|
IN PVOID RegistryPath,
|
|
IN ULONG BusNumber,
|
|
IN OUT PPCI_SLOT_NUMBER SlotNumber
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
);
|
|
|
|
VOID
|
|
ScsiPortUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortFdoPnp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortStartAdapter(
|
|
IN PDEVICE_OBJECT Fdo
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortStopAdapter(
|
|
IN PDEVICE_OBJECT Adapter,
|
|
IN PIRP StopRequest
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortStartLogicalUnit(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortInitLogicalUnit(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortStopLogicalUnit(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
NTSTATUS
|
|
SpEnumerateAdapterSynchronous(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN BOOLEAN Force
|
|
);
|
|
|
|
VOID
|
|
SpEnumerateAdapterAsynchronous(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN PSP_ENUMERATION_REQUEST EnumerationRequest,
|
|
IN BOOLEAN Force
|
|
);
|
|
|
|
VOID
|
|
SpEnumerationWorker(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
NTSTATUS
|
|
SpExtractDeviceRelations(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN DEVICE_RELATION_TYPE RelationType,
|
|
OUT PDEVICE_RELATIONS *DeviceRelations
|
|
);
|
|
|
|
VOID
|
|
ScsiPortInitializeDispatchTables(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortStringArrayToMultiString(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
PUNICODE_STRING MultiString,
|
|
PCSTR StringArray[]
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortGetDeviceId(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
OUT PUNICODE_STRING UnicodeString
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortGetInstanceId(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
OUT PUNICODE_STRING UnicodeString
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortGetCompatibleIds(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PINQUIRYDATA InquiryData,
|
|
OUT PUNICODE_STRING UnicodeString
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortGetHardwareIds(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PINQUIRYDATA InquiryData,
|
|
OUT PUNICODE_STRING UnicodeString
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortStartAdapterCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
SpReportNewAdapter(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortQueryPropertyPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP QueryIrp
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortQueryProperty(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP QueryIrp
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortInitLegacyAdapter(
|
|
IN PSCSIPORT_DRIVER_EXTENSION DriverExtension,
|
|
IN PHW_INITIALIZATION_DATA HwInitializationData,
|
|
IN PVOID HwContext
|
|
);
|
|
|
|
NTSTATUS
|
|
SpCreateAdapter(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
OUT PDEVICE_OBJECT *Fdo
|
|
);
|
|
|
|
VOID
|
|
SpInitializeAdapterExtension(
|
|
IN PADAPTER_EXTENSION FdoExtension,
|
|
IN PHW_INITIALIZATION_DATA HwInitializationData,
|
|
IN OUT PHW_DEVICE_EXTENSION HwDeviceExtension OPTIONAL
|
|
);
|
|
|
|
PHW_INITIALIZATION_DATA
|
|
SpFindInitData(
|
|
IN PSCSIPORT_DRIVER_EXTENSION DriverExtension,
|
|
IN INTERFACE_TYPE InterfaceType
|
|
);
|
|
|
|
VOID
|
|
SpBuildConfiguration(
|
|
IN PADAPTER_EXTENSION AdapterExtension,
|
|
IN PHW_INITIALIZATION_DATA HwInitializationData,
|
|
IN PPORT_CONFIGURATION_INFORMATION ConfigInformation
|
|
);
|
|
|
|
NTSTATUS
|
|
SpCallHwFindAdapter(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PHW_INITIALIZATION_DATA HwInitData,
|
|
IN PVOID HwContext OPTIONAL,
|
|
IN OUT PCONFIGURATION_CONTEXT ConfigurationContext,
|
|
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
|
OUT PBOOLEAN CallAgain
|
|
);
|
|
|
|
NTSTATUS
|
|
SpCallHwInitialize(
|
|
IN PDEVICE_OBJECT Fdo
|
|
);
|
|
|
|
HANDLE
|
|
SpOpenParametersKey(
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
HANDLE
|
|
SpOpenDeviceKey(
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN ULONG DeviceNumber
|
|
);
|
|
|
|
ULONG
|
|
SpQueryPnpInterfaceFlags(
|
|
IN PSCSIPORT_DRIVER_EXTENSION DriverExtension,
|
|
IN INTERFACE_TYPE InterfaceType
|
|
);
|
|
|
|
NTSTATUS
|
|
SpGetRegistryValue(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN HANDLE Handle,
|
|
IN PWSTR KeyString,
|
|
OUT PKEY_VALUE_FULL_INFORMATION *KeyInformation
|
|
);
|
|
|
|
NTSTATUS
|
|
SpInitDeviceMap(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
SpBuildDeviceMapEntry(
|
|
IN PCOMMON_EXTENSION CommonExtension
|
|
);
|
|
|
|
VOID
|
|
SpDeleteDeviceMapEntry(
|
|
IN PCOMMON_EXTENSION CommonExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
SpUpdateLogicalUnitDeviceMapEntry(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
VOID
|
|
SpLogResetMsg(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN PSCSI_REQUEST_BLOCK Srb,
|
|
IN ULONG UniqueId
|
|
);
|
|
|
|
VOID
|
|
SpLogResetError(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN PLOGICAL_UNIT_EXTENSION Lun,
|
|
IN ULONG UniqueId
|
|
);
|
|
|
|
VOID
|
|
SpRemoveLogicalUnitFromBin (
|
|
IN PADAPTER_EXTENSION AdapterExtension,
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnitExtension
|
|
);
|
|
|
|
VOID
|
|
SpAddLogicalUnitToBin (
|
|
IN PADAPTER_EXTENSION AdapterExtension,
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnitExtension
|
|
);
|
|
|
|
PSCSIPORT_DEVICE_TYPE
|
|
SpGetDeviceTypeInfo(
|
|
IN UCHAR DeviceType
|
|
);
|
|
|
|
BOOLEAN
|
|
SpRemoveLogicalUnit(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
|
IN UCHAR RemoveType
|
|
);
|
|
|
|
VOID
|
|
SpDeleteLogicalUnit(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
PLOGICAL_UNIT_EXTENSION
|
|
SpFindSafeLogicalUnit(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR PathId,
|
|
IN PVOID LockTag
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortSystemControlIrp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp);
|
|
|
|
NTSTATUS
|
|
SpWmiIrpNormalRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR WmiMinorCode,
|
|
IN OUT PWMI_PARAMETERS WmiParameters);
|
|
|
|
NTSTATUS
|
|
SpWmiIrpRegisterRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PWMI_PARAMETERS WmiParameters);
|
|
|
|
NTSTATUS
|
|
SpWmiHandleOnMiniPortBehalf(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR WmiMinorCode,
|
|
IN OUT PWMI_PARAMETERS WmiParameters);
|
|
|
|
NTSTATUS
|
|
SpWmiPassToMiniPort(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR WmiMinorCode,
|
|
IN OUT PWMI_PARAMETERS WmiParameters);
|
|
|
|
VOID
|
|
SpWmiInitializeSpRegInfo(
|
|
IN PDEVICE_OBJECT DeviceObject);
|
|
|
|
VOID
|
|
SpWmiGetSpRegInfo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT PWMIREGINFO * SpRegInfoBuf,
|
|
OUT ULONG * SpRegInfoBufSize);
|
|
|
|
VOID
|
|
SpWmiDestroySpRegInfo(
|
|
IN PDEVICE_OBJECT DeviceObject);
|
|
|
|
NTSTATUS
|
|
SpWmiInitializeFreeRequestList(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG NumberOfItems
|
|
);
|
|
|
|
VOID
|
|
SpWmiPushExistingFreeRequestItem(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN PWMI_MINIPORT_REQUEST_ITEM WmiRequestItem
|
|
);
|
|
|
|
NTSTATUS
|
|
SpWmiPushFreeRequestItem(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
PWMI_MINIPORT_REQUEST_ITEM
|
|
SpWmiPopFreeRequestItem(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
BOOLEAN
|
|
SpWmiRemoveFreeMiniPortRequestItems(
|
|
IN PADAPTER_EXTENSION fdoExtension
|
|
);
|
|
|
|
#if DBG
|
|
ULONG
|
|
FASTCALL
|
|
FASTCALL
|
|
SpAcquireRemoveLockEx(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OPTIONAL PVOID Tag,
|
|
IN PCSTR File,
|
|
IN ULONG Line
|
|
);
|
|
#else
|
|
ULONG
|
|
INLINE
|
|
SpAcquireRemoveLock(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OPTIONAL PVOID Tag
|
|
)
|
|
{
|
|
PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
|
|
InterlockedIncrement(&commonExtension->RemoveLock);
|
|
return (commonExtension->IsRemoved);
|
|
}
|
|
#endif
|
|
|
|
VOID
|
|
FASTCALL
|
|
SpReleaseRemoveLock(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OPTIONAL PVOID Tag
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
FASTCALL
|
|
SpCompleteRequest(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN OPTIONAL PSRB_DATA SrbData,
|
|
IN CCHAR PriorityBoost
|
|
);
|
|
|
|
NTSTATUS
|
|
ScsiPortDispatchPower(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
SpDefaultPowerCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PIRP OriginalIrp,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
);
|
|
|
|
PCM_RESOURCE_LIST
|
|
RtlDuplicateCmResourceList(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
POOL_TYPE PoolType,
|
|
PCM_RESOURCE_LIST ResourceList,
|
|
ULONG Tag
|
|
);
|
|
|
|
ULONG
|
|
RtlSizeOfCmResourceList(
|
|
IN PCM_RESOURCE_LIST ResourceList
|
|
);
|
|
|
|
BOOLEAN
|
|
SpTranslateResources(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PCM_RESOURCE_LIST AllocatedResources,
|
|
OUT PCM_RESOURCE_LIST *TranslatedResources
|
|
);
|
|
|
|
BOOLEAN
|
|
SpFindAddressTranslation(
|
|
IN PADAPTER_EXTENSION AdapterExtension,
|
|
IN INTERFACE_TYPE BusType,
|
|
IN ULONG BusNumber,
|
|
IN PHYSICAL_ADDRESS RangeStart,
|
|
IN ULONG RangeLength,
|
|
IN BOOLEAN InIoSpace,
|
|
IN OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Translation
|
|
);
|
|
|
|
NTSTATUS
|
|
SpAllocateAdapterResources(
|
|
IN PDEVICE_OBJECT Fdo
|
|
);
|
|
|
|
NTSTATUS
|
|
SpLockUnlockQueue(
|
|
IN PDEVICE_OBJECT LogicalUnit,
|
|
IN BOOLEAN LockQueue,
|
|
IN BOOLEAN BypassLockedQueue
|
|
);
|
|
|
|
VOID
|
|
ScsiPortRemoveAdapter(
|
|
IN PDEVICE_OBJECT Adapter,
|
|
IN BOOLEAN Surprise
|
|
);
|
|
|
|
VOID
|
|
SpTerminateAdapter(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
NTSTATUS
|
|
SpQueryDeviceText(
|
|
IN PDEVICE_OBJECT LogicalUnit,
|
|
IN DEVICE_TEXT_TYPE TextType,
|
|
IN LCID LocaleId,
|
|
IN OUT PWSTR *DeviceText
|
|
);
|
|
|
|
NTSTATUS
|
|
SpCheckSpecialDeviceFlags(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
|
IN PINQUIRYDATA InquiryData
|
|
);
|
|
|
|
PSRB_DATA
|
|
FASTCALL
|
|
SpAllocateSrbData(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN OPTIONAL PIRP Request,
|
|
IN OPTIONAL PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
PSRB_DATA
|
|
FASTCALL
|
|
SpAllocateBypassSrbData(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
VOID
|
|
SpCheckSrbLists(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN PUCHAR FailureString
|
|
);
|
|
|
|
VOID
|
|
ScsiPortCompletionDpc(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
SpAllocateTagBitMap(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
NTSTATUS
|
|
SpRequestValidPowerState(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
);
|
|
|
|
NTSTATUS
|
|
SpRequestValidAdapterPowerStateSynchronous(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
NTSTATUS
|
|
SpEnableDisableAdapter(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN BOOLEAN Enable
|
|
);
|
|
|
|
NTSTATUS
|
|
SpEnableDisableLogicalUnit(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
|
IN BOOLEAN Enable,
|
|
IN PSP_ENABLE_DISABLE_COMPLETION_ROUTINE CompletionRoutine,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
ScsiPortProcessAdapterPower(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
INTERFACE_TYPE
|
|
SpGetPdoInterfaceType(
|
|
IN PDEVICE_OBJECT Pdo
|
|
);
|
|
|
|
NTSTATUS
|
|
SpReadNumericInstanceValue(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PWSTR ValueName,
|
|
OUT PULONG Value
|
|
);
|
|
|
|
NTSTATUS
|
|
SpWriteNumericInstanceValue(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PWSTR ValueName,
|
|
IN ULONG Value
|
|
);
|
|
|
|
VOID
|
|
SpGetSupportedAdapterControlFunctions(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
VOID
|
|
SpReleaseMappedAddresses(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
VOID
|
|
SpGetSupportedAdapterControlFunctions(
|
|
PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
BOOLEAN
|
|
SpIsAdapterControlTypeSupported(
|
|
IN PADAPTER_EXTENSION AdapterExtension,
|
|
IN SCSI_ADAPTER_CONTROL_TYPE ControlType
|
|
);
|
|
|
|
SCSI_ADAPTER_CONTROL_STATUS
|
|
SpCallAdapterControl(
|
|
IN PADAPTER_EXTENSION AdapterExtension,
|
|
IN SCSI_ADAPTER_CONTROL_TYPE ControlType,
|
|
IN PVOID Parameters
|
|
);
|
|
|
|
PVOID
|
|
SpAllocateSrbDataBackend(
|
|
IN POOL_TYPE PoolType,
|
|
IN ULONG NumberOfBytes,
|
|
IN ULONG AdapterIndex
|
|
);
|
|
|
|
VOID
|
|
SpFreeSrbDataBackend(
|
|
IN PSRB_DATA SrbData
|
|
);
|
|
|
|
ULONG
|
|
SpAllocateQueueTag(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
VOID
|
|
SpReleaseQueueTag(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN ULONG QueueTag
|
|
);
|
|
|
|
NTSTATUS
|
|
SpInitializeGuidInterfaceMapping(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
NTSTATUS
|
|
SpSignalCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PKEVENT Event
|
|
);
|
|
|
|
NTSTATUS
|
|
SpSendIrpSynchronous(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SpGetBusTypeGuid(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
BOOLEAN
|
|
SpDetermine64BitSupport(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SpAdjustDisabledBit(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
|
IN BOOLEAN Enable
|
|
);
|
|
|
|
NTSTATUS
|
|
SpReadNumericValue(
|
|
IN OPTIONAL HANDLE Root,
|
|
IN OPTIONAL PUNICODE_STRING KeyName,
|
|
IN PUNICODE_STRING ValueName,
|
|
OUT PULONG Value
|
|
);
|
|
|
|
VOID
|
|
SpWaitForRemoveLock(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID LockTag
|
|
);
|
|
|
|
VOID
|
|
SpStartLockRequest(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
|
IN PIRP Irp OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
SpAdapterConfiguredForSenseDataEvents(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT GUID *SenseDataClass
|
|
);
|
|
|
|
NTSTATUS
|
|
SpInitAdapterWmiRegInfo(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
PMAPPED_ADDRESS
|
|
SpAllocateAddressMapping(
|
|
PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
BOOLEAN
|
|
SpPreallocateAddressMapping(
|
|
PADAPTER_EXTENSION Adapter,
|
|
IN UCHAR NumberOfBlocks
|
|
);
|
|
|
|
VOID
|
|
SpPurgeFreeMappedAddressList(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
BOOLEAN
|
|
SpFreeMappedAddress(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN PVOID MappedAddress
|
|
);
|
|
|
|
PMAPPED_ADDRESS
|
|
SpFindMappedAddress(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN LARGE_INTEGER IoAddress,
|
|
IN ULONG NumberOfBytes,
|
|
IN ULONG SystemIoBusNumber
|
|
);
|
|
|
|
BOOLEAN
|
|
SpTransferBlockedRequestsToAdapter(
|
|
PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
//
|
|
// SCSIPORT specified verifier error codes.
|
|
//
|
|
#define SCSIPORT_VERIFIER_BAD_INIT_PARAMS 0x1000
|
|
#define SCSIPORT_VERIFIER_STALL_TOO_LONG 0x1001
|
|
#define SCSIPORT_VERIFIER_MINIPORT_ROUTINE_TIMEOUT 0x1002
|
|
#define SCSIPORT_VERIFIER_REQUEST_COMPLETED_TWICE 0x1003
|
|
#define SCSIPORT_VERIFIER_BAD_SRBSTATUS 0x1004
|
|
#define SCSIPORT_VERIFIER_UNTAGGED_REQUEST_ACTIVE 0x1005
|
|
#define SCSIPORT_VERIFIER_BAD_VA 0x1006
|
|
#define SCSIPORT_VERIFIER_RQSTS_NOT_COMPLETE 0x1007
|
|
#define SCSIPORT_VERIFIER_BAD_BUSDATATYPE 0x1008
|
|
|
|
#define SP_VRFY_NONE (ULONG)-1
|
|
#define SP_VRFY_COMMON_BUFFERS 0x00000001
|
|
|
|
typedef struct _SP_VA_MAPPING_INFO {
|
|
PVOID OriginalSrbExtVa;
|
|
ULONG SrbExtLen;
|
|
PMDL SrbExtMdl;
|
|
PVOID RemappedSrbExtVa;
|
|
PVOID OriginalSenseVa;
|
|
ULONG SenseLen;
|
|
PMDL SenseMdl;
|
|
PVOID RemappedSenseVa;
|
|
} SP_VA_MAPPING_INFO, *PSP_VA_MAPPING_INFO;
|
|
|
|
#define GET_VA_MAPPING_INFO(adapter, block)\
|
|
(PSP_VA_MAPPING_INFO)((PUCHAR)(block) + ((adapter)->CommonBufferSize - PAGE_SIZE))
|
|
|
|
BOOLEAN
|
|
SpVerifierInitialization(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SpVerifySrbStatus(
|
|
PVOID HwDeviceExtension,
|
|
PSCSI_REQUEST_BLOCK srb
|
|
);
|
|
|
|
ULONG
|
|
SpHwFindAdapterVrfy (
|
|
IN PVOID DeviceExtension,
|
|
IN PVOID HwContext,
|
|
IN PVOID BusInformation,
|
|
IN PCHAR ArgumentString,
|
|
IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
|
|
OUT PBOOLEAN Again
|
|
);
|
|
|
|
BOOLEAN
|
|
SpHwInitializeVrfy (
|
|
IN PVOID DeviceExtension
|
|
);
|
|
|
|
BOOLEAN
|
|
SpHwStartIoVrfy (
|
|
IN PVOID DeviceExtension,
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
);
|
|
|
|
BOOLEAN
|
|
SpHwInterruptVrfy (
|
|
IN PVOID DeviceExtension
|
|
);
|
|
|
|
BOOLEAN
|
|
SpHwResetBusVrfy (
|
|
IN PVOID DeviceExtension,
|
|
IN ULONG PathId
|
|
);
|
|
|
|
VOID
|
|
SpHwDmaStartedVrfy (
|
|
IN PVOID DeviceExtension
|
|
);
|
|
|
|
BOOLEAN
|
|
SpHwRequestInterruptVrfy (
|
|
IN PVOID DeviceExtension
|
|
);
|
|
|
|
BOOLEAN
|
|
SpHwTimerRequestVrfy (
|
|
IN PVOID DeviceExtension
|
|
);
|
|
|
|
SCSI_ADAPTER_CONTROL_STATUS
|
|
SpHwAdapterControlVrfy (
|
|
IN PVOID DeviceExtension,
|
|
IN SCSI_ADAPTER_CONTROL_TYPE ControlType,
|
|
IN PVOID Parameters
|
|
);
|
|
|
|
NTSTATUS
|
|
SpGetCommonBufferVrfy(
|
|
PADAPTER_EXTENSION DeviceExtension,
|
|
ULONG NonCachedExtensionSize
|
|
);
|
|
|
|
VOID
|
|
SpFreeCommonBufferVrfy(
|
|
PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
PVOID
|
|
SpGetOriginalSrbExtVa(
|
|
PADAPTER_EXTENSION Adapter,
|
|
PVOID Va
|
|
);
|
|
|
|
VOID
|
|
SpInsertSrbExtension(
|
|
PADAPTER_EXTENSION Adapter,
|
|
PCCHAR SrbExtension
|
|
);
|
|
|
|
PVOID
|
|
SpPrepareSrbExtensionForUse(
|
|
PADAPTER_EXTENSION Adapter,
|
|
PCCHAR *SrbExtension
|
|
);
|
|
|
|
PCCHAR
|
|
SpPrepareSenseBufferForUse(
|
|
PADAPTER_EXTENSION Adapter,
|
|
PCCHAR SrbExtension
|
|
);
|
|
|
|
PVOID
|
|
SpGetInaccessiblePage(
|
|
PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
VOID
|
|
SpEnsureAllRequestsAreComplete(
|
|
PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
VOID
|
|
SpDoVerifierCleanup(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
);
|
|
|
|
VOID
|
|
SpDoVerifierInit(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN PHW_INITIALIZATION_DATA HwInitializationData
|
|
);
|
|
|
|
VOID
|
|
ScsiPortInitPdoWmi(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit
|
|
);
|
|
|
|
PMDL
|
|
INLINE
|
|
SpGetRemappedSrbExt(
|
|
PADAPTER_EXTENSION Adapter,
|
|
PVOID Block
|
|
)
|
|
{
|
|
PSP_VA_MAPPING_INFO MappingInfo = GET_VA_MAPPING_INFO(Adapter, Block);
|
|
return MappingInfo->SrbExtMdl;
|
|
}
|
|
|
|
PMDL
|
|
INLINE
|
|
SpGetRemappedSenseBuffer(
|
|
PADAPTER_EXTENSION Adapter,
|
|
PVOID Block
|
|
)
|
|
{
|
|
PSP_VA_MAPPING_INFO MappingInfo = GET_VA_MAPPING_INFO(Adapter, Block);
|
|
return MappingInfo->SenseMdl;
|
|
}
|
|
|
|
BOOLEAN
|
|
INLINE
|
|
SpVerifierActive(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
)
|
|
{
|
|
return (Adapter->VerifierExtension != NULL) ? TRUE : FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
INLINE
|
|
SpVerifyingCommonBuffer(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
)
|
|
{
|
|
return (Adapter->VerifierExtension == NULL) ? FALSE :
|
|
(Adapter->VerifierExtension->VrfyLevel & SP_VRFY_COMMON_BUFFERS) ? TRUE :
|
|
FALSE;
|
|
}
|
|
|
|
//
|
|
// Definitions and declarations used for logging allocation failures. When
|
|
// enabled, all allocation failures are logged to the system event log
|
|
// as warnings.
|
|
//
|
|
|
|
PVOID
|
|
SpAllocateErrorLogEntry(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
SpLogAllocationFailureFn(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN POOL_TYPE PoolType,
|
|
IN SIZE_T Size,
|
|
IN ULONG Tag,
|
|
IN ULONG FileId,
|
|
IN ULONG LineNumber
|
|
);
|
|
|
|
PVOID
|
|
SpAllocatePoolEx(
|
|
IN POOL_TYPE PoolType,
|
|
IN SIZE_T NumberOfBytes,
|
|
IN ULONG Tag,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN ULONG FileId,
|
|
IN ULONG LineNumber
|
|
);
|
|
|
|
PMDL
|
|
SpAllocateMdlEx(
|
|
IN PVOID VirtualAddress,
|
|
IN ULONG Length,
|
|
IN BOOLEAN SecondaryBuffer,
|
|
IN BOOLEAN ChargeQuota,
|
|
IN OUT PIRP Irp,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN ULONG FileId,
|
|
IN ULONG LineNumber
|
|
);
|
|
|
|
PIRP
|
|
SpAllocateIrpEx(
|
|
IN CCHAR StackSize,
|
|
IN BOOLEAN ChargeQuota,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN ULONG FileId,
|
|
IN ULONG LineNumber
|
|
);
|
|
|
|
#define SCSIPORT_TAG_ALLOCMDL TAG('LDMs')
|
|
#define SCSIPORT_TAG_ALLOCIRP TAG('PRIs')
|
|
#define SCSIPORT_TAG_LOOKASIDE TAG('LALs')
|
|
|
|
#define SpAllocatePool(type, size, tag, drvObj) \
|
|
SpAllocatePoolEx((type), (size), (tag), (drvObj), __FILE_ID__, __LINE__)
|
|
|
|
#define SpAllocateMdl(va, len, secbuf, cq, irp, drvobj) \
|
|
SpAllocateMdlEx((va), (len), (secbuf), (cq), (irp), (drvobj), __FILE_ID__, __LINE__)
|
|
|
|
#define SpAllocateIrp(ss, cq, drvobj) \
|
|
SpAllocateIrpEx((ss), (cq), (drvobj), __FILE_ID__, __LINE__)
|
|
|
|
//
|
|
// This structure makes it easy to allocate a contiguous chunk of memory
|
|
// for an event log entry with room for the insertion strings.
|
|
//
|
|
typedef struct _SCSIPORT_ALLOCFAILURE_DATA {
|
|
ULONG Size;
|
|
ULONG FileId;
|
|
ULONG LineNumber;
|
|
} SCSIPORT_ALLOCFAILURE_DATA;
|
|
|
|
//
|
|
// Inline functions
|
|
//
|
|
|
|
ULONG
|
|
INLINE
|
|
SpGetCommonBufferSize(
|
|
IN PADAPTER_EXTENSION DeviceExtension,
|
|
IN ULONG NonCachedExtensionSize,
|
|
OUT OPTIONAL PULONG BlockSize
|
|
)
|
|
{
|
|
ULONG length;
|
|
ULONG blockSize;
|
|
|
|
//
|
|
// To ensure that we never transfer normal request data to the SrbExtension
|
|
// (ie. the case of Srb->SenseInfoBuffer == VirtualAddress in
|
|
// ScsiPortGetPhysicalAddress) on some platforms where an inconsistency in
|
|
// MM can result in the same Virtual address supplied for 2 different
|
|
// physical addresses, bump the SrbExtensionSize if it's zero.
|
|
//
|
|
|
|
if (DeviceExtension->SrbExtensionSize == 0) {
|
|
DeviceExtension->SrbExtensionSize = 16;
|
|
}
|
|
|
|
//
|
|
// Calculate the block size for the list elements based on the Srb
|
|
// Extension.
|
|
//
|
|
|
|
blockSize = DeviceExtension->SrbExtensionSize;
|
|
|
|
//
|
|
// If auto request sense is supported then add in space for the request
|
|
// sense data.
|
|
//
|
|
|
|
if (DeviceExtension->AutoRequestSense) {
|
|
blockSize += sizeof(SENSE_DATA) +
|
|
DeviceExtension->AdditionalSenseBytes;
|
|
}
|
|
|
|
//
|
|
// Round blocksize up to the size of a PVOID.
|
|
//
|
|
|
|
blockSize = (blockSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
|
|
|
|
//
|
|
// The length of the common buffer should be equal to the size of the
|
|
// noncached extension and a minimum number of srb extension
|
|
//
|
|
|
|
length = NonCachedExtensionSize +
|
|
(blockSize * DeviceExtension->NumberOfRequests);
|
|
|
|
//
|
|
// Round the length up to a page size, since HalAllocateCommonBuffer
|
|
// allocates in pages anyway.
|
|
//
|
|
|
|
length = (ULONG)ROUND_TO_PAGES(length);
|
|
|
|
//
|
|
// If the user is interested in the block size, copy it into the provided
|
|
// buffer.
|
|
//
|
|
|
|
if (BlockSize != NULL) {
|
|
*BlockSize = blockSize;
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
NTSTATUS
|
|
INLINE
|
|
SpDispatchRequest(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PCOMMON_EXTENSION commonExtension = &(LogicalUnit->CommonExtension);
|
|
PCOMMON_EXTENSION lowerCommonExtension =
|
|
commonExtension->LowerDeviceObject->DeviceExtension;
|
|
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
|
|
|
|
ASSERT_PDO(LogicalUnit->CommonExtension.DeviceObject);
|
|
ASSERT_SRB_DATA(srb->OriginalRequest);
|
|
|
|
if((LogicalUnit->CommonExtension.IdleTimer != NULL) &&
|
|
(SpSrbRequiresPower(srb)) &&
|
|
!(srb->SrbFlags & SRB_FLAGS_BYPASS_LOCKED_QUEUE) &&
|
|
!(srb->SrbFlags & SRB_FLAGS_NO_KEEP_AWAKE)) {
|
|
PoSetDeviceBusy(LogicalUnit->CommonExtension.IdleTimer);
|
|
}
|
|
|
|
ASSERT(irpStack->MajorFunction == IRP_MJ_SCSI);
|
|
return (lowerCommonExtension->MajorFunction[IRP_MJ_SCSI])(
|
|
commonExtension->LowerDeviceObject,
|
|
Irp);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
INLINE
|
|
SpSrbIsBypassRequest(
|
|
PSCSI_REQUEST_BLOCK Srb,
|
|
ULONG LuFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines whether a request is a "bypass" request - one which
|
|
should skip the lun queueing and be injected straight into the startio
|
|
queue.
|
|
|
|
Bypass requests do not start the next LU request when they complete. This
|
|
ensures that no new i/o is run until the condition being bypassed is
|
|
cleared.
|
|
|
|
Note: LOCK & UNLOCK requests are not bypass requests unless the queue
|
|
is already locked. This ensures that the first LOCK request will
|
|
get run after previously queued requests, but that additional LOCK
|
|
requests will not get stuck in the lun queue.
|
|
|
|
Likewise any UNLOCK request sent when the queue is locked will be
|
|
run immediately. However since SpStartIoSynchronized checks to
|
|
see if the request is a bypass request AFTER ScsiPortStartIo has
|
|
cleared the QUEUE_LOCKED flag this will force the completion dpc
|
|
to call GetNextLuRequest which will take the next operation out of
|
|
the lun queue. This is how i/o is restarted after a lock sequence
|
|
has been completed.
|
|
|
|
Arguments:
|
|
|
|
Srb - the srb in question
|
|
|
|
LuFlags - the flags for the lun.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the request should bypass the lun queue, be injected into the
|
|
StartIo queue and if GetNextLuRequest should not be called after this
|
|
request has completed.
|
|
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG flags = Srb->SrbFlags & (SRB_FLAGS_BYPASS_FROZEN_QUEUE |
|
|
SRB_FLAGS_BYPASS_LOCKED_QUEUE);
|
|
|
|
ASSERT(TEST_FLAG(LuFlags, LU_QUEUE_FROZEN | LU_QUEUE_LOCKED) !=
|
|
(LU_QUEUE_FROZEN | LU_QUEUE_LOCKED));
|
|
|
|
if(flags == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
if(flags & SRB_FLAGS_BYPASS_LOCKED_QUEUE) {
|
|
|
|
DebugPrint((2, "SpSrbIsBypassRequest: Srb %#08lx is marked to bypass "
|
|
"locked queue\n", Srb));
|
|
|
|
if(TEST_FLAG(LuFlags, LU_QUEUE_LOCKED | LU_QUEUE_PAUSED)) {
|
|
|
|
DebugPrint((1, "SpSrbIsBypassRequest: Queue is locked - %#08lx is "
|
|
"a bypass srb\n", Srb));
|
|
return TRUE;
|
|
} else {
|
|
DebugPrint((3, "SpSrbIsBypassRequest: Queue is not locked - not a "
|
|
"bypass request\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
INLINE
|
|
SpRequestCompletionDpc(
|
|
IN PDEVICE_OBJECT Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will request that the Completion DPC be queued if there isn't
|
|
already one queued or in progress. It will set the DpcFlags
|
|
PD_DPC_NOTIFICATION_REQUIRED and PD_DPC_RUNNING. If the DPC_RUNNING flag
|
|
was not already set then it will request a DPC from the system as well.
|
|
|
|
Arguments:
|
|
|
|
Adapter - the Adapter to request the DPC for
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
PADAPTER_EXTENSION adapterExtension = Adapter->DeviceExtension;
|
|
ULONG oldDpcFlags;
|
|
|
|
//
|
|
// Set the DPC flags to indicate that there is work to be processed
|
|
// (otherwise we wouldn't queue the DPC) and that the DPC is queued.
|
|
//
|
|
|
|
oldDpcFlags = InterlockedExchange(
|
|
&(adapterExtension->DpcFlags),
|
|
(PD_NOTIFICATION_REQUIRED | PD_DPC_RUNNING));
|
|
|
|
//
|
|
// If the DPC was already queued or running then don't bother requesting
|
|
// a new one - the current one will pickup the work itself.
|
|
//
|
|
|
|
if(TEST_FLAG(oldDpcFlags, PD_DPC_RUNNING) == FALSE) {
|
|
IoRequestDpc(Adapter, NULL, NULL);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
INLINE
|
|
SpTranslateScsiStatus(
|
|
IN PSCSI_REQUEST_BLOCK Srb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine translates an srb status into an ntstatus.
|
|
|
|
Arguments:
|
|
|
|
Srb - Supplies a pointer to the failing Srb.
|
|
|
|
Return Value:
|
|
|
|
An nt status approprate for the error.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (SRB_STATUS(Srb->SrbStatus)) {
|
|
case SRB_STATUS_INVALID_LUN:
|
|
case SRB_STATUS_INVALID_TARGET_ID:
|
|
case SRB_STATUS_NO_DEVICE:
|
|
case SRB_STATUS_NO_HBA:
|
|
return(STATUS_DEVICE_DOES_NOT_EXIST);
|
|
case SRB_STATUS_COMMAND_TIMEOUT:
|
|
case SRB_STATUS_TIMEOUT:
|
|
return(STATUS_IO_TIMEOUT);
|
|
case SRB_STATUS_SELECTION_TIMEOUT:
|
|
return(STATUS_DEVICE_NOT_CONNECTED);
|
|
case SRB_STATUS_BAD_FUNCTION:
|
|
case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
|
|
return(STATUS_INVALID_DEVICE_REQUEST);
|
|
case SRB_STATUS_DATA_OVERRUN:
|
|
return(STATUS_BUFFER_OVERFLOW);
|
|
default:
|
|
return(STATUS_IO_DEVICE_ERROR);
|
|
}
|
|
|
|
return(STATUS_IO_DEVICE_ERROR);
|
|
}
|
|
|
|
PVOID
|
|
INLINE
|
|
SpGetSrbExtensionBuffer(
|
|
IN PADAPTER_EXTENSION Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a pointer to the adapter's SrbExtensionBuffer.
|
|
|
|
Arguments:
|
|
|
|
Adapter - Supplies a pointer to the adapter's ADAPTER_EXTNENSION.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the adapter's SrbExtensionBuffer.
|
|
|
|
--*/
|
|
|
|
{
|
|
return (SpVerifyingCommonBuffer(Adapter)) ?
|
|
Adapter->VerifierExtension->CommonBufferVAs :
|
|
Adapter->SrbExtensionBuffer;
|
|
}
|
|
|
|
VOID
|
|
INLINE
|
|
SpForceRequestIntoLuQueue(
|
|
IN PKDEVICE_QUEUE DeviceQueue,
|
|
IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry,
|
|
IN ULONG SortKey,
|
|
IN PVOID BusyRequest
|
|
)
|
|
{
|
|
if (!KeInsertByKeyDeviceQueue(
|
|
DeviceQueue,
|
|
DeviceQueueEntry,
|
|
SortKey)) {
|
|
|
|
//
|
|
// The LU says it is busy, so there should be a busy request.
|
|
//
|
|
|
|
ASSERT(BusyRequest != NULL);
|
|
|
|
//
|
|
// We can arrive here if the LU's device queue was drained by
|
|
// the DCP routine prior to calling us, transitioning the queue
|
|
// from busy to not busy. It is safe for us to force the
|
|
// request into the queue because we know we have a busy
|
|
// request that will get restarted by our TickHandler routine.
|
|
//
|
|
|
|
KeInsertByKeyDeviceQueue(
|
|
DeviceQueue,
|
|
DeviceQueueEntry,
|
|
SortKey);
|
|
}
|
|
}
|
|
|
|
PMDL
|
|
SpBuildMdlForMappedTransfer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PDMA_ADAPTER AdapterObject,
|
|
IN PMDL OriginalMdl,
|
|
IN PVOID StartVa,
|
|
IN ULONG ByteCount,
|
|
IN PSRB_SCATTER_GATHER ScatterGatherList,
|
|
IN ULONG ScatterGatherEntries
|
|
);
|
|
|
|
NTSTATUS
|
|
SpFlushReleaseQueue(
|
|
IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
|
|
IN BOOLEAN Flush,
|
|
IN BOOLEAN SurpriseRemove
|
|
);
|
|
|
|
#if defined(FORWARD_PROGRESS)
|
|
VOID
|
|
SpPrepareMdlForMappedTransfer(
|
|
IN PMDL mdl,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PDMA_ADAPTER AdapterObject,
|
|
IN PMDL OriginalMdl,
|
|
IN PVOID StartVa,
|
|
IN ULONG ByteCount,
|
|
IN PSRB_SCATTER_GATHER ScatterGatherList,
|
|
IN ULONG ScatterGatherEntries
|
|
);
|
|
|
|
VOID
|
|
INLINE
|
|
SpFreeSrbExtension(
|
|
IN PADAPTER_EXTENSION Adapter,
|
|
IN PVOID SrbExtension
|
|
)
|
|
{
|
|
if (SpVerifyingCommonBuffer(Adapter)) {
|
|
|
|
SpInsertSrbExtension(Adapter, SrbExtension);
|
|
|
|
} else {
|
|
|
|
*((PVOID *) SrbExtension) = Adapter->SrbExtensionListHeader;
|
|
Adapter->SrbExtensionListHeader = SrbExtension;
|
|
|
|
}
|
|
}
|
|
#endif // FORWARD_PROGRESS
|
|
|
|
#endif
|
|
|
|
#if defined(NEWQUEUE)
|
|
#define SP_DEFAULT_MAX_CAPACITY 0xffffffff
|
|
#define SP_DEFAULT_ZONES 4
|
|
|
|
extern ULONG SpPerZoneLimit;
|
|
extern ULONG SpPerBlockLimit;
|
|
#endif // NEWQUEUE
|
|
|
|
#endif // _PORT_H_
|
|
|