/*++ Copyright (c) 1991-5 Microsoft Corporation Module Name: ftdisk.h Abstract: These are the structures that FtDisk driver uses to support IO to NTFT volumes. Author: Bob Rinne (bobri) 2-Feb-1992 Mike Glass (mglass) Norbert Kusters 2-Feb-1995 Notes: Revision History: --*/ extern "C" { #include "ntddk.h" #include "stdio.h" #include #include #include #include "ftlog.h" } #if DBG extern "C" { VOID FtDebugPrint( ULONG DebugPrintLevel, PCCHAR DebugMessage, ... ); extern ULONG FtDebug; } #define DebugPrint(X) FtDebugPrint X #else #define DebugPrint(X) #endif // DBG #ifdef POOL_TAGGING #undef ExAllocatePool #undef ExAllocatePoolWithQuota #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'tFtN') #define ExAllocatePoolWithQuota(a,b) ExAllocatePoolWithQuotaTag(a,b,'tFtN') #endif #define STRIPE_SIZE ((ULONG) 0x00010000) class TRANSFER_PACKET; typedef TRANSFER_PACKET* PTRANSFER_PACKET; typedef VOID (*FT_TRANSFER_COMPLETION_ROUTINE)( IN PTRANSFER_PACKET TransferPacket ); typedef VOID (*FT_COMPLETION_ROUTINE)( IN PVOID Context, IN NTSTATUS Status ); class FT_VOLUME; typedef FT_VOLUME* PFT_VOLUME; typedef struct _FT_COMPLETION_ROUTINE_CONTEXT { KSPIN_LOCK SpinLock; NTSTATUS Status; LONG RefCount; FT_COMPLETION_ROUTINE CompletionRoutine; PVOID Context; PFT_VOLUME ParentVolume; } FT_COMPLETION_ROUTINE_CONTEXT, *PFT_COMPLETION_ROUTINE_CONTEXT; typedef PVOID (*FT_STATE_CHANGE_CALLBACK)( IN PVOID Context, IN FT_PARTITION_STATE MemberState ); class FT_BASE_CLASS; typedef FT_BASE_CLASS* PFT_BASE_CLASS; class FT_BASE_CLASS { public: static PVOID operator new( IN unsigned int Size ); static VOID operator delete( IN PVOID MemPtr ); }; class TRANSFER_PACKET : public FT_BASE_CLASS { public: TRANSFER_PACKET( ) { _freeMdl = FALSE; _freeBuffer = FALSE; SpecialRead = 0; }; virtual ~TRANSFER_PACKET( ); BOOLEAN AllocateMdl( IN PVOID Buffer, IN ULONG Length ); BOOLEAN AllocateMdl( IN ULONG Length ); VOID FreeMdl( ); // These fields must be filled in by the caller. PMDL Mdl; ULONG Length; LONGLONG Offset; FT_TRANSFER_COMPLETION_ROUTINE CompletionRoutine; PFT_VOLUME TargetVolume; PETHREAD Thread; UCHAR IrpFlags; BOOLEAN ReadPacket; UCHAR SpecialRead; // A spin lock which may be used to resolve contention for the // fields below. This spin lock must be initialized by the callee. KSPIN_LOCK SpinLock; // This field must be filled in by the callee. IO_STATUS_BLOCK IoStatus; // These fields are for use by the callee. LONG RefCount; LIST_ENTRY QueueEntry; private: BOOLEAN _freeMdl; BOOLEAN _freeBuffer; }; #define TP_SPECIAL_READ_PRIMARY (1) #define TP_SPECIAL_READ_SECONDARY (2) struct DEVICE_EXTENSION; typedef DEVICE_EXTENSION* PDEVICE_EXTENSION; class DISPATCH_TP; typedef DISPATCH_TP* PDISPATCH_TP; class DISPATCH_TP : public TRANSFER_PACKET { public: PIRP Irp; PDEVICE_EXTENSION Extension; }; class VOLUME_SET; typedef VOLUME_SET* PVOLUME_SET; class VOLSET_TP; typedef VOLSET_TP* PVOLSET_TP; class VOLSET_TP : public TRANSFER_PACKET { public: PTRANSFER_PACKET MasterPacket; PVOLUME_SET VolumeSet; ULONG WhichMember; }; class STRIPE; typedef STRIPE* PSTRIPE; class STRIPE_TP; typedef STRIPE_TP* PSTRIPE_TP; class STRIPE_TP : public TRANSFER_PACKET { public: PTRANSFER_PACKET MasterPacket; PSTRIPE Stripe; ULONG WhichMember; }; class OVERLAPPED_IO_MANAGER; typedef OVERLAPPED_IO_MANAGER* POVERLAPPED_IO_MANAGER; class OVERLAP_TP; typedef OVERLAP_TP* POVERLAP_TP; class OVERLAP_TP : public TRANSFER_PACKET { friend class OVERLAPPED_IO_MANAGER; public: OVERLAP_TP( ) { InQueue = FALSE; }; virtual ~OVERLAP_TP( ); private: BOOLEAN AllMembers; BOOLEAN InQueue; LIST_ENTRY OverlapQueue; LIST_ENTRY CompletionList; POVERLAPPED_IO_MANAGER OverlappedIoManager; }; class MIRROR; typedef MIRROR* PMIRROR; class MIRROR_TP; typedef MIRROR_TP* PMIRROR_TP; class MIRROR_TP : public OVERLAP_TP { public: MIRROR_TP( ) { OneReadFailed = FALSE; }; PTRANSFER_PACKET MasterPacket; PMIRROR Mirror; ULONG WhichMember; BOOLEAN OneReadFailed; PMIRROR_TP SecondWritePacket; FT_TRANSFER_COMPLETION_ROUTINE SavedCompletionRoutine; }; class MIRROR_RECOVER_TP; typedef MIRROR_RECOVER_TP* PMIRROR_RECOVER_TP; class MIRROR_RECOVER_TP : public MIRROR_TP { public: MIRROR_RECOVER_TP( ) { PartialMdl = NULL; VerifyMdl = NULL; }; virtual ~MIRROR_RECOVER_TP( ); BOOLEAN AllocateMdls( IN ULONG Length ); VOID FreeMdls( ); PMDL PartialMdl; PMDL VerifyMdl; }; class PARITY_IO_MANAGER; typedef PARITY_IO_MANAGER* PPARITY_IO_MANAGER; class PARITY_TP; typedef PARITY_TP* PPARITY_TP; class PARITY_TP : public TRANSFER_PACKET { friend class PARITY_IO_MANAGER; friend VOID UpdateParityCompletionRoutine( IN OUT PTRANSFER_PACKET TransferPacket ); private: BOOLEAN Idle; LIST_ENTRY OverlapQueue; LIST_ENTRY UpdateQueue; PPARITY_IO_MANAGER ParityIoManager; LONGLONG BucketNumber; }; class STRIPE_WP; typedef STRIPE_WP* PSTRIPE_WP; class SWP_TP; typedef SWP_TP* PSWP_TP; class SWP_TP : public OVERLAP_TP { public: PTRANSFER_PACKET MasterPacket; PSTRIPE_WP StripeWithParity; ULONG WhichMember; FT_TRANSFER_COMPLETION_ROUTINE SavedCompletionRoutine; BOOLEAN OneReadFailed; }; class SWP_RECOVER_TP; typedef SWP_RECOVER_TP* PSWP_RECOVER_TP; class SWP_RECOVER_TP : public SWP_TP { public: SWP_RECOVER_TP( ) { PartialMdl = NULL; VerifyMdl = NULL; }; virtual ~SWP_RECOVER_TP( ); BOOLEAN AllocateMdls( IN ULONG Length ); VOID FreeMdls( ); PMDL PartialMdl; PMDL VerifyMdl; }; class SWP_WRITE_TP; typedef SWP_WRITE_TP* PSWP_WRITE_TP; class SWP_WRITE_TP : public SWP_TP { public: SWP_WRITE_TP( ) { ReadAndParityMdl = NULL; WriteMdl = NULL; }; virtual ~SWP_WRITE_TP( ); BOOLEAN AllocateMdls( IN ULONG Length ); VOID FreeMdls( ); PMDL ReadAndParityMdl; PMDL WriteMdl; FT_PARTITION_STATE TargetState; ULONG ParityMember; SWP_TP ReadWritePacket; PARITY_TP ParityPacket; }; class SWP_REGENERATE_TP; typedef SWP_REGENERATE_TP *PSWP_REGENERATE_TP; class SWP_REGENERATE_TP : public TRANSFER_PACKET { public: PSWP_TP MasterPacket; ULONG WhichMember; LIST_ENTRY RegenPacketList; }; class SWP_REBUILD_TP; typedef SWP_REBUILD_TP *PSWP_REBUILD_TP; class SWP_REBUILD_TP : public SWP_TP { public: PFT_COMPLETION_ROUTINE_CONTEXT Context; BOOLEAN Initialize; }; class OVERLAPPED_IO_MANAGER : public FT_BASE_CLASS { public: NTSTATUS Initialize( IN ULONG BucketSize ); VOID AcquireIoRegion( IN OUT POVERLAP_TP TransferPacket, IN BOOLEAN AllMembers ); VOID ReleaseIoRegion( IN OUT POVERLAP_TP TransferPacket ); VOID PromoteToAllMembers( IN OUT POVERLAP_TP TransferPacket ); OVERLAPPED_IO_MANAGER( ) { _spinLock = NULL; _ioQueue = NULL; }; ~OVERLAPPED_IO_MANAGER( ); private: ULONG _numQueues; ULONG _bucketSize; PKSPIN_LOCK _spinLock; PLIST_ENTRY _ioQueue; }; class PARITY_IO_MANAGER : public FT_BASE_CLASS { friend VOID UpdateParityCompletionRoutine( IN OUT PTRANSFER_PACKET TransferPacket ); public: NTSTATUS Initialize( IN ULONG BucketSize ); VOID StartReadForUpdateParity( IN LONGLONG Offset, IN ULONG Length, IN PFT_VOLUME TargetVolume, IN PETHREAD Thread, IN UCHAR IrpFlags ); VOID UpdateParity( IN OUT PPARITY_TP TransferPacket ); PARITY_IO_MANAGER( ) { _spinLock = NULL; _ioQueue = NULL; _ePacket = NULL; }; ~PARITY_IO_MANAGER( ); private: ULONG _numQueues; ULONG _bucketSize; PKSPIN_LOCK _spinLock; PLIST_ENTRY _ioQueue; // // Emergency packet. // PPARITY_TP _ePacket; BOOLEAN _ePacketInUse; BOOLEAN _ePacketQueueBeingServiced; LIST_ENTRY _ePacketQueue; KSPIN_LOCK _ePacketSpinLock; }; class PARTITION; typedef PARTITION* PPARTITION; class FT_VOLUME : public FT_BASE_CLASS { friend VOID SetMemberStateWorker( IN PVOID Context ); public: VOID Initialize( ); VOID SetMemberInformation( IN OUT PFT_VOLUME ParentVolume, IN PDEVICE_EXTENSION MemberExtension ) { _parentVolume = ParentVolume; _memberExtension = MemberExtension; }; PDEVICE_EXTENSION GetMemberExtension( ) { return _memberExtension; }; virtual VOID Transfer( IN OUT PTRANSFER_PACKET TransferPacket ) = 0; virtual VOID ReplaceBadSector( IN OUT PTRANSFER_PACKET TransferPacket ) = 0; virtual VOID StartSyncOperations( IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ) = 0; virtual BOOLEAN Regenerate( IN OUT PFT_VOLUME SpareVolume, IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ) = 0; virtual VOID FlushBuffers( IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ) = 0; virtual BOOLEAN IsPartition( ) = 0; virtual ULONG QueryNumberOfMembers( ) = 0; virtual PFT_VOLUME GetMember( IN ULONG MemberNumber ) = 0; virtual BOOLEAN IsCreatingCheckData( ) = 0; virtual VOID SetCheckDataDirty( ) = 0; virtual ULONG QuerySectorSize( ) = 0; virtual LONGLONG QueryVolumeSize( ) = 0; virtual FT_TYPE QueryVolumeType( ) = 0; virtual FT_STATE QueryVolumeState( ) = 0; virtual ULONG QueryAlignmentRequirement( ) = 0; virtual VOID SetFtBitInPartitionType( IN BOOLEAN Value, IN BOOLEAN SpecialBitValue ) = 0; virtual PPARTITION FindPartition( IN ULONG DiskNumber, IN ULONG PartitionNumber ) = 0; virtual PPARTITION FindPartition( IN ULONG Signature, IN LONGLONG Offset ) = 0; virtual BOOLEAN OrphanPartition( IN PPARTITION Partition ) = 0; virtual VOID MemberStateChangeNotification( IN PFT_VOLUME ChangedMember ); virtual ~FT_VOLUME( ); FT_PARTITION_STATE QueryMemberState( ); FT_PARTITION_STATE QueryMemberStateUnprotected( ) { return _memberState; }; VOID SetMemberState( IN FT_PARTITION_STATE MemberState ); VOID SetMemberStateWithoutNotification( IN FT_PARTITION_STATE MemberState ); protected: KSPIN_LOCK _spinLock; private: FT_PARTITION_STATE _memberState; PFT_VOLUME _parentVolume; PDEVICE_EXTENSION _memberExtension; }; #define TRANSFER(a) ((a)->TargetVolume->Transfer((a))) class PARTITION : public FT_VOLUME { friend VOID SetFtBitInPartitionTypeWorker( IN PVOID Context ); friend NTSTATUS PartitionTransferCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID TransferPacket ); public: PARTITION( ) { _emergencyIrp = NULL; }; virtual ~PARTITION( ); NTSTATUS Initialize( IN OUT PDEVICE_OBJECT TargetObject, IN ULONG SectorSize, IN ULONG DiskSignature, IN LONGLONG PartitionOffset, IN LONGLONG PartitionLength, IN BOOLEAN IsOnline, IN ULONG DiskNumber, IN ULONG PartitionNumber ); virtual VOID Transfer( IN OUT PTRANSFER_PACKET TransferPacket ); virtual VOID ReplaceBadSector( IN OUT PTRANSFER_PACKET TransferPacket ); virtual VOID StartSyncOperations( IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ); virtual BOOLEAN Regenerate( IN OUT PFT_VOLUME SpareVolume, IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ); virtual VOID FlushBuffers( IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ); virtual BOOLEAN IsPartition( ); virtual ULONG QueryNumberOfMembers( ); virtual PFT_VOLUME GetMember( IN ULONG MemberNumber ); virtual BOOLEAN IsCreatingCheckData( ); virtual VOID SetCheckDataDirty( ); virtual ULONG QuerySectorSize( ); virtual LONGLONG QueryVolumeSize( ); virtual FT_TYPE QueryVolumeType( ); virtual FT_STATE QueryVolumeState( ); virtual ULONG QueryAlignmentRequirement( ); virtual VOID SetFtBitInPartitionType( IN BOOLEAN Value, IN BOOLEAN SpecialBitValue ); UCHAR QueryPartitionType( ); virtual PPARTITION FindPartition( IN ULONG DiskNumber, IN ULONG PartitionNumber ); virtual PPARTITION FindPartition( IN ULONG Signature, IN LONGLONG Offset ); virtual BOOLEAN OrphanPartition( IN PPARTITION Partition ); ULONG QueryDiskSignature( ) { return _diskSignature; }; LONGLONG QueryPartitionOffset( ) { return _partitionOffset; }; LONGLONG QueryPartitionLength( ) { return _partitionLength; }; BOOLEAN IsOnline( ) { return _isOnline; }; ULONG QueryDiskNumber( ) { return _diskNumber; }; ULONG QueryPartitionNumber( ) { return _partitionNumber; }; private: PDEVICE_OBJECT _targetObject; ULONG _sectorSize; ULONG _diskSignature; LONGLONG _partitionOffset; LONGLONG _partitionLength; BOOLEAN _isOnline; ULONG _diskNumber; ULONG _partitionNumber; PIRP _emergencyIrp; BOOLEAN _emergencyIrpInUse; LIST_ENTRY _emergencyIrpQueue; }; class COMPOSITE_FT_VOLUME; typedef COMPOSITE_FT_VOLUME *PCOMPOSITE_FT_VOLUME; class COMPOSITE_FT_VOLUME : public FT_VOLUME { public: virtual NTSTATUS Initialize( IN OUT PFT_VOLUME* VolumeArray, IN ULONG ArraySize ); virtual VOID Transfer( IN OUT PTRANSFER_PACKET TransferPacket ) = 0; virtual VOID ReplaceBadSector( IN OUT PTRANSFER_PACKET TransferPacket ) = 0; virtual VOID StartSyncOperations( IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ); virtual BOOLEAN Regenerate( IN OUT PFT_VOLUME SpareVolume, IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ); virtual VOID FlushBuffers( IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ); virtual BOOLEAN IsPartition( ); virtual ULONG QueryNumberOfMembers( ); virtual PFT_VOLUME GetMember( IN ULONG MemberNumber ); virtual BOOLEAN IsCreatingCheckData( ) = 0; virtual VOID SetCheckDataDirty( ) = 0; virtual ULONG QuerySectorSize( ); virtual LONGLONG QueryVolumeSize( ) = 0; virtual FT_TYPE QueryVolumeType( ) = 0; virtual FT_STATE QueryVolumeState( ) = 0; virtual ULONG QueryAlignmentRequirement( ); virtual VOID SetFtBitInPartitionType( IN BOOLEAN Value, IN BOOLEAN SpecialBitValue ); virtual PPARTITION FindPartition( IN ULONG DiskNumber, IN ULONG PartitionNumber ); virtual PPARTITION FindPartition( IN ULONG Signature, IN LONGLONG Offset ); virtual BOOLEAN OrphanPartition( IN PPARTITION Partition ); VOID SetMember( IN ULONG MemberNumber, IN PFT_VOLUME NewVolume ); COMPOSITE_FT_VOLUME( ) { _volumeArray = NULL; }; virtual ~COMPOSITE_FT_VOLUME( ); protected: PFT_VOLUME GetMemberUnprotected( IN ULONG MemberNumber ) { return _volumeArray[MemberNumber]; }; VOID SetMemberUnprotected( IN ULONG MemberNumber, IN PFT_VOLUME NewVolume ) { _volumeArray[MemberNumber] = NewVolume; }; ULONG QueryNumMembers( ) { return _arraySize; }; private: PFT_VOLUME* _volumeArray; ULONG _arraySize; ULONG _sectorSize; }; class VOLUME_SET : public COMPOSITE_FT_VOLUME { friend VOID VolsetTransferSequentialCompletionRoutine( IN PTRANSFER_PACKET TransferPacket ); public: VOLUME_SET( ) { _ePacket = NULL; }; virtual ~VOLUME_SET( ); virtual NTSTATUS Initialize( IN OUT PFT_VOLUME* VolumeArray, IN ULONG ArraySize ); virtual VOID Transfer( IN OUT PTRANSFER_PACKET TransferPacket ); virtual VOID ReplaceBadSector( IN OUT PTRANSFER_PACKET TransferPacket ); virtual BOOLEAN IsCreatingCheckData( ); virtual VOID SetCheckDataDirty( ); virtual LONGLONG QueryVolumeSize( ); virtual FT_TYPE QueryVolumeType( ); virtual FT_STATE QueryVolumeState( ); private: BOOLEAN LaunchParallel( IN OUT PTRANSFER_PACKET TransferPacket ); VOID LaunchSequential( IN OUT PTRANSFER_PACKET TransferPacket ); LONGLONG _volumeSize; PVOLSET_TP _ePacket; BOOLEAN _ePacketInUse; LIST_ENTRY _ePacketQueue; }; class STRIPE : public COMPOSITE_FT_VOLUME { friend VOID StripeSequentialTransferCompletionRoutine( IN PTRANSFER_PACKET TransferPacket ); public: STRIPE( IN ULONG StripeSize ) { _stripeSize = StripeSize; _ePacket = NULL; }; virtual ~STRIPE( ); virtual NTSTATUS Initialize( IN OUT PFT_VOLUME* VolumeArray, IN ULONG ArraySize ); virtual VOID Transfer( IN OUT PTRANSFER_PACKET TransferPacket ); virtual VOID ReplaceBadSector( IN OUT PTRANSFER_PACKET TransferPacket ); virtual BOOLEAN IsCreatingCheckData( ); virtual VOID SetCheckDataDirty( ); virtual LONGLONG QueryVolumeSize( ); virtual FT_TYPE QueryVolumeType( ); virtual FT_STATE QueryVolumeState( ); private: BOOLEAN LaunchParallel( IN OUT PTRANSFER_PACKET TransferPacket ); VOID LaunchSequential( IN OUT PTRANSFER_PACKET TransferPacket ); ULONG _stripeSize; LONGLONG _memberSize; LONGLONG _volumeSize; PSTRIPE_TP _ePacket; BOOLEAN _ePacketInUse; LIST_ENTRY _ePacketQueue; }; class MIRROR : public COMPOSITE_FT_VOLUME { friend VOID FinishRegenerate( IN PMIRROR Mirror, IN PFT_COMPLETION_ROUTINE_CONTEXT RegenContext, IN PMIRROR_TP TransferPacket ); friend VOID MirrorRegenerateCompletionRoutine( IN PTRANSFER_PACKET TransferPacket ); friend VOID StartRegeneration( IN PVOID Context, IN NTSTATUS Status ); friend VOID MirrorTransferCompletionRoutine( IN PTRANSFER_PACKET TransferPacket ); friend VOID MirrorRecoverPhase8( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID MirrorRecoverPhase7( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID MirrorRecoverPhase6( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID MirrorRecoverPhase5( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID MirrorRecoverPhase4( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID MirrorRecoverPhase3( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID MirrorRecoverPhase2( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID MirrorRecoverEmergencyCompletion( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID MirrorRecoverPhase1( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID MirrorMaxTransferCompletionRoutine( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID MirrorMaxTransferEmergencyCompletion( IN OUT PTRANSFER_PACKET TransferPacket ); public: virtual ~MIRROR( ); virtual NTSTATUS Initialize( IN OUT PFT_VOLUME* VolumeArray, IN ULONG ArraySize ); virtual VOID Transfer( IN OUT PTRANSFER_PACKET TransferPacket ); virtual VOID ReplaceBadSector( IN OUT PTRANSFER_PACKET TransferPacket ); virtual VOID StartSyncOperations( IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ); virtual BOOLEAN Regenerate( IN OUT PFT_VOLUME SpareVolume, IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ); virtual BOOLEAN IsCreatingCheckData( ); virtual VOID SetCheckDataDirty( ); virtual LONGLONG QueryVolumeSize( ); virtual FT_TYPE QueryVolumeType( ); virtual FT_STATE QueryVolumeState( ); virtual BOOLEAN OrphanPartition( IN PPARTITION Partition ); virtual VOID MemberStateChangeNotification( IN PFT_VOLUME ChangedMember ); MIRROR( IN PDEVICE_EXTENSION Extension ) { _extension = Extension; _ePacket = NULL; _ePacket2 = NULL; _eRecoverPacket = NULL; }; private: VOID IncrementRequestCount( IN ULONG MemberNumber ) { _requestCount[MemberNumber]++; }; BOOLEAN DecrementRequestCount( IN ULONG MemberNumber ); BOOLEAN LaunchRead( IN OUT PTRANSFER_PACKET TransferPacket, IN OUT PMIRROR_TP Packet1 ); BOOLEAN LaunchWrite( IN OUT PTRANSFER_PACKET TransferPacket, IN OUT PMIRROR_TP Packet1, IN OUT PMIRROR_TP Packet2 ); VOID Recycle( IN OUT PMIRROR_TP TransferPacket, IN BOOLEAN ServiceEmergencyQueue ); VOID Recover( IN OUT PMIRROR_TP TransferPacket ); VOID MaxTransfer( IN OUT PMIRROR_TP TransferPacket ); PDEVICE_EXTENSION _extension; LONGLONG _volumeSize; // // State for keeping track of outstanding requests. // LONG _requestCount[2]; FT_COMPLETION_ROUTINE _waitingForOrphanIdle; PVOID _waitingForOrphanIdleContext; ULONG _waitingOrphanNumber; // // Indicates whether or not 'StartSyncOperations' is expected. // BOOLEAN _syncExpected; // // Emergency packet. // PMIRROR_TP _ePacket, _ePacket2; BOOLEAN _ePacketInUse; LIST_ENTRY _ePacketQueue; // // Emergency recover packet. // PMIRROR_RECOVER_TP _eRecoverPacket; BOOLEAN _eRecoverPacketInUse; LIST_ENTRY _eRecoverPacketQueue; // // Overlapped io manager. // OVERLAPPED_IO_MANAGER _overlappedIoManager; }; class STRIPE_WP : public COMPOSITE_FT_VOLUME { friend VOID StripeWpSyncFinalCompletion( IN PVOID Context, IN NTSTATUS Status ); friend VOID StripeWpSyncCompletionRoutine( IN PTRANSFER_PACKET TransferPacket ); friend VOID StartStripeRegeneration( IN PVOID Context, IN NTSTATUS Status ); friend VOID StripeWpParallelTransferCompletionRoutine( IN PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpSequentialTransferCompletionRoutine( IN PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpWritePhase31( IN OUT PTRANSFER_PACKET Packet ); friend VOID StripeWpWritePhase30( IN OUT PTRANSFER_PACKET Packet ); friend VOID StripeWpWritePhase2( IN OUT PTRANSFER_PACKET ReadPacket ); friend VOID StripeWpWritePhase1( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpSequentialRegenerateCompletion( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpSequentialEmergencyCompletion( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpParallelRegenerateCompletion( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpRegeneratePacketPhase1( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpRecoverPhase8( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpRecoverPhase7( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpRecoverPhase6( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpRecoverPhase5( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpRecoverPhase4( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpRecoverPhase3( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpRecoverPhase2( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpRecoverEmergencyCompletion( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpRecoverPhase1( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpMaxTransferCompletionRoutine( IN OUT PTRANSFER_PACKET TransferPacket ); friend VOID StripeWpMaxTransferEmergencyCompletion( IN OUT PTRANSFER_PACKET TransferPacket ); public: virtual NTSTATUS Initialize( IN OUT PFT_VOLUME* VolumeArray, IN ULONG ArraySize ); virtual VOID Transfer( IN OUT PTRANSFER_PACKET TransferPacket ); virtual VOID ReplaceBadSector( IN OUT PTRANSFER_PACKET TransferPacket ); virtual VOID StartSyncOperations( IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ); virtual BOOLEAN Regenerate( IN OUT PFT_VOLUME SpareVolume, IN FT_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context ); virtual BOOLEAN IsCreatingCheckData( ); virtual VOID SetCheckDataDirty( ); virtual LONGLONG QueryVolumeSize( ); virtual FT_TYPE QueryVolumeType( ); virtual FT_STATE QueryVolumeState( ); virtual BOOLEAN OrphanPartition( IN PPARTITION Partition ); STRIPE_WP( IN PDEVICE_EXTENSION Extension, IN ULONG StripeSize ); virtual ~STRIPE_WP( ); private: VOID IncrementRequestCount( IN ULONG MemberNumber ) { _requestCount[MemberNumber]++; }; BOOLEAN DecrementRequestCount( IN ULONG MemberNumber ); BOOLEAN LaunchParallel( IN OUT PTRANSFER_PACKET TransferPacket ); VOID LaunchSequential( IN OUT PTRANSFER_PACKET TransferPacket ); VOID ReadPacket( IN OUT PSWP_TP TransferPacket ); VOID WritePacket( IN OUT PSWP_WRITE_TP TransferPacket ); VOID RegeneratePacket( IN OUT PSWP_TP TransferPacket, IN BOOLEAN AllocateRegion ); VOID Recover( IN OUT PSWP_TP TransferPacket ); VOID MaxTransfer( IN OUT PSWP_TP TransferPacket ); VOID RecycleRecoverTp( IN OUT PSWP_RECOVER_TP TransferPacket ); PDEVICE_EXTENSION _extension; ULONG _stripeSize; LONGLONG _memberSize; LONGLONG _volumeSize; // // State for creating check data. // BOOLEAN _initializing; // // Indicates whether or not 'StartSyncOperations' is expected. // BOOLEAN _syncExpected; // // State for keeping track of outstanding requests. // PLONG _requestCount; FT_COMPLETION_ROUTINE _waitingForOrphanIdle; PVOID _waitingForOrphanIdleContext; ULONG _waitingOrphanNumber; // // State for keeping track of overlapping write requests. // One OVERLAPPED_IO_MANAGER for each member. // OVERLAPPED_IO_MANAGER _overlappedIoManager; // // State for serializing parity I/O. // PARITY_IO_MANAGER _parityIoManager; // // Emergency read/write packet. // PSWP_WRITE_TP _ePacket; BOOLEAN _ePacketInUse; BOOLEAN _ePacketQueueBeingServiced; LIST_ENTRY _ePacketQueue; // // Emergency regenerate packet. // PSWP_REGENERATE_TP _eRegeneratePacket; BOOLEAN _eRegeneratePacketInUse; LIST_ENTRY _eRegeneratePacketQueue; // // Emergency recover packet. // PSWP_RECOVER_TP _eRecoverPacket; BOOLEAN _eRecoverPacketInUse; LIST_ENTRY _eRecoverPacketQueue; }; struct DEVICE_EXTENSION { // // Pointer to the device object for this extension. // PDEVICE_OBJECT DeviceObject; // 00 // // The logical disk and partition number - filled in during initialization. // A DiskNumber of -1 indicated the root extension. A PartitionNumber of // 1 or greater implies a partition while a PartitionNumber of 0 implies // a whole disk if DiskNumber >= 0. // ULONG DiskNumber; // 04 ULONG PartitionNumber; // 08 // // Pointer to the root device extension. // PDEVICE_EXTENSION Root; // 0C // // The device object on which this device object is layered. // PDEVICE_OBJECT TargetObject; // 10 union { struct { // // A pointer to the FT_VOLUME that will handle READ and WRITE // requests. // Protect with 'SpinLock' below. Also, use a 'RefCount' to // keep track of how many activities are taking place on the // volume. // PFT_VOLUME FtVolume; // 14 LONG RefCount; // 18 // // \Harddisk(N)\Partition(M) -> \Harddisk(N)\Partition(M+1) // Protect with 'SpinLock' below. // PDEVICE_EXTENSION PartitionChain; // 1C // // Pointer to the Whole disk extension for this partition. // PDEVICE_EXTENSION WholeDisk; // 20 // // Parameters about the partition that this is layered above. // LARGE_INTEGER PartitionOffset; // 28 LARGE_INTEGER PartitionLength; // 30 // // Emergency queue for a transfer packet. // PDISPATCH_TP EmergencyTransferPacket; LIST_ENTRY EmergencyTransferPacketQueue; BOOLEAN EmergencyTransferPacketInUse; } Partition; struct { // // \Harddisk(N)\Paritition0 -> \Harddisk(N+1)\Partition0 // Protect with 'SpinLock' below. // PDEVICE_EXTENSION DiskChain; // 14 // // Points to \Harddisk(N)\Partition(1) // Protect with 'SpinLock' below. // PDEVICE_EXTENSION PartitionChain; // 18 // // Parameters about the partition that this is layered above. // Protect with 'SpinLock' below. // DISK_GEOMETRY DiskGeometry; // 20 ULONG Signature; // 38 } WholeDisk; struct { // // Pointer to the driver object. // PDRIVER_OBJECT DriverObject; // 14 // // Points to \Harddisk0\Partition0 // Protect with 'SpinLock' below. // PDEVICE_EXTENSION DiskChain; // 18 // // The number of disks found so far. // ULONG NumberOfDisks; // 1C } Root; } u; // // A spin lock to protect certain fields of this extension. // KSPIN_LOCK SpinLock; // 3C }; BOOLEAN FtpIsWorseStatus( IN NTSTATUS Status1, IN NTSTATUS Status2 ); VOID FtpDisolveVolume( IN PDEVICE_EXTENSION Extension, IN PFT_VOLUME Volume ); VOID FtpComputeParity( IN PVOID TargetBuffer, IN PVOID SourceBuffer, IN ULONG BufferLength ); NTSTATUS FtpReturnRegistryInformation( IN PCHAR ValueName, IN OUT PVOID *FreePoolAddress, IN OUT PVOID *Information ); NTSTATUS FtpWriteRegistryInformation( IN PCHAR ValueName, IN PVOID Information, IN ULONG InformationLength ); VOID FtpLogError( IN PDEVICE_EXTENSION DeviceExtension, IN NTSTATUS SpecificIoStatus, IN NTSTATUS FinalStatus, IN ULONG UniqueErrorValue, IN PIRP Irp );