From: Owen Smith Date: Wed, 5 Apr 2017 12:35:36 +0000 (+0100) Subject: Rename Pdo -> Target X-Git-Tag: 9.0.0-rc1~95 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=9a5699025c29ca8cf5763fa4912d090641835708;p=pvdrivers%2Fwin%2Fxenvbd.git Rename Pdo -> Target Signed-off-by: Owen Smith --- diff --git a/src/xenvbd/adapter.c b/src/xenvbd/adapter.c index 6e0f94d..4782ed3 100644 --- a/src/xenvbd/adapter.c +++ b/src/xenvbd/adapter.c @@ -48,7 +48,7 @@ #include "adapter.h" #include "driver.h" #include "registry.h" -#include "pdo.h" +#include "target.h" #include "srbext.h" #include "thread.h" #include "buffer.h" @@ -89,7 +89,7 @@ struct _XENVBD_ADAPTER { // Targets KSPIN_LOCK TargetLock; - PXENVBD_PDO Targets[XENVBD_MAX_TARGETS]; + PXENVBD_TARGET Targets[XENVBD_MAX_TARGETS]; // Target Enumeration PXENVBD_THREAD ScanThread; @@ -141,97 +141,97 @@ __AdapterGetDevicePowerState( } __checkReturn -static FORCEINLINE PXENVBD_PDO -__AdapterGetPdoAlways( +static FORCEINLINE PXENVBD_TARGET +__AdapterGetTargetAlways( __in PXENVBD_ADAPTER Adapter, __in ULONG TargetId, __in PCHAR Caller ) { - PXENVBD_PDO Pdo; + PXENVBD_TARGET Target; KIRQL Irql; ASSERT3U(TargetId, <, XENVBD_MAX_TARGETS); KeAcquireSpinLock(&Adapter->TargetLock, &Irql); - Pdo = Adapter->Targets[TargetId]; - if (Pdo) { - __PdoReference(Pdo, Caller); + Target = Adapter->Targets[TargetId]; + if (Target) { + __TargetReference(Target, Caller); } KeReleaseSpinLock(&Adapter->TargetLock, Irql); - return Pdo; + return Target; } __checkReturn -static FORCEINLINE PXENVBD_PDO -___AdapterGetPdo( +static FORCEINLINE PXENVBD_TARGET +___AdapterGetTarget( __in PXENVBD_ADAPTER Adapter, __in ULONG TargetId, __in PCHAR Caller ) { - PXENVBD_PDO Pdo = NULL; + PXENVBD_TARGET Target = NULL; KIRQL Irql; ASSERT3U(TargetId, <, XENVBD_MAX_TARGETS); KeAcquireSpinLock(&Adapter->TargetLock, &Irql); if (Adapter->Targets[TargetId] && - __PdoReference(Adapter->Targets[TargetId], Caller) > 0) { - Pdo = Adapter->Targets[TargetId]; + __TargetReference(Adapter->Targets[TargetId], Caller) > 0) { + Target = Adapter->Targets[TargetId]; } KeReleaseSpinLock(&Adapter->TargetLock, Irql); - return Pdo; + return Target; } -#define __AdapterGetPdo(f, t) ___AdapterGetPdo(f, t, __FUNCTION__) +#define __AdapterGetTarget(f, t) ___AdapterGetTarget(f, t, __FUNCTION__) BOOLEAN -AdapterLinkPdo( +AdapterLinkTarget( __in PXENVBD_ADAPTER Adapter, - __in PXENVBD_PDO Pdo + __in PXENVBD_TARGET Target ) { KIRQL Irql; - PXENVBD_PDO Current; + PXENVBD_TARGET Current; BOOLEAN Result = FALSE; - ULONG TargetId = PdoGetTargetId(Pdo); + ULONG TargetId = TargetGetTargetId(Target); KeAcquireSpinLock(&Adapter->TargetLock, &Irql); Current = Adapter->Targets[TargetId]; if (Adapter->Targets[TargetId] == NULL) { - Adapter->Targets[TargetId] = Pdo; + Adapter->Targets[TargetId] = Target; Result = TRUE; } KeReleaseSpinLock(&Adapter->TargetLock, Irql); if (!Result) { - Warning("Target[%d] : Current 0x%p, New 0x%p\n", TargetId, Current, Pdo); + Warning("Target[%d] : Current 0x%p, New 0x%p\n", TargetId, Current, Target); } return Result; } BOOLEAN -AdapterUnlinkPdo( +AdapterUnlinkTarget( __in PXENVBD_ADAPTER Adapter, - __in PXENVBD_PDO Pdo + __in PXENVBD_TARGET Target ) { KIRQL Irql; - PXENVBD_PDO Current; + PXENVBD_TARGET Current; BOOLEAN Result = FALSE; - ULONG TargetId = PdoGetTargetId(Pdo); + ULONG TargetId = TargetGetTargetId(Target); KeAcquireSpinLock(&Adapter->TargetLock, &Irql); Current = Adapter->Targets[TargetId]; - if (Adapter->Targets[TargetId] == Pdo) { + if (Adapter->Targets[TargetId] == Target) { Adapter->Targets[TargetId] = NULL; Result = TRUE; } KeReleaseSpinLock(&Adapter->TargetLock, Irql); if (!Result) { - Warning("Target[%d] : Current 0x%p, Expected 0x%p\n", TargetId, Current, Pdo); + Warning("Target[%d] : Current 0x%p, Expected 0x%p\n", TargetId, Current, Target); } return Result; } @@ -367,21 +367,21 @@ AdapterDebugCallback( BufferDebugCallback(&Adapter->Debug); for (TargetId = 0; TargetId < XENVBD_MAX_TARGETS; ++TargetId) { - // no need to use __AdapterGetPdo (which is locked at DISPATCH) as called at HIGH_LEVEL - PXENVBD_PDO Pdo = Adapter->Targets[TargetId]; - if (Pdo == NULL) + // no need to use __AdapterGetTarget (which is locked at DISPATCH) as called at HIGH_LEVEL + PXENVBD_TARGET Target = Adapter->Targets[TargetId]; + if (Target == NULL) continue; XENBUS_DEBUG(Printf, &Adapter->Debug, "ADAPTER: ====> Target[%-3d] : 0x%p\n", - TargetId, Pdo); + TargetId, Target); // call Target's debug callback directly - PdoDebugCallback(Pdo, &Adapter->Debug); + TargetDebugCallback(Target, &Adapter->Debug); XENBUS_DEBUG(Printf, &Adapter->Debug, "ADAPTER: <==== Target[%-3d] : 0x%p\n", - TargetId, Pdo); + TargetId, Target); } Adapter->MaximumSrbs = Adapter->CurrentSrbs; @@ -490,7 +490,7 @@ ignore: } __checkReturn static FORCEINLINE BOOLEAN -__AdapterIsPdoUnplugged( +__AdapterIsTargetUnplugged( __in PXENVBD_ADAPTER Adapter, __in PCHAR Enumerator, __in PCHAR Device, @@ -534,7 +534,7 @@ __AdapterEnumerate( ULONG TargetId; PANSI_STRING Device; ULONG Index; - PXENVBD_PDO Pdo; + PXENVBD_TARGET Target; *NeedInvalidate = FALSE; *NeedReboot = FALSE; @@ -542,8 +542,8 @@ __AdapterEnumerate( for (TargetId = 0; TargetId < XENVBD_MAX_TARGETS; ++TargetId) { BOOLEAN Missing = TRUE; - Pdo = __AdapterGetPdo(Adapter, TargetId); - if (Pdo == NULL) + Target = __AdapterGetTarget(Adapter, TargetId); + if (Target == NULL) continue; for (Index = 0; Devices[Index].Buffer != NULL; ++Index) { @@ -556,19 +556,19 @@ __AdapterEnumerate( } } - if (Missing && !PdoIsMissing(Pdo)) { - PdoSetMissing(Pdo, "Device Disappeared"); - if (PdoGetDevicePnpState(Pdo) == Present) - PdoSetDevicePnpState(Pdo, Deleted); + if (Missing && !TargetIsMissing(Target)) { + TargetSetMissing(Target, "Device Disappeared"); + if (TargetGetDevicePnpState(Target) == Present) + TargetSetDevicePnpState(Target, Deleted); else *NeedInvalidate = TRUE; } - if (PdoGetDevicePnpState(Pdo) == Deleted) { - PdoDereference(Pdo); - PdoDestroy(Pdo); + if (TargetGetDevicePnpState(Target) == Deleted) { + TargetDereference(Target); + TargetDestroy(Target); } else { - PdoDereference(Pdo); + TargetDereference(Target); } } @@ -583,9 +583,9 @@ __AdapterEnumerate( continue; } - Pdo = __AdapterGetPdo(Adapter, TargetId); - if (Pdo) { - PdoDereference(Pdo); + Target = __AdapterGetTarget(Adapter, TargetId); + if (Target) { + TargetDereference(Target); continue; } @@ -593,7 +593,7 @@ __AdapterEnumerate( continue; } - if (!__AdapterIsPdoUnplugged(Adapter, + if (!__AdapterIsTargetUnplugged(Adapter, AdapterEnum(Adapter), Device->Buffer, TargetId)) { @@ -601,7 +601,7 @@ __AdapterEnumerate( continue; } - if (PdoCreate(Adapter, + if (TargetCreate(Adapter, Device->Buffer, TargetId, DeviceType)) { @@ -1340,12 +1340,12 @@ AdapterD3ToD0( if (!NT_SUCCESS(Status)) goto fail2; - // Power UP any PDOs + // Power UP any TARGETs for (TargetId = 0; TargetId < XENVBD_MAX_TARGETS; ++TargetId) { - PXENVBD_PDO Pdo = __AdapterGetPdo(Adapter, TargetId); - if (Pdo) { - Status = PdoD3ToD0(Pdo); - PdoDereference(Pdo); + PXENVBD_TARGET Target = __AdapterGetTarget(Adapter, TargetId); + if (Target) { + Status = TargetD3ToD0(Target); + TargetDereference(Target); if (!NT_SUCCESS(Status)) goto fail3; @@ -1382,10 +1382,10 @@ fail3: Error("Fail3\n"); for (TargetId = 0; TargetId < XENVBD_MAX_TARGETS; ++TargetId) { - PXENVBD_PDO Pdo = __AdapterGetPdo(Adapter, TargetId); - if (Pdo) { - PdoD0ToD3(Pdo); - PdoDereference(Pdo); + PXENVBD_TARGET Target = __AdapterGetTarget(Adapter, TargetId); + if (Target) { + TargetD0ToD3(Target); + TargetDereference(Target); } } @@ -1423,12 +1423,12 @@ AdapterD0ToD3( __AdapterD0ToD3(Adapter); - // Power DOWN any PDOs + // Power DOWN any TARGETs for (TargetId = 0; TargetId < XENVBD_MAX_TARGETS; ++TargetId) { - PXENVBD_PDO Pdo = __AdapterGetPdo(Adapter, TargetId); - if (Pdo) { - PdoD0ToD3(Pdo); - PdoDereference(Pdo); + PXENVBD_TARGET Target = __AdapterGetTarget(Adapter, TargetId); + if (Target) { + TargetD0ToD3(Target); + TargetDereference(Target); } } @@ -1605,16 +1605,16 @@ __AdapterTerminate( // delete targets for (TargetId = 0; TargetId < XENVBD_MAX_TARGETS; ++TargetId) { - PXENVBD_PDO Pdo = __AdapterGetPdoAlways(Adapter, TargetId, __FUNCTION__); - if (Pdo) { - // Pdo may not be in Deleted state yet, force it as Adapter is terminating - if (PdoGetDevicePnpState(Pdo) != Deleted) - PdoSetDevicePnpState(Pdo, Deleted); + PXENVBD_TARGET Target = __AdapterGetTargetAlways(Adapter, TargetId, __FUNCTION__); + if (Target) { + // Target may not be in Deleted state yet, force it as Adapter is terminating + if (TargetGetDevicePnpState(Target) != Deleted) + TargetSetDevicePnpState(Target, Deleted); // update missing (for debug output more than anything else - PdoSetMissing(Pdo, "AdapterTerminate"); - // drop ref-count acquired in __AdapterGetPdo *before* destroying Pdo - PdoDereference(Pdo); - PdoDestroy(Pdo); + TargetSetMissing(Target, "AdapterTerminate"); + // drop ref-count acquired in __AdapterGetTarget *before* destroying Target + TargetDereference(Target); + TargetDestroy(Target); } } @@ -1708,10 +1708,10 @@ AdapterResetBus( Verbose("====>\n"); for (TargetId = 0; TargetId < XENVBD_MAX_TARGETS; ++TargetId) { - PXENVBD_PDO Pdo = __AdapterGetPdo(Adapter, TargetId); - if (Pdo) { - PdoReset(Pdo); - PdoDereference(Pdo); + PXENVBD_TARGET Target = __AdapterGetTarget(Adapter, TargetId); + if (Target) { + TargetReset(Target); + TargetDereference(Target); } } Verbose("<====\n"); @@ -1792,12 +1792,12 @@ __AdapterSrbPnp( ) { if (!(Srb->SrbPnPFlags & SRB_PNP_FLAGS_ADAPTER_REQUEST)) { - PXENVBD_PDO Pdo; + PXENVBD_TARGET Target; - Pdo = __AdapterGetPdo(Adapter, Srb->TargetId); - if (Pdo) { - PdoSrbPnp(Pdo, Srb); - PdoDereference(Pdo); + Target = __AdapterGetTarget(Adapter, Srb->TargetId); + if (Target) { + TargetSrbPnp(Target, Srb); + TargetDereference(Target); } } } @@ -1845,13 +1845,13 @@ AdapterStartIo( __in PSCSI_REQUEST_BLOCK Srb ) { - PXENVBD_PDO Pdo; + PXENVBD_TARGET Target; BOOLEAN CompleteSrb = TRUE; - Pdo = __AdapterGetPdo(Adapter, Srb->TargetId); - if (Pdo) { - CompleteSrb = PdoStartIo(Pdo, Srb); - PdoDereference(Pdo); + Target = __AdapterGetTarget(Adapter, Srb->TargetId); + if (Target) { + CompleteSrb = TargetStartIo(Target, Srb); + TargetDereference(Target); } if (CompleteSrb) { @@ -1860,8 +1860,8 @@ AdapterStartIo( return TRUE; } -static PXENVBD_PDO -AdapterGetPdoFromDeviceObject( +static PXENVBD_TARGET +AdapterGetTargetFromDeviceObject( __in PXENVBD_ADAPTER Adapter, __in PDEVICE_OBJECT DeviceObject ) @@ -1871,24 +1871,24 @@ AdapterGetPdoFromDeviceObject( ASSERT3P(DeviceObject, !=, NULL); for (TargetId = 0; TargetId < XENVBD_MAX_TARGETS; ++TargetId) { - PXENVBD_PDO Pdo = __AdapterGetPdo(Adapter, TargetId); - if (Pdo) { - if (PdoGetDeviceObject(Pdo) == DeviceObject) - return Pdo; - PdoDereference(Pdo); + PXENVBD_TARGET Target = __AdapterGetTarget(Adapter, TargetId); + if (Target) { + if (TargetGetDeviceObject(Target) == DeviceObject) + return Target; + TargetDereference(Target); } } return NULL; } -static PXENVBD_PDO -AdapterMapDeviceObjectToPdo( +static PXENVBD_TARGET +AdapterMapDeviceObjectToTarget( __in PXENVBD_ADAPTER Adapter, __in PDEVICE_OBJECT DeviceObject ) { - PXENVBD_PDO Pdo; + PXENVBD_TARGET Target; KEVENT Complete; PIRP Irp; IO_STATUS_BLOCK StatusBlock; @@ -1939,14 +1939,14 @@ AdapterMapDeviceObjectToPdo( if (!NT_SUCCESS(Status)) goto fail4; - Pdo = __AdapterGetPdo(Adapter, TargetId); - if (Pdo == NULL) + Target = __AdapterGetTarget(Adapter, TargetId); + if (Target == NULL) goto fail5; - PdoSetDeviceObject(Pdo, DeviceObject); + TargetSetDeviceObject(Target, DeviceObject); ExFreePool(String); - return Pdo; + return Target; fail5: fail4: @@ -1966,21 +1966,21 @@ AdapterForwardPnp( ) { PIO_STACK_LOCATION Stack; - PXENVBD_PDO Pdo; + PXENVBD_TARGET Target; ASSERT3P(DeviceObject, !=, Adapter->DeviceObject); - Pdo = AdapterGetPdoFromDeviceObject(Adapter, DeviceObject); - if (Pdo != NULL) { - return PdoDispatchPnp(Pdo, DeviceObject, Irp); + Target = AdapterGetTargetFromDeviceObject(Adapter, DeviceObject); + if (Target != NULL) { + return TargetDispatchPnp(Target, DeviceObject, Irp); } Stack = IoGetCurrentIrpStackLocation(Irp); if (Stack->MinorFunction == IRP_MN_QUERY_ID && Stack->Parameters.QueryId.IdType == BusQueryDeviceID) { - Pdo = AdapterMapDeviceObjectToPdo(Adapter, DeviceObject); - if (Pdo != NULL) { - return PdoDispatchPnp(Pdo, DeviceObject, Irp); + Target = AdapterMapDeviceObjectToTarget(Adapter, DeviceObject); + if (Target != NULL) { + return TargetDispatchPnp(Target, DeviceObject, Irp); } } diff --git a/src/xenvbd/adapter.h b/src/xenvbd/adapter.h index 0087837..1a6808f 100644 --- a/src/xenvbd/adapter.h +++ b/src/xenvbd/adapter.h @@ -37,7 +37,7 @@ typedef struct _XENVBD_ADAPTER XENVBD_ADAPTER, *PXENVBD_ADAPTER; #include -#include "pdo.h" +#include "target.h" #include #include #include @@ -45,17 +45,17 @@ typedef struct _XENVBD_ADAPTER XENVBD_ADAPTER, *PXENVBD_ADAPTER; #include #include -// Link PDOs +// Link TARGETs extern BOOLEAN -AdapterLinkPdo( +AdapterLinkTarget( __in PXENVBD_ADAPTER Adapter, - __in PXENVBD_PDO Pdo + __in PXENVBD_TARGET Target ); extern BOOLEAN -AdapterUnlinkPdo( +AdapterUnlinkTarget( __in PXENVBD_ADAPTER Adapter, - __in PXENVBD_PDO Pdo + __in PXENVBD_TARGET Target ); // Query Methods __checkReturn diff --git a/src/xenvbd/blockring.c b/src/xenvbd/blockring.c index b60f39e..8d914d3 100644 --- a/src/xenvbd/blockring.c +++ b/src/xenvbd/blockring.c @@ -31,7 +31,7 @@ #include "blockring.h" #include "frontend.h" -#include "pdo.h" +#include "target.h" #include "adapter.h" #include "util.h" #include "debug.h" @@ -277,7 +277,7 @@ BlockRingConnect( NTSTATUS status; PCHAR Value; ULONG Index, RingPages; - PXENVBD_ADAPTER Adapter = PdoGetAdapter(FrontendGetPdo(BlockRing->Frontend)); + PXENVBD_ADAPTER Adapter = TargetGetAdapter(FrontendGetTarget(BlockRing->Frontend)); PXENVBD_GRANTER Granter = FrontendGetGranter(BlockRing->Frontend); ASSERT(BlockRing->Connected == FALSE); @@ -509,7 +509,7 @@ BlockRingPoll( IN PXENVBD_BLOCKRING BlockRing ) { - PXENVBD_PDO Pdo = FrontendGetPdo(BlockRing->Frontend); + PXENVBD_TARGET Target = FrontendGetTarget(BlockRing->Frontend); ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL); KeAcquireSpinLockAtDpcLevel(&BlockRing->Lock); @@ -542,7 +542,7 @@ BlockRingPoll( if (__BlockRingPutTag(BlockRing, Response->id, &Tag)) { ++BlockRing->Received; - PdoCompleteResponse(Pdo, Tag, Response->status); + TargetCompleteResponse(Target, Tag, Response->status); } RtlZeroMemory(Response, sizeof(union blkif_sring_entry)); diff --git a/src/xenvbd/driver.c b/src/xenvbd/driver.c index 39194e2..d4efaf1 100644 --- a/src/xenvbd/driver.c +++ b/src/xenvbd/driver.c @@ -31,7 +31,7 @@ #include "driver.h" #include "adapter.h" -#include "pdo.h" +#include "target.h" #include "registry.h" #include "srbext.h" #include "buffer.h" @@ -118,7 +118,7 @@ DriverDispatchPower( VOID DriverLinkAdapter( - __in PXENVBD_ADAPTER Adapter + IN PXENVBD_ADAPTER Adapter ) { KIRQL Irql; @@ -130,7 +130,7 @@ DriverLinkAdapter( VOID DriverUnlinkAdapter( - __in PXENVBD_ADAPTER Adapter + IN PXENVBD_ADAPTER Adapter ) { KIRQL Irql; diff --git a/src/xenvbd/frontend.c b/src/xenvbd/frontend.c index daf5338..1d7d51e 100644 --- a/src/xenvbd/frontend.c +++ b/src/xenvbd/frontend.c @@ -50,7 +50,7 @@ struct _XENVBD_FRONTEND { // Frontend - PXENVBD_PDO Pdo; + PXENVBD_TARGET Target; ULONG TargetId; ULONG DeviceId; PCHAR FrontendPath; @@ -188,12 +188,12 @@ FrontendGetInquiry( { return Frontend->Inquiry; } -PXENVBD_PDO -FrontendGetPdo( +PXENVBD_TARGET +FrontendGetTarget( __in PXENVBD_FRONTEND Frontend ) { - return Frontend->Pdo; + return Frontend->Target; } PXENVBD_BLOCKRING FrontendGetBlockRing( @@ -328,7 +328,7 @@ FrontendNotifyResponses( ) { BlockRingPoll(Frontend->BlockRing); - PdoSubmitRequests(Frontend->Pdo); + TargetSubmitRequests(Frontend->Target); } //============================================================================= @@ -609,7 +609,7 @@ abort: Trace("Target[%d] : BackendState(%s) FrontendState(%s)\n", Frontend->TargetId, XenbusStateName(BackendState), XenbusStateName(FrontendState)); - PdoIssueDeviceEject(Frontend->Pdo, XenbusStateName(BackendState)); + TargetIssueDeviceEject(Frontend->Target, XenbusStateName(BackendState)); } } @@ -1407,7 +1407,7 @@ FrontendSuspendLateCallback( Verbose("Target[%d] : ===> from %s\n", Frontend->TargetId, __XenvbdStateName(Frontend->State)); State = Frontend->State; - PdoPreResume(Frontend->Pdo); + TargetPreResume(Frontend->Target); // dont acquire state lock - called at DISPATCH on 1 vCPU with interrupts enabled Status = __FrontendSetState(Frontend, XENVBD_CLOSED); @@ -1423,7 +1423,7 @@ FrontendSuspendLateCallback( ASSERT(FALSE); } - PdoPostResume(Frontend->Pdo); + TargetPostResume(Frontend->Target); NotifierTrigger(Frontend->Notifier); Verbose("Target[%d] : <=== restored %s\n", Frontend->TargetId, __XenvbdStateName(Frontend->State)); @@ -1442,13 +1442,13 @@ FrontendD3ToD0( KeAcquireSpinLock(&Frontend->StateLock, &Irql); // acquire interfaces - Frontend->Store = AdapterAcquireStore(PdoGetAdapter(Frontend->Pdo)); + Frontend->Store = AdapterAcquireStore(TargetGetAdapter(Frontend->Target)); Status = STATUS_UNSUCCESSFUL; if (Frontend->Store == NULL) goto fail1; - Frontend->Suspend = AdapterAcquireSuspend(PdoGetAdapter(Frontend->Pdo)); + Frontend->Suspend = AdapterAcquireSuspend(TargetGetAdapter(Frontend->Target)); Status = STATUS_UNSUCCESSFUL; if (Frontend->Suspend == NULL) @@ -1575,7 +1575,7 @@ FrontendBackend( __checkReturn NTSTATUS FrontendCreate( - __in PXENVBD_PDO Pdo, + __in PXENVBD_TARGET Target, __in PCHAR DeviceId, __in ULONG TargetId, __out PXENVBD_FRONTEND* _Frontend @@ -1593,7 +1593,7 @@ FrontendCreate( goto fail1; // populate members - Frontend->Pdo = Pdo; + Frontend->Target = Target; Frontend->TargetId = TargetId; Frontend->DeviceId = strtoul(DeviceId, NULL, 10); Frontend->State = XENVBD_INITIALIZED; @@ -1601,7 +1601,7 @@ FrontendCreate( Frontend->BackendId = DOMID_INVALID; Status = STATUS_INSUFFICIENT_RESOURCES; - Frontend->FrontendPath = DriverFormat("device/%s/%s", AdapterEnum(PdoGetAdapter(Pdo)), DeviceId); + Frontend->FrontendPath = DriverFormat("device/%s/%s", AdapterEnum(TargetGetAdapter(Target)), DeviceId); if (Frontend->FrontendPath == NULL) goto fail2; diff --git a/src/xenvbd/frontend.h b/src/xenvbd/frontend.h index 7e40bce..a192cff 100644 --- a/src/xenvbd/frontend.h +++ b/src/xenvbd/frontend.h @@ -32,7 +32,7 @@ #ifndef _XENVBD_FRONTEND_H #define _XENVBD_FRONTEND_H -#include "pdo.h" +#include "target.h" #include typedef enum _XENVBD_STATE { @@ -100,8 +100,8 @@ extern PVOID FrontendGetInquiry( __in PXENVBD_FRONTEND Frontend ); -extern PXENVBD_PDO -FrontendGetPdo( +extern PXENVBD_TARGET +FrontendGetTarget( __in PXENVBD_FRONTEND Frontend ); #include "blockring.h" @@ -174,7 +174,7 @@ FrontendSetState( __checkReturn extern NTSTATUS FrontendCreate( - __in PXENVBD_PDO Pdo, + __in PXENVBD_TARGET Target, __in PCHAR DeviceId, __in ULONG TargetId, __out PXENVBD_FRONTEND* _Frontend diff --git a/src/xenvbd/granter.c b/src/xenvbd/granter.c index f670304..bd0fa5b 100644 --- a/src/xenvbd/granter.c +++ b/src/xenvbd/granter.c @@ -30,7 +30,7 @@ */ #include "frontend.h" -#include "pdo.h" +#include "target.h" #include "adapter.h" #include "util.h" #include "debug.h" @@ -139,7 +139,7 @@ GranterConnect( IN USHORT BackendDomain ) { - PXENVBD_ADAPTER Adapter = PdoGetAdapter(FrontendGetPdo(Granter->Frontend)); + PXENVBD_ADAPTER Adapter = TargetGetAdapter(FrontendGetTarget(Granter->Frontend)); CHAR Name[MAXNAMELEN]; NTSTATUS status; diff --git a/src/xenvbd/notifier.c b/src/xenvbd/notifier.c index 3bff2f6..4835a46 100644 --- a/src/xenvbd/notifier.c +++ b/src/xenvbd/notifier.c @@ -31,7 +31,7 @@ #include "notifier.h" #include "frontend.h" -#include "pdo.h" +#include "target.h" #include "adapter.h" #include "util.h" #include "debug.h" @@ -162,7 +162,7 @@ NotifierConnect( IN USHORT BackendDomain ) { - PXENVBD_ADAPTER Adapter = PdoGetAdapter(FrontendGetPdo(Notifier->Frontend)); + PXENVBD_ADAPTER Adapter = TargetGetAdapter(FrontendGetTarget(Notifier->Frontend)); NTSTATUS status; ASSERT(Notifier->Connected == FALSE); diff --git a/src/xenvbd/pdo.c b/src/xenvbd/pdo.c deleted file mode 100644 index 522337f..0000000 --- a/src/xenvbd/pdo.c +++ /dev/null @@ -1,2732 +0,0 @@ -/* Copyright (c) Citrix Systems Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "pdo.h" -#include "driver.h" -#include "adapter.h" -#include "frontend.h" -#include "queue.h" -#include "srbext.h" -#include "buffer.h" -#include "pdoinquiry.h" -#include "debug.h" -#include "assert.h" -#include "util.h" -#include -#include -#include -#include -#include -#include -#include - -typedef struct _XENVBD_SG_LIST { - // SGList from SRB - PSTOR_SCATTER_GATHER_LIST SGList; - // "current" values - STOR_PHYSICAL_ADDRESS PhysAddr; - ULONG PhysLen; - // iteration - ULONG Index; - ULONG Offset; - ULONG Length; -} XENVBD_SG_LIST, *PXENVBD_SG_LIST; - -#define PDO_SIGNATURE 'odpX' - -typedef struct _XENVBD_LOOKASIDE { - KEVENT Empty; - LONG Used; - LONG Max; - ULONG Failed; - ULONG Size; - NPAGED_LOOKASIDE_LIST List; -} XENVBD_LOOKASIDE, *PXENVBD_LOOKASIDE; - -struct _XENVBD_PDO { - ULONG Signature; - PXENVBD_ADAPTER Adapter; - PDEVICE_OBJECT DeviceObject; - KEVENT RemoveEvent; - LONG ReferenceCount; - DEVICE_PNP_STATE DevicePnpState; - DEVICE_PNP_STATE PrevPnpState; - DEVICE_POWER_STATE DevicePowerState; - KSPIN_LOCK Lock; - - // Frontend (Ring, includes XenBus interfaces) - PXENVBD_FRONTEND Frontend; - XENVBD_DEVICE_TYPE DeviceType; - - // State - LONG Paused; - - // Eject - BOOLEAN WrittenEjected; - BOOLEAN EjectRequested; - BOOLEAN EjectPending; - BOOLEAN Missing; - const CHAR* Reason; - - // SRBs - XENVBD_LOOKASIDE RequestList; - XENVBD_LOOKASIDE SegmentList; - XENVBD_LOOKASIDE IndirectList; - XENVBD_QUEUE FreshSrbs; - XENVBD_QUEUE PreparedReqs; - XENVBD_QUEUE SubmittedReqs; - XENVBD_QUEUE ShutdownSrbs; - ULONG NextTag; - - // Stats - SRB Counts by BLKIF_OP_ - ULONG BlkOpRead; - ULONG BlkOpWrite; - ULONG BlkOpIndirectRead; - ULONG BlkOpIndirectWrite; - ULONG BlkOpBarrier; - ULONG BlkOpDiscard; - ULONG BlkOpFlush; - // Stats - Failures - ULONG FailedMaps; - ULONG FailedBounces; - ULONG FailedGrants; - // Stats - Segments - ULONG64 SegsGranted; - ULONG64 SegsBounced; -}; - -//============================================================================= -#define PDO_POOL_TAG 'odPX' -#define REQUEST_POOL_TAG 'qeRX' -#define SEGMENT_POOL_TAG 'geSX' -#define INDIRECT_POOL_TAG 'dnIX' - -__checkReturn -__drv_allocatesMem(mem) -__bcount(Size) -static FORCEINLINE PVOID -#pragma warning(suppress: 28195) -__PdoAlloc( - __in ULONG Size - ) -{ - return __AllocatePoolWithTag(NonPagedPool, Size, PDO_POOL_TAG); -} - -static FORCEINLINE VOID -#pragma warning(suppress: 28197) -__PdoFree( - __in __drv_freesMem(mem) PVOID Buffer - ) -{ - if (Buffer) - __FreePoolWithTag(Buffer, PDO_POOL_TAG); -} - -//============================================================================= -// Lookasides -static FORCEINLINE VOID -__LookasideInit( - IN OUT PXENVBD_LOOKASIDE Lookaside, - IN ULONG Size, - IN ULONG Tag - ) -{ - RtlZeroMemory(Lookaside, sizeof(XENVBD_LOOKASIDE)); - Lookaside->Size = Size; - KeInitializeEvent(&Lookaside->Empty, SynchronizationEvent, TRUE); - ExInitializeNPagedLookasideList(&Lookaside->List, NULL, NULL, 0, - Size, Tag, 0); -} - -static FORCEINLINE VOID -__LookasideTerm( - IN PXENVBD_LOOKASIDE Lookaside - ) -{ - ASSERT3U(Lookaside->Used, ==, 0); - ExDeleteNPagedLookasideList(&Lookaside->List); - RtlZeroMemory(Lookaside, sizeof(XENVBD_LOOKASIDE)); -} - -static FORCEINLINE PVOID -__LookasideAlloc( - IN PXENVBD_LOOKASIDE Lookaside - ) -{ - LONG Result; - PVOID Buffer; - - Buffer = ExAllocateFromNPagedLookasideList(&Lookaside->List); - if (Buffer == NULL) { - ++Lookaside->Failed; - return NULL; - } - - RtlZeroMemory(Buffer, Lookaside->Size); - Result = InterlockedIncrement(&Lookaside->Used); - ASSERT3S(Result, >, 0); - if (Result > Lookaside->Max) - Lookaside->Max = Result; - KeClearEvent(&Lookaside->Empty); - - return Buffer; -} - -static FORCEINLINE VOID -__LookasideFree( - IN PXENVBD_LOOKASIDE Lookaside, - IN PVOID Buffer - ) -{ - LONG Result; - - ExFreeToNPagedLookasideList(&Lookaside->List, Buffer); - Result = InterlockedDecrement(&Lookaside->Used); - ASSERT3S(Result, >=, 0); - - if (Result == 0) { - KeSetEvent(&Lookaside->Empty, IO_NO_INCREMENT, FALSE); - } -} - -static FORCEINLINE VOID -__LookasideDebug( - IN PXENVBD_LOOKASIDE Lookaside, - IN PXENBUS_DEBUG_INTERFACE Debug, - IN PCHAR Name - ) -{ - XENBUS_DEBUG(Printf, Debug, - "LOOKASIDE: %s: %u / %u (%u failed)\n", - Name, Lookaside->Used, - Lookaside->Max, Lookaside->Failed); - - Lookaside->Max = Lookaside->Used; - Lookaside->Failed = 0; -} - -//============================================================================= -// Debug -static FORCEINLINE PCHAR -__PnpStateName( - __in DEVICE_PNP_STATE State - ) -{ - switch (State) { - case Invalid: return "Invalid"; - case Present: return "Present"; - case Enumerated: return "Enumerated"; - case Added: return "Added"; - case Started: return "Started"; - case StopPending: return "StopPending"; - case Stopped: return "Stopped"; - case RemovePending: return "RemovePending"; - case SurpriseRemovePending: return "SurpriseRemovePending"; - case Deleted: return "Deleted"; - default: return "UNKNOWN"; - } -} - -DECLSPEC_NOINLINE VOID -PdoDebugCallback( - __in PXENVBD_PDO Pdo, - __in PXENBUS_DEBUG_INTERFACE DebugInterface - ) -{ - if (Pdo == NULL || DebugInterface == NULL) - return; - if (Pdo->Signature != PDO_SIGNATURE) - return; - - XENBUS_DEBUG(Printf, DebugInterface, - "PDO: Adapter 0x%p DeviceObject 0x%p\n", - Pdo->Adapter, - Pdo->DeviceObject); - XENBUS_DEBUG(Printf, DebugInterface, - "PDO: ReferenceCount %d\n", - Pdo->ReferenceCount); - XENBUS_DEBUG(Printf, DebugInterface, - "PDO: DevicePnpState %s (%s)\n", - __PnpStateName(Pdo->DevicePnpState), - __PnpStateName(Pdo->PrevPnpState)); - XENBUS_DEBUG(Printf, DebugInterface, - "PDO: DevicePowerState %s\n", - PowerDeviceStateName(Pdo->DevicePowerState)); - XENBUS_DEBUG(Printf, DebugInterface, - "PDO: %s\n", - Pdo->Missing ? Pdo->Reason : "Not Missing"); - - XENBUS_DEBUG(Printf, DebugInterface, - "PDO: BLKIF_OPs: READ=%u WRITE=%u\n", - Pdo->BlkOpRead, Pdo->BlkOpWrite); - XENBUS_DEBUG(Printf, DebugInterface, - "PDO: BLKIF_OPs: INDIRECT_READ=%u INDIRECT_WRITE=%u\n", - Pdo->BlkOpIndirectRead, Pdo->BlkOpIndirectWrite); - XENBUS_DEBUG(Printf, DebugInterface, - "PDO: BLKIF_OPs: BARRIER=%u DISCARD=%u FLUSH=%u\n", - Pdo->BlkOpBarrier, Pdo->BlkOpDiscard, Pdo->BlkOpFlush); - XENBUS_DEBUG(Printf, DebugInterface, - "PDO: Failed: Maps=%u Bounces=%u Grants=%u\n", - Pdo->FailedMaps, Pdo->FailedBounces, Pdo->FailedGrants); - XENBUS_DEBUG(Printf, DebugInterface, - "PDO: Segments Granted=%llu Bounced=%llu\n", - Pdo->SegsGranted, Pdo->SegsBounced); - - __LookasideDebug(&Pdo->RequestList, DebugInterface, "REQUESTs"); - __LookasideDebug(&Pdo->SegmentList, DebugInterface, "SEGMENTs"); - __LookasideDebug(&Pdo->IndirectList, DebugInterface, "INDIRECTs"); - - QueueDebugCallback(&Pdo->FreshSrbs, "Fresh ", DebugInterface); - QueueDebugCallback(&Pdo->PreparedReqs, "Prepared ", DebugInterface); - QueueDebugCallback(&Pdo->SubmittedReqs, "Submitted", DebugInterface); - QueueDebugCallback(&Pdo->ShutdownSrbs, "Shutdown ", DebugInterface); - - FrontendDebugCallback(Pdo->Frontend, DebugInterface); - - Pdo->BlkOpRead = Pdo->BlkOpWrite = 0; - Pdo->BlkOpIndirectRead = Pdo->BlkOpIndirectWrite = 0; - Pdo->BlkOpBarrier = Pdo->BlkOpDiscard = Pdo->BlkOpFlush = 0; - Pdo->FailedMaps = Pdo->FailedBounces = Pdo->FailedGrants = 0; - Pdo->SegsGranted = Pdo->SegsBounced = 0; -} - -//============================================================================= -// Power States -__checkReturn -static FORCEINLINE BOOLEAN -PdoSetDevicePowerState( - __in PXENVBD_PDO Pdo, - __in DEVICE_POWER_STATE State - ) -{ - KIRQL Irql; - BOOLEAN Changed = FALSE; - - KeAcquireSpinLock(&Pdo->Lock, &Irql); - if (Pdo->DevicePowerState != State) { - Verbose("Target[%d] : POWER %s to %s\n", PdoGetTargetId(Pdo), PowerDeviceStateName(Pdo->DevicePowerState), PowerDeviceStateName(State)); - Pdo->DevicePowerState = State; - Changed = TRUE; - } - KeReleaseSpinLock(&Pdo->Lock, Irql); - - return Changed; -} - -//============================================================================= -// PnP States -FORCEINLINE VOID -PdoSetMissing( - __in PXENVBD_PDO Pdo, - __in __nullterminated const CHAR* Reason - ) -{ - KIRQL Irql; - - ASSERT3P(Reason, !=, NULL); - - KeAcquireSpinLock(&Pdo->Lock, &Irql); - if (Pdo->Missing) { - Verbose("Target[%d] : Already MISSING (%s) when trying to set (%s)\n", PdoGetTargetId(Pdo), Pdo->Reason, Reason); - } else { - Verbose("Target[%d] : MISSING %s\n", PdoGetTargetId(Pdo), Reason); - Pdo->Missing = TRUE; - Pdo->Reason = Reason; - } - KeReleaseSpinLock(&Pdo->Lock, Irql); -} - -__checkReturn -FORCEINLINE BOOLEAN -PdoIsMissing( - __in PXENVBD_PDO Pdo - ) -{ - KIRQL Irql; - BOOLEAN Missing; - - KeAcquireSpinLock(&Pdo->Lock, &Irql); - Missing = Pdo->Missing; - KeReleaseSpinLock(&Pdo->Lock, Irql); - - return Missing; -} - -FORCEINLINE const CHAR* -PdoMissingReason( - __in PXENVBD_PDO Pdo - ) -{ - KIRQL Irql; - const CHAR* Reason; - - KeAcquireSpinLock(&Pdo->Lock, &Irql); - Reason = Pdo->Reason; - KeReleaseSpinLock(&Pdo->Lock, Irql); - - return Reason; -} - -FORCEINLINE VOID -PdoSetDevicePnpState( - __in PXENVBD_PDO Pdo, - __in DEVICE_PNP_STATE State - ) -{ - Verbose("Target[%d] : PNP %s to %s\n", - PdoGetTargetId(Pdo), - __PnpStateName(Pdo->DevicePnpState), - __PnpStateName(State)); - - if (Pdo->DevicePnpState == Deleted) - return; - - Pdo->PrevPnpState = Pdo->DevicePnpState; - Pdo->DevicePnpState = State; -} - -__checkReturn -FORCEINLINE DEVICE_PNP_STATE -PdoGetDevicePnpState( - __in PXENVBD_PDO Pdo - ) -{ - return Pdo->DevicePnpState; -} - -static FORCEINLINE VOID -__PdoRestoreDevicePnpState( - __in PXENVBD_PDO Pdo, - __in DEVICE_PNP_STATE State - ) -{ - if (Pdo->DevicePnpState == State) { - Verbose("Target[%d] : PNP %s to %s\n", PdoGetTargetId(Pdo), __PnpStateName(Pdo->DevicePnpState), __PnpStateName(Pdo->PrevPnpState)); - Pdo->DevicePnpState = Pdo->PrevPnpState; - } -} - -//============================================================================= -// Reference Counting -FORCEINLINE LONG -__PdoReference( - __in PXENVBD_PDO Pdo, - __in PCHAR Caller - ) -{ - LONG Result; - - ASSERT3P(Pdo, !=, NULL); - Result = InterlockedIncrement(&Pdo->ReferenceCount); - ASSERTREFCOUNT(Result, >, 0, Caller); - - if (Result == 1) { - Result = InterlockedDecrement(&Pdo->ReferenceCount); - Error("Target[%d] : %s: Attempting to take reference of removed PDO from %d\n", PdoGetTargetId(Pdo), Caller, Result); - return 0; - } else { - ASSERTREFCOUNT(Result, >, 1, Caller); - return Result; - } -} - -FORCEINLINE LONG -__PdoDereference( - __in PXENVBD_PDO Pdo, - __in PCHAR Caller - ) -{ - LONG Result; - - ASSERT3P(Pdo, !=, NULL); - Result = InterlockedDecrement(&Pdo->ReferenceCount); - ASSERTREFCOUNT(Result, >=, 0, Caller); - - if (Result == 0) { - Verbose("Final ReferenceCount dropped, Target[%d] able to be removed\n", PdoGetTargetId(Pdo)); - KeSetEvent(&Pdo->RemoveEvent, IO_NO_INCREMENT, FALSE); - } - return Result; -} - -//============================================================================= -// Query Methods -FORCEINLINE ULONG -PdoGetTargetId( - __in PXENVBD_PDO Pdo - ) -{ - ASSERT3P(Pdo, !=, NULL); - return FrontendGetTargetId(Pdo->Frontend); -} - -__checkReturn -FORCEINLINE PDEVICE_OBJECT -PdoGetDeviceObject( - __in PXENVBD_PDO Pdo - ) -{ - ASSERT3P(Pdo, !=, NULL); - return Pdo->DeviceObject; -} - -FORCEINLINE VOID -PdoSetDeviceObject( - __in PXENVBD_PDO Pdo, - __in PDEVICE_OBJECT DeviceObject - ) -{ - Verbose("Target[%d] : Setting DeviceObject = 0x%p\n", PdoGetTargetId(Pdo), DeviceObject); - - ASSERT3P(Pdo->DeviceObject, ==, NULL); - Pdo->DeviceObject = DeviceObject; -} - -__checkReturn -FORCEINLINE BOOLEAN -PdoIsPaused( - __in PXENVBD_PDO Pdo - ) -{ - BOOLEAN Paused; - KIRQL Irql; - - KeAcquireSpinLock(&Pdo->Lock, &Irql); - Paused = (Pdo->Paused > 0); - KeReleaseSpinLock(&Pdo->Lock, Irql); - - return Paused; -} - -__checkReturn -FORCEINLINE ULONG -PdoOutstandingReqs( - __in PXENVBD_PDO Pdo - ) -{ - return QueueCount(&Pdo->SubmittedReqs); -} - -__checkReturn -FORCEINLINE PXENVBD_ADAPTER -PdoGetAdapter( - __in PXENVBD_PDO Pdo - ) -{ - return Pdo->Adapter; -} - -FORCEINLINE ULONG -PdoSectorSize( - __in PXENVBD_PDO Pdo - ) -{ - return FrontendGetDiskInfo(Pdo->Frontend)->SectorSize; -} - -//============================================================================= -static PXENVBD_INDIRECT -PdoGetIndirect( - IN PXENVBD_PDO Pdo - ) -{ - PXENVBD_INDIRECT Indirect; - NTSTATUS status; - PXENVBD_GRANTER Granter = FrontendGetGranter(Pdo->Frontend); - - Indirect = __LookasideAlloc(&Pdo->IndirectList); - if (Indirect == NULL) - goto fail1; - - RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); - - Indirect->Mdl = __AllocatePage(); - if (Indirect->Mdl == NULL) - goto fail2; - - Indirect->Page = MmGetSystemAddressForMdlSafe(Indirect->Mdl, - NormalPagePriority); - - status = GranterGet(Granter, - MmGetMdlPfnArray(Indirect->Mdl)[0], - TRUE, - &Indirect->Grant); - if (!NT_SUCCESS(status)) - goto fail3; - - return Indirect; - -fail3: - __FreePage(Indirect->Mdl); -fail2: - __LookasideFree(&Pdo->IndirectList, Indirect); -fail1: - return NULL; -} - -static VOID -PdoPutIndirect( - IN PXENVBD_PDO Pdo, - IN PXENVBD_INDIRECT Indirect - ) -{ - PXENVBD_GRANTER Granter = FrontendGetGranter(Pdo->Frontend); - - if (Indirect->Grant) - GranterPut(Granter, Indirect->Grant); - if (Indirect->Page) - __FreePage(Indirect->Mdl); - - RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); - __LookasideFree(&Pdo->IndirectList, Indirect); -} - -static PXENVBD_SEGMENT -PdoGetSegment( - IN PXENVBD_PDO Pdo - ) -{ - PXENVBD_SEGMENT Segment; - - Segment = __LookasideAlloc(&Pdo->SegmentList); - if (Segment == NULL) - goto fail1; - - RtlZeroMemory(Segment, sizeof(XENVBD_SEGMENT)); - return Segment; - -fail1: - return NULL; -} - -static VOID -PdoPutSegment( - IN PXENVBD_PDO Pdo, - IN PXENVBD_SEGMENT Segment - ) -{ - PXENVBD_GRANTER Granter = FrontendGetGranter(Pdo->Frontend); - - if (Segment->Grant) - GranterPut(Granter, Segment->Grant); - - if (Segment->BufferId) - BufferPut(Segment->BufferId); - - if (Segment->Buffer) - MmUnmapLockedPages(Segment->Buffer, &Segment->Mdl); - - RtlZeroMemory(Segment, sizeof(XENVBD_SEGMENT)); - __LookasideFree(&Pdo->SegmentList, Segment); -} - -static PXENVBD_REQUEST -PdoGetRequest( - IN PXENVBD_PDO Pdo - ) -{ - PXENVBD_REQUEST Request; - - Request = __LookasideAlloc(&Pdo->RequestList); - if (Request == NULL) - goto fail1; - - RtlZeroMemory(Request, sizeof(XENVBD_REQUEST)); - Request->Id = (ULONG)InterlockedIncrement((PLONG)&Pdo->NextTag); - InitializeListHead(&Request->Segments); - InitializeListHead(&Request->Indirects); - - return Request; - -fail1: - return NULL; -} - -static VOID -PdoPutRequest( - IN PXENVBD_PDO Pdo, - IN PXENVBD_REQUEST Request - ) -{ - PLIST_ENTRY Entry; - - for (;;) { - PXENVBD_SEGMENT Segment; - - Entry = RemoveHeadList(&Request->Segments); - if (Entry == &Request->Segments) - break; - Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); - PdoPutSegment(Pdo, Segment); - } - - for (;;) { - PXENVBD_INDIRECT Indirect; - - Entry = RemoveHeadList(&Request->Indirects); - if (Entry == &Request->Indirects) - break; - Indirect = CONTAINING_RECORD(Entry, XENVBD_INDIRECT, Entry); - PdoPutIndirect(Pdo, Indirect); - } - - RtlZeroMemory(Request, sizeof(XENVBD_REQUEST)); - __LookasideFree(&Pdo->RequestList, Request); -} - -static FORCEINLINE PXENVBD_REQUEST -PdoRequestFromTag( - IN PXENVBD_PDO Pdo, - IN ULONG Tag - ) -{ - KIRQL Irql; - PLIST_ENTRY Entry; - PXENVBD_QUEUE Queue = &Pdo->SubmittedReqs; - - KeAcquireSpinLock(&Queue->Lock, &Irql); - - for (Entry = Queue->List.Flink; Entry != &Queue->List; Entry = Entry->Flink) { - PXENVBD_REQUEST Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - if (Request->Id == Tag) { - RemoveEntryList(&Request->Entry); - --Queue->Current; - KeReleaseSpinLock(&Queue->Lock, Irql); - return Request; - } - } - - KeReleaseSpinLock(&Queue->Lock, Irql); - Warning("Target[%d] : Tag %x not found in submitted list (%u items)\n", - PdoGetTargetId(Pdo), Tag, QueueCount(Queue)); - return NULL; -} - -static FORCEINLINE VOID -__PdoIncBlkifOpCount( - __in PXENVBD_PDO Pdo, - __in PXENVBD_REQUEST Request - ) -{ - switch (Request->Operation) { - case BLKIF_OP_READ: - if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) - ++Pdo->BlkOpIndirectRead; - else - ++Pdo->BlkOpRead; - break; - case BLKIF_OP_WRITE: - if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) - ++Pdo->BlkOpIndirectWrite; - else - ++Pdo->BlkOpWrite; - break; - case BLKIF_OP_WRITE_BARRIER: - ++Pdo->BlkOpBarrier; - break; - case BLKIF_OP_DISCARD: - ++Pdo->BlkOpDiscard; - break; - case BLKIF_OP_FLUSH_DISKCACHE: - ++Pdo->BlkOpFlush; - break; - default: - ASSERT(FALSE); - break; - } -} - -static FORCEINLINE ULONG -__SectorsPerPage( - __in ULONG SectorSize - ) -{ - ASSERT3U(SectorSize, !=, 0); - return PAGE_SIZE / SectorSize; -} - -static FORCEINLINE VOID -__Operation( - __in UCHAR CdbOp, - __out PUCHAR RingOp, - __out PBOOLEAN ReadOnly - ) -{ - switch (CdbOp) { - case SCSIOP_READ: - *RingOp = BLKIF_OP_READ; - *ReadOnly = FALSE; - break; - case SCSIOP_WRITE: - *RingOp = BLKIF_OP_WRITE; - *ReadOnly = TRUE; - break; - default: - ASSERT(FALSE); - } -} - -static FORCEINLINE ULONG -__Offset( - __in STOR_PHYSICAL_ADDRESS PhysAddr - ) -{ - return (ULONG)(PhysAddr.QuadPart & (PAGE_SIZE - 1)); -} - -static FORCEINLINE PFN_NUMBER -__Phys2Pfn( - __in STOR_PHYSICAL_ADDRESS PhysAddr - ) -{ - return (PFN_NUMBER)(PhysAddr.QuadPart >> PAGE_SHIFT); -} - -static FORCEINLINE PFN_NUMBER -__Virt2Pfn( - __in PVOID VirtAddr - ) -{ - return (PFN_NUMBER)(MmGetPhysicalAddress(VirtAddr).QuadPart >> PAGE_SHIFT); -} - -static FORCEINLINE MM_PAGE_PRIORITY -__PdoPriority( - __in PXENVBD_PDO Pdo - ) -{ - PXENVBD_CAPS Caps = FrontendGetCaps(Pdo->Frontend); - if (!(Caps->Paging || - Caps->Hibernation || - Caps->DumpFile)) - return NormalPagePriority; - - return HighPagePriority; -} - -#define __min(_x, _y) ((_x) < (_y)) ? (_x) : (_y) - -static FORCEINLINE VOID -SGListGet( - IN OUT PXENVBD_SG_LIST SGList - ) -{ - PSTOR_SCATTER_GATHER_ELEMENT SGElement; - - ASSERT3U(SGList->Index, <, SGList->SGList->NumberOfElements); - - SGElement = &SGList->SGList->List[SGList->Index]; - - SGList->PhysAddr.QuadPart = SGElement->PhysicalAddress.QuadPart + SGList->Offset; - SGList->PhysLen = __min(PAGE_SIZE - __Offset(SGList->PhysAddr) - SGList->Length, SGElement->Length - SGList->Offset); - - ASSERT3U(SGList->PhysLen, <=, PAGE_SIZE); - ASSERT3U(SGList->Offset, <, SGElement->Length); - - SGList->Length = SGList->PhysLen; // gets reset every time for Granted, every 1or2 times for Bounced - SGList->Offset = SGList->Offset + SGList->PhysLen; - if (SGList->Offset >= SGElement->Length) { - SGList->Index = SGList->Index + 1; - SGList->Offset = 0; - } -} - -static FORCEINLINE BOOLEAN -SGListNext( - IN OUT PXENVBD_SG_LIST SGList, - IN ULONG AlignmentMask - ) -{ - SGList->Length = 0; - SGListGet(SGList); // get next PhysAddr and PhysLen - return !((SGList->PhysAddr.QuadPart & AlignmentMask) || (SGList->PhysLen & AlignmentMask)); -} - -static FORCEINLINE BOOLEAN -MapSegmentBuffer( - IN PXENVBD_PDO Pdo, - IN PXENVBD_SEGMENT Segment, - IN PXENVBD_SG_LIST SGList, - IN ULONG SectorSize, - IN ULONG SectorsNow - ) -{ - PMDL Mdl; - - // map PhysAddr to 1 or 2 pages and lock for VirtAddr -#pragma warning(push) -#pragma warning(disable:28145) - Mdl = &Segment->Mdl; - Mdl->Next = NULL; - Mdl->Size = (SHORT)(sizeof(MDL) + sizeof(PFN_NUMBER)); - Mdl->MdlFlags = MDL_PAGES_LOCKED; - Mdl->Process = NULL; - Mdl->MappedSystemVa = NULL; - Mdl->StartVa = NULL; - Mdl->ByteCount = SGList->PhysLen; - Mdl->ByteOffset = __Offset(SGList->PhysAddr); - Segment->Pfn[0] = __Phys2Pfn(SGList->PhysAddr); - - if (SGList->PhysLen < SectorsNow * SectorSize) { - SGListGet(SGList); - Mdl->Size += sizeof(PFN_NUMBER); - Mdl->ByteCount = Mdl->ByteCount + SGList->PhysLen; - Segment->Pfn[1] = __Phys2Pfn(SGList->PhysAddr); - } -#pragma warning(pop) - - ASSERT((Mdl->ByteCount & (SectorSize - 1)) == 0); - ASSERT3U(Mdl->ByteCount, <=, PAGE_SIZE); - ASSERT3U(SectorsNow, ==, (Mdl->ByteCount / SectorSize)); - - Segment->Length = __min(Mdl->ByteCount, PAGE_SIZE); - Segment->Buffer = MmMapLockedPagesSpecifyCache(Mdl, KernelMode, - MmCached, NULL, FALSE, __PdoPriority(Pdo)); - if (!Segment->Buffer) { - goto fail; - } - - ASSERT3P(MmGetMdlPfnArray(Mdl)[0], ==, Segment->Pfn[0]); - ASSERT3P(MmGetMdlPfnArray(Mdl)[1], ==, Segment->Pfn[1]); - - return TRUE; - -fail: - return FALSE; -} - -static FORCEINLINE VOID -RequestCopyOutput( - __in PXENVBD_REQUEST Request - ) -{ - PLIST_ENTRY Entry; - - if (Request->Operation != BLKIF_OP_READ) - return; - - for (Entry = Request->Segments.Flink; - Entry != &Request->Segments; - Entry = Entry->Flink) { - PXENVBD_SEGMENT Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); - - if (Segment->BufferId) - BufferCopyOut(Segment->BufferId, Segment->Buffer, Segment->Length); - } -} - -static BOOLEAN -PrepareSegment( - IN PXENVBD_PDO Pdo, - IN PXENVBD_SEGMENT Segment, - IN PXENVBD_SG_LIST SGList, - IN BOOLEAN ReadOnly, - IN ULONG SectorsLeft, - OUT PULONG SectorsNow - ) -{ - PFN_NUMBER Pfn; - NTSTATUS Status; - PXENVBD_GRANTER Granter = FrontendGetGranter(Pdo->Frontend); - const ULONG SectorSize = PdoSectorSize(Pdo); - const ULONG SectorsPerPage = __SectorsPerPage(SectorSize); - - if (SGListNext(SGList, SectorSize - 1)) { - ++Pdo->SegsGranted; - // get first sector, last sector and count - Segment->FirstSector = (UCHAR)((__Offset(SGList->PhysAddr) + SectorSize - 1) / SectorSize); - *SectorsNow = __min(SectorsLeft, SectorsPerPage - Segment->FirstSector); - Segment->LastSector = (UCHAR)(Segment->FirstSector + *SectorsNow - 1); - Segment->BufferId = NULL; // granted, ensure its null - Segment->Buffer = NULL; // granted, ensure its null - Segment->Length = 0; // granted, ensure its 0 - Pfn = __Phys2Pfn(SGList->PhysAddr); - - ASSERT3U((SGList->PhysLen / SectorSize), ==, *SectorsNow); - ASSERT3U((SGList->PhysLen & (SectorSize - 1)), ==, 0); - } else { - ++Pdo->SegsBounced; - // get first sector, last sector and count - Segment->FirstSector = 0; - *SectorsNow = __min(SectorsLeft, SectorsPerPage); - Segment->LastSector = (UCHAR)(*SectorsNow - 1); - - // map SGList to Virtual Address. Populates Segment->Buffer and Segment->Length - if (!MapSegmentBuffer(Pdo, Segment, SGList, SectorSize, *SectorsNow)) { - ++Pdo->FailedMaps; - goto fail1; - } - - // get a buffer - if (!BufferGet(Segment, &Segment->BufferId, &Pfn)) { - ++Pdo->FailedBounces; - goto fail2; - } - - // copy contents in - if (ReadOnly) { // Operation == BLKIF_OP_WRITE - BufferCopyIn(Segment->BufferId, Segment->Buffer, Segment->Length); - } - } - - // Grant segment's page - Status = GranterGet(Granter, Pfn, ReadOnly, &Segment->Grant); - if (!NT_SUCCESS(Status)) { - ++Pdo->FailedGrants; - goto fail3; - } - - return TRUE; - -fail3: -fail2: -fail1: - return FALSE; -} - -static BOOLEAN -PrepareBlkifReadWrite( - IN PXENVBD_PDO Pdo, - IN PXENVBD_REQUEST Request, - IN PXENVBD_SG_LIST SGList, - IN ULONG MaxSegments, - IN ULONG64 SectorStart, - IN ULONG SectorsLeft, - OUT PULONG SectorsDone - ) -{ - UCHAR Operation; - BOOLEAN ReadOnly; - ULONG Index; - __Operation(Cdb_OperationEx(Request->Srb), &Operation, &ReadOnly); - - Request->Operation = Operation; - Request->NrSegments = 0; - Request->FirstSector = SectorStart; - - for (Index = 0; - Index < MaxSegments && - SectorsLeft > 0; - ++Index) { - PXENVBD_SEGMENT Segment; - ULONG SectorsNow; - - Segment = PdoGetSegment(Pdo); - if (Segment == NULL) - goto fail1; - - InsertTailList(&Request->Segments, &Segment->Entry); - ++Request->NrSegments; - - if (!PrepareSegment(Pdo, - Segment, - SGList, - ReadOnly, - SectorsLeft, - &SectorsNow)) - goto fail2; - - *SectorsDone += SectorsNow; - SectorsLeft -= SectorsNow; - } - ASSERT3U(Request->NrSegments, >, 0); - ASSERT3U(Request->NrSegments, <=, MaxSegments); - - return TRUE; - -fail2: -fail1: - return FALSE; -} - -static BOOLEAN -PrepareBlkifIndirect( - IN PXENVBD_PDO Pdo, - IN PXENVBD_REQUEST Request - ) -{ - ULONG Index; - ULONG NrSegments = 0; - - for (Index = 0; - Index < BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST && - NrSegments < Request->NrSegments; - ++Index) { - PXENVBD_INDIRECT Indirect; - - Indirect = PdoGetIndirect(Pdo); - if (Indirect == NULL) - goto fail1; - InsertTailList(&Request->Indirects, &Indirect->Entry); - - NrSegments += XENVBD_MAX_SEGMENTS_PER_PAGE; - } - - return TRUE; - -fail1: - return FALSE; -} - -static FORCEINLINE ULONG -UseIndirect( - IN PXENVBD_PDO Pdo, - IN ULONG SectorsLeft - ) -{ - const ULONG SectorsPerPage = __SectorsPerPage(PdoSectorSize(Pdo)); - const ULONG MaxIndirectSegs = FrontendGetFeatures(Pdo->Frontend)->Indirect; - - if (MaxIndirectSegs <= BLKIF_MAX_SEGMENTS_PER_REQUEST) - return BLKIF_MAX_SEGMENTS_PER_REQUEST; // not supported - - if (SectorsLeft < BLKIF_MAX_SEGMENTS_PER_REQUEST * SectorsPerPage) - return BLKIF_MAX_SEGMENTS_PER_REQUEST; // first into a single BLKIF_OP_{READ/WRITE} - - return MaxIndirectSegs; -} - -static FORCEINLINE ULONG -PdoQueueRequestList( - IN PXENVBD_PDO Pdo, - IN PLIST_ENTRY List - ) -{ - ULONG Count = 0; - for (;;) { - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry; - - Entry = RemoveHeadList(List); - if (Entry == List) - break; - - ++Count; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - __PdoIncBlkifOpCount(Pdo, Request); - QueueAppend(&Pdo->PreparedReqs, &Request->Entry); - } - return Count; -} - -static FORCEINLINE VOID -PdoCancelRequestList( - IN PXENVBD_PDO Pdo, - IN PLIST_ENTRY List - ) -{ - for (;;) { - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry; - - Entry = RemoveHeadList(List); - if (Entry == List) - break; - - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - PdoPutRequest(Pdo, Request); - } -} - -__checkReturn -static BOOLEAN -PrepareReadWrite( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); - ULONG64 SectorStart = Cdb_LogicalBlock(Srb); - ULONG SectorsLeft = Cdb_TransferBlock(Srb); - LIST_ENTRY List; - XENVBD_SG_LIST SGList; - ULONG DebugCount; - - Srb->SrbStatus = SRB_STATUS_PENDING; - - InitializeListHead(&List); - SrbExt->Count = 0; - - RtlZeroMemory(&SGList, sizeof(SGList)); - SGList.SGList = StorPortGetScatterGatherList(PdoGetAdapter(Pdo), Srb); - - while (SectorsLeft > 0) { - ULONG MaxSegments; - ULONG SectorsDone = 0; - PXENVBD_REQUEST Request; - - Request = PdoGetRequest(Pdo); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->Entry); - InterlockedIncrement(&SrbExt->Count); - - Request->Srb = Srb; - MaxSegments = UseIndirect(Pdo, SectorsLeft); - - if (!PrepareBlkifReadWrite(Pdo, - Request, - &SGList, - MaxSegments, - SectorStart, - SectorsLeft, - &SectorsDone)) - goto fail2; - - if (MaxSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { - if (!PrepareBlkifIndirect(Pdo, Request)) - goto fail3; - } - - SectorsLeft -= SectorsDone; - SectorStart += SectorsDone; - } - - DebugCount = PdoQueueRequestList(Pdo, &List); - if (DebugCount != (ULONG)SrbExt->Count) { - Trace("[%u] %d != %u\n", PdoGetTargetId(Pdo), SrbExt->Count, DebugCount); - } - return TRUE; - -fail3: -fail2: -fail1: - PdoCancelRequestList(Pdo, &List); - SrbExt->Count = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; -} - -__checkReturn -static BOOLEAN -PrepareSyncCache( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); - PXENVBD_REQUEST Request; - LIST_ENTRY List; - UCHAR Operation; - ULONG DebugCount; - - Srb->SrbStatus = SRB_STATUS_PENDING; - - if (FrontendGetDiskInfo(Pdo->Frontend)->FlushCache) - Operation = BLKIF_OP_FLUSH_DISKCACHE; - else - Operation = BLKIF_OP_WRITE_BARRIER; - - InitializeListHead(&List); - SrbExt->Count = 0; - - Request = PdoGetRequest(Pdo); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->Entry); - InterlockedIncrement(&SrbExt->Count); - - Request->Srb = Srb; - Request->Operation = Operation; - Request->FirstSector = Cdb_LogicalBlock(Srb); - - DebugCount = PdoQueueRequestList(Pdo, &List); - if (DebugCount != (ULONG)SrbExt->Count) { - Trace("[%u] %d != %u\n", PdoGetTargetId(Pdo), SrbExt->Count, DebugCount); - } - return TRUE; - -fail1: - PdoCancelRequestList(Pdo, &List); - SrbExt->Count = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; -} - -__checkReturn -static BOOLEAN -PrepareUnmap( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); - PUNMAP_LIST_HEADER Unmap = Srb->DataBuffer; - ULONG Count = _byteswap_ushort(*(PUSHORT)Unmap->BlockDescrDataLength) / sizeof(UNMAP_BLOCK_DESCRIPTOR); - ULONG Index; - LIST_ENTRY List; - ULONG DebugCount; - - Srb->SrbStatus = SRB_STATUS_PENDING; - - InitializeListHead(&List); - SrbExt->Count = 0; - - for (Index = 0; Index < Count; ++Index) { - PUNMAP_BLOCK_DESCRIPTOR Descr = &Unmap->Descriptors[Index]; - PXENVBD_REQUEST Request; - - Request = PdoGetRequest(Pdo); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->Entry); - InterlockedIncrement(&SrbExt->Count); - - Request->Srb = Srb; - Request->Operation = BLKIF_OP_DISCARD; - Request->FirstSector = _byteswap_uint64(*(PULONG64)Descr->StartingLba); - Request->NrSectors = _byteswap_ulong(*(PULONG)Descr->LbaCount); - Request->Flags = 0; - } - - DebugCount = PdoQueueRequestList(Pdo, &List); - if (DebugCount != (ULONG)SrbExt->Count) { - Trace("[%u] %d != %u\n", PdoGetTargetId(Pdo), SrbExt->Count, DebugCount); - } - return TRUE; - -fail1: - PdoCancelRequestList(Pdo, &List); - SrbExt->Count = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; -} - -//============================================================================= -// Queue-Related -static FORCEINLINE VOID -__PdoPauseDataPath( - __in PXENVBD_PDO Pdo, - __in BOOLEAN Timeout - ) -{ - KIRQL Irql; - ULONG Requests; - ULONG Count = 0; - PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Pdo->Frontend); - PXENVBD_BLOCKRING BlockRing = FrontendGetBlockRing(Pdo->Frontend); - - KeAcquireSpinLock(&Pdo->Lock, &Irql); - ++Pdo->Paused; - KeReleaseSpinLock(&Pdo->Lock, Irql); - - Requests = QueueCount(&Pdo->SubmittedReqs); - KeMemoryBarrier(); - - Verbose("Target[%d] : Waiting for %d Submitted requests\n", PdoGetTargetId(Pdo), Requests); - - // poll ring and send event channel notification every 1ms (for up to 3 minutes) - while (QueueCount(&Pdo->SubmittedReqs)) { - if (Timeout && Count > 180000) - break; - KeRaiseIrql(DISPATCH_LEVEL, &Irql); - BlockRingPoll(BlockRing); - KeLowerIrql(Irql); - NotifierSend(Notifier); // let backend know it needs to do some work - StorPortStallExecution(1000); // 1000 micro-seconds - ++Count; - } - - Verbose("Target[%d] : %u/%u Submitted requests left (%u iterrations)\n", - PdoGetTargetId(Pdo), QueueCount(&Pdo->SubmittedReqs), Requests, Count); - - // Abort Fresh SRBs - for (;;) { - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY Entry = QueuePop(&Pdo->FreshSrbs); - if (Entry == NULL) - break; - SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); - - Verbose("Target[%d] : FreshSrb 0x%p -> SCSI_ABORTED\n", PdoGetTargetId(Pdo), SrbExt->Srb); - SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; - SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED; - AdapterCompleteSrb(PdoGetAdapter(Pdo), SrbExt->Srb); - } - - // Fail PreparedReqs - for (;;) { - PXENVBD_SRBEXT SrbExt; - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry = QueuePop(&Pdo->PreparedReqs); - if (Entry == NULL) - break; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - SrbExt = GetSrbExt(Request->Srb); - - Verbose("Target[%d] : PreparedReq 0x%p -> FAILED\n", PdoGetTargetId(Pdo), Request); - - SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; - PdoPutRequest(Pdo, Request); - - if (InterlockedDecrement(&SrbExt->Count) == 0) { - SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED - AdapterCompleteSrb(PdoGetAdapter(Pdo), SrbExt->Srb); - } - } -} - -static FORCEINLINE VOID -__PdoUnpauseDataPath( - __in PXENVBD_PDO Pdo - ) -{ - KIRQL Irql; - - KeAcquireSpinLock(&Pdo->Lock, &Irql); - --Pdo->Paused; - KeReleaseSpinLock(&Pdo->Lock, Irql); -} - -static FORCEINLINE BOOLEAN -PdoPrepareFresh( - IN PXENVBD_PDO Pdo - ) -{ - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY Entry; - - Entry = QueuePop(&Pdo->FreshSrbs); - if (Entry == NULL) - return FALSE; // fresh queue is empty - - SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); - - switch (Cdb_OperationEx(SrbExt->Srb)) { - case SCSIOP_READ: - case SCSIOP_WRITE: - if (PrepareReadWrite(Pdo, SrbExt->Srb)) - return TRUE; // prepared this SRB - break; - case SCSIOP_SYNCHRONIZE_CACHE: - if (PrepareSyncCache(Pdo, SrbExt->Srb)) - return TRUE; // prepared this SRB - break; - case SCSIOP_UNMAP: - if (PrepareUnmap(Pdo, SrbExt->Srb)) - return TRUE; // prepared this SRB - break; - default: - ASSERT(FALSE); - break; - } - QueueUnPop(&Pdo->FreshSrbs, &SrbExt->Entry); - - return FALSE; // prepare failed -} - -static FORCEINLINE BOOLEAN -PdoSubmitPrepared( - __in PXENVBD_PDO Pdo - ) -{ - PXENVBD_BLOCKRING BlockRing = FrontendGetBlockRing(Pdo->Frontend); - if (PdoIsPaused(Pdo)) { - if (QueueCount(&Pdo->PreparedReqs)) - Warning("Target[%d] : Paused, not submitting new requests (%u)\n", - PdoGetTargetId(Pdo), - QueueCount(&Pdo->PreparedReqs)); - return FALSE; - } - - for (;;) { - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry; - - Entry = QueuePop(&Pdo->PreparedReqs); - if (Entry == NULL) - break; - - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - - QueueAppend(&Pdo->SubmittedReqs, &Request->Entry); - KeMemoryBarrier(); - - if (BlockRingSubmit(BlockRing, Request)) - continue; - - QueueRemove(&Pdo->SubmittedReqs, &Request->Entry); - QueueUnPop(&Pdo->PreparedReqs, &Request->Entry); - return FALSE; // ring full - } - - return TRUE; -} - -static FORCEINLINE VOID -PdoCompleteShutdown( - __in PXENVBD_PDO Pdo - ) -{ - if (QueueCount(&Pdo->ShutdownSrbs) == 0) - return; - - if (QueueCount(&Pdo->FreshSrbs) || - QueueCount(&Pdo->PreparedReqs) || - QueueCount(&Pdo->SubmittedReqs)) - return; - - for (;;) { - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY Entry = QueuePop(&Pdo->ShutdownSrbs); - if (Entry == NULL) - break; - SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); - SrbExt->Srb->SrbStatus = SRB_STATUS_SUCCESS; - AdapterCompleteSrb(PdoGetAdapter(Pdo), SrbExt->Srb); - } -} - -static FORCEINLINE PCHAR -BlkifOperationName( - IN UCHAR Operation - ) -{ - switch (Operation) { - case BLKIF_OP_READ: return "READ"; - case BLKIF_OP_WRITE: return "WRITE"; - case BLKIF_OP_WRITE_BARRIER: return "WRITE_BARRIER"; - case BLKIF_OP_FLUSH_DISKCACHE: return "FLUSH_DISKCACHE"; - case BLKIF_OP_RESERVED_1: return "RESERVED_1"; - case BLKIF_OP_DISCARD: return "DISCARD"; - case BLKIF_OP_INDIRECT: return "INDIRECT"; - default: return ""; - } -} - -VOID -PdoSubmitRequests( - __in PXENVBD_PDO Pdo - ) -{ - for (;;) { - // submit all prepared requests (0 or more requests) - // return TRUE if submitted 0 or more requests from prepared queue - // return FALSE iff ring is full - if (!PdoSubmitPrepared(Pdo)) - break; - - // prepare a single SRB (into 1 or more requests) - // return TRUE if prepare succeeded - // return FALSE if prepare failed or fresh queue empty - if (!PdoPrepareFresh(Pdo)) - break; - } - - // if no requests/SRBs outstanding, complete any shutdown SRBs - PdoCompleteShutdown(Pdo); -} - -VOID -PdoCompleteResponse( - __in PXENVBD_PDO Pdo, - __in ULONG Tag, - __in SHORT Status - ) -{ - PXENVBD_REQUEST Request; - PSCSI_REQUEST_BLOCK Srb; - PXENVBD_SRBEXT SrbExt; - - Request = PdoRequestFromTag(Pdo, Tag); - if (Request == NULL) - return; - - Srb = Request->Srb; - SrbExt = GetSrbExt(Srb); - ASSERT3P(SrbExt, !=, NULL); - - switch (Status) { - case BLKIF_RSP_OKAY: - RequestCopyOutput(Request); - break; - - case BLKIF_RSP_EOPNOTSUPP: - // Remove appropriate feature support - FrontendRemoveFeature(Pdo->Frontend, Request->Operation); - // Succeed this SRB, subsiquent SRBs will be succeeded instead of being passed to the backend. - Srb->SrbStatus = SRB_STATUS_SUCCESS; - break; - - case BLKIF_RSP_ERROR: - default: - Warning("Target[%d] : %s BLKIF_RSP_ERROR (Tag %x)\n", - PdoGetTargetId(Pdo), BlkifOperationName(Request->Operation), Tag); - Srb->SrbStatus = SRB_STATUS_ERROR; - break; - } - - PdoPutRequest(Pdo, Request); - - // complete srb - if (InterlockedDecrement(&SrbExt->Count) == 0) { - if (Srb->SrbStatus == SRB_STATUS_PENDING) { - // SRB has not hit a failure condition (BLKIF_RSP_ERROR | BLKIF_RSP_EOPNOTSUPP) - // from any of its responses. SRB must have succeeded - Srb->SrbStatus = SRB_STATUS_SUCCESS; - Srb->ScsiStatus = 0x00; // SCSI_GOOD - } else { - // Srb->SrbStatus has already been set by 1 or more requests with Status != BLKIF_RSP_OKAY - Srb->ScsiStatus = 0x40; // SCSI_ABORTED - } - - AdapterCompleteSrb(PdoGetAdapter(Pdo), Srb); - } -} - -VOID -PdoPreResume( - __in PXENVBD_PDO Pdo - ) -{ - LIST_ENTRY List; - - InitializeListHead(&List); - - // pop all submitted requests, cleanup and add associated SRB to a list - for (;;) { - PXENVBD_SRBEXT SrbExt; - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry = QueuePop(&Pdo->SubmittedReqs); - if (Entry == NULL) - break; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - SrbExt = GetSrbExt(Request->Srb); - - PdoPutRequest(Pdo, Request); - - if (InterlockedDecrement(&SrbExt->Count) == 0) { - InsertTailList(&List, &SrbExt->Entry); - } - } - - // pop all prepared requests, cleanup and add associated SRB to a list - for (;;) { - PXENVBD_SRBEXT SrbExt; - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry = QueuePop(&Pdo->PreparedReqs); - if (Entry == NULL) - break; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - SrbExt = GetSrbExt(Request->Srb); - - PdoPutRequest(Pdo, Request); - - if (InterlockedDecrement(&SrbExt->Count) == 0) { - InsertTailList(&List, &SrbExt->Entry); - } - } - - // foreach SRB in list, put on start of FreshSrbs - for (;;) { - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY Entry = RemoveTailList(&List); - if (Entry == &List) - break; - SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); - - QueueUnPop(&Pdo->FreshSrbs, &SrbExt->Entry); - } - - // now the first set of requests popped off submitted list is the next SRB - // to be popped off the fresh list -} - -VOID -PdoPostResume( - __in PXENVBD_PDO Pdo - ) -{ - KIRQL Irql; - - Verbose("Target[%d] : %d Fresh SRBs\n", PdoGetTargetId(Pdo), QueueCount(&Pdo->FreshSrbs)); - - // clear missing flag - KeAcquireSpinLock(&Pdo->Lock, &Irql); - Verbose("Target[%d] : %s (%s)\n", PdoGetTargetId(Pdo), Pdo->Missing ? "MISSING" : "NOT_MISSING", Pdo->Reason); - Pdo->Missing = FALSE; - Pdo->Reason = NULL; - KeReleaseSpinLock(&Pdo->Lock, Irql); -} - -//============================================================================= -// SRBs -__checkReturn -static FORCEINLINE BOOLEAN -__ValidateSectors( - __in ULONG64 SectorCount, - __in ULONG64 Start, - __in ULONG Length - ) -{ - // Deal with overflow - return (Start < SectorCount) && ((Start + Length) <= SectorCount); -} - -__checkReturn -static FORCEINLINE BOOLEAN -__ValidateSrbBuffer( - __in PCHAR Caller, - __in PSCSI_REQUEST_BLOCK Srb, - __in ULONG MinLength - ) -{ - if (Srb->DataBuffer == NULL) { - Error("%s: Srb[0x%p].DataBuffer = NULL\n", Caller, Srb); - return FALSE; - } - if (MinLength) { - if (Srb->DataTransferLength < MinLength) { - Error("%s: Srb[0x%p].DataTransferLength < %d\n", Caller, Srb, MinLength); - return FALSE; - } - } else { - if (Srb->DataTransferLength == 0) { - Error("%s: Srb[0x%p].DataTransferLength = 0\n", Caller, Srb); - return FALSE; - } - } - - return TRUE; -} - -__checkReturn -static DECLSPEC_NOINLINE BOOLEAN -PdoReadWrite( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Pdo->Frontend); - PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); - PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Pdo->Frontend); - - if (FrontendGetCaps(Pdo->Frontend)->Connected == FALSE) { - Trace("Target[%d] : Not Ready, fail SRB\n", PdoGetTargetId(Pdo)); - Srb->ScsiStatus = 0x40; // SCSI_ABORT; - return TRUE; - } - - // check valid sectors - if (!__ValidateSectors(DiskInfo->SectorCount, Cdb_LogicalBlock(Srb), Cdb_TransferBlock(Srb))) { - Trace("Target[%d] : Invalid Sector (%d @ %lld < %lld)\n", PdoGetTargetId(Pdo), Cdb_TransferBlock(Srb), Cdb_LogicalBlock(Srb), DiskInfo->SectorCount); - Srb->ScsiStatus = 0x40; // SCSI_ABORT - return TRUE; // Complete now - } - - QueueAppend(&Pdo->FreshSrbs, &SrbExt->Entry); - NotifierKick(Notifier); - - return FALSE; -} - -__checkReturn -static DECLSPEC_NOINLINE BOOLEAN -PdoSyncCache( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); - PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Pdo->Frontend); - - if (FrontendGetCaps(Pdo->Frontend)->Connected == FALSE) { - Trace("Target[%d] : Not Ready, fail SRB\n", PdoGetTargetId(Pdo)); - Srb->ScsiStatus = 0x40; // SCSI_ABORT; - return TRUE; - } - - if (FrontendGetDiskInfo(Pdo->Frontend)->FlushCache == FALSE && - FrontendGetDiskInfo(Pdo->Frontend)->Barrier == FALSE) { - Trace("Target[%d] : FLUSH and BARRIER not supported, suppressing\n", PdoGetTargetId(Pdo)); - Srb->ScsiStatus = 0x00; // SCSI_GOOD - Srb->SrbStatus = SRB_STATUS_SUCCESS; - return TRUE; - } - - QueueAppend(&Pdo->FreshSrbs, &SrbExt->Entry); - NotifierKick(Notifier); - - return FALSE; -} - -__checkReturn -static DECLSPEC_NOINLINE BOOLEAN -PdoUnmap( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); - PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Pdo->Frontend); - - if (FrontendGetCaps(Pdo->Frontend)->Connected == FALSE) { - Trace("Target[%d] : Not Ready, fail SRB\n", PdoGetTargetId(Pdo)); - Srb->ScsiStatus = 0x40; // SCSI_ABORT; - return TRUE; - } - - if (FrontendGetDiskInfo(Pdo->Frontend)->Discard == FALSE) { - Trace("Target[%d] : DISCARD not supported, suppressing\n", PdoGetTargetId(Pdo)); - Srb->ScsiStatus = 0x00; // SCSI_GOOD - Srb->SrbStatus = SRB_STATUS_SUCCESS; - return TRUE; - } - - QueueAppend(&Pdo->FreshSrbs, &SrbExt->Entry); - NotifierKick(Notifier); - - return FALSE; -} - -#define MODE_CACHING_PAGE_LENGTH 20 -static DECLSPEC_NOINLINE VOID -PdoModeSense( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PMODE_PARAMETER_HEADER Header = Srb->DataBuffer; - const UCHAR PageCode = Cdb_PageCode(Srb); - ULONG LengthLeft = Cdb_AllocationLength(Srb); - PVOID CurrentPage = Srb->DataBuffer; - - UNREFERENCED_PARAMETER(Pdo); - - RtlZeroMemory(Srb->DataBuffer, Srb->DataTransferLength); - - if (!__ValidateSrbBuffer(__FUNCTION__, Srb, (ULONG)sizeof(struct _MODE_SENSE))) { - Srb->ScsiStatus = 0x40; - Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; - Srb->DataTransferLength = 0; - return; - } - - // TODO : CDROM requires more ModePage entries - // Header - Header->ModeDataLength = sizeof(MODE_PARAMETER_HEADER) - 1; - Header->MediumType = 0; - Header->DeviceSpecificParameter = 0; - Header->BlockDescriptorLength = 0; - LengthLeft -= sizeof(MODE_PARAMETER_HEADER); - CurrentPage = ((PUCHAR)CurrentPage + sizeof(MODE_PARAMETER_HEADER)); - - // Fill in Block Parameters (if Specified and space) - // when the DBD (Disable Block Descriptor) is set, ignore the block page - if (Cdb_Dbd(Srb) == 0 && - LengthLeft >= sizeof(MODE_PARAMETER_BLOCK)) { - PMODE_PARAMETER_BLOCK Block = (PMODE_PARAMETER_BLOCK)CurrentPage; - // Fill in BlockParams - Block->DensityCode = 0; - Block->NumberOfBlocks[0] = 0; - Block->NumberOfBlocks[1] = 0; - Block->NumberOfBlocks[2] = 0; - Block->BlockLength[0] = 0; - Block->BlockLength[1] = 0; - Block->BlockLength[2] = 0; - - Header->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); - Header->ModeDataLength += sizeof(MODE_PARAMETER_BLOCK); - LengthLeft -= sizeof(MODE_PARAMETER_BLOCK); - CurrentPage = ((PUCHAR)CurrentPage + sizeof(MODE_PARAMETER_BLOCK)); - } - - // Fill in Cache Parameters (if Specified and space) - if ((PageCode == MODE_PAGE_CACHING || PageCode == MODE_SENSE_RETURN_ALL) && - LengthLeft >= MODE_CACHING_PAGE_LENGTH) { - PMODE_CACHING_PAGE Caching = (PMODE_CACHING_PAGE)CurrentPage; - // Fill in CachingParams - Caching->PageCode = MODE_PAGE_CACHING; - Caching->PageSavable = 0; - Caching->PageLength = MODE_CACHING_PAGE_LENGTH; - Caching->ReadDisableCache = 0; - Caching->MultiplicationFactor = 0; - Caching->WriteCacheEnable = FrontendGetDiskInfo(Pdo->Frontend)->FlushCache ? 1 : 0; - Caching->WriteRetensionPriority = 0; - Caching->ReadRetensionPriority = 0; - Caching->DisablePrefetchTransfer[0] = 0; - Caching->DisablePrefetchTransfer[1] = 0; - Caching->MinimumPrefetch[0] = 0; - Caching->MinimumPrefetch[1] = 0; - Caching->MaximumPrefetch[0] = 0; - Caching->MaximumPrefetch[1] = 0; - Caching->MaximumPrefetchCeiling[0] = 0; - Caching->MaximumPrefetchCeiling[1] = 0; - - Header->ModeDataLength += MODE_CACHING_PAGE_LENGTH; - LengthLeft -= MODE_CACHING_PAGE_LENGTH; - CurrentPage = ((PUCHAR)CurrentPage + MODE_CACHING_PAGE_LENGTH); - } - - // Fill in Informational Exception Parameters (if Specified and space) - if ((PageCode == MODE_PAGE_FAULT_REPORTING || PageCode == MODE_SENSE_RETURN_ALL) && - LengthLeft >= sizeof(MODE_INFO_EXCEPTIONS)) { - PMODE_INFO_EXCEPTIONS Exceptions = (PMODE_INFO_EXCEPTIONS)CurrentPage; - // Fill in Exceptions - Exceptions->PageCode = MODE_PAGE_FAULT_REPORTING; - Exceptions->PSBit = 0; - Exceptions->PageLength = sizeof(MODE_INFO_EXCEPTIONS); - Exceptions->Flags = 0; - Exceptions->Dexcpt = 1; // disabled - Exceptions->ReportMethod = 0; - Exceptions->IntervalTimer[0] = 0; - Exceptions->IntervalTimer[1] = 0; - Exceptions->IntervalTimer[2] = 0; - Exceptions->IntervalTimer[3] = 0; - Exceptions->ReportCount[0] = 0; - Exceptions->ReportCount[1] = 0; - Exceptions->ReportCount[2] = 0; - Exceptions->ReportCount[3] = 0; - - Header->ModeDataLength += sizeof(MODE_INFO_EXCEPTIONS); - LengthLeft -= sizeof(MODE_INFO_EXCEPTIONS); - CurrentPage = ((PUCHAR)CurrentPage + sizeof(MODE_INFO_EXCEPTIONS)); - } - - // Finish this SRB - Srb->SrbStatus = SRB_STATUS_SUCCESS; - Srb->DataTransferLength = __min(Cdb_AllocationLength(Srb), (ULONG)(Header->ModeDataLength + 1)); -} - -static DECLSPEC_NOINLINE VOID -PdoRequestSense( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PSENSE_DATA Sense = Srb->DataBuffer; - - UNREFERENCED_PARAMETER(Pdo); - - if (!__ValidateSrbBuffer(__FUNCTION__, Srb, (ULONG)sizeof(SENSE_DATA))) { - Srb->ScsiStatus = 0x40; - Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; - return; - } - - RtlZeroMemory(Sense, sizeof(SENSE_DATA)); - - Sense->ErrorCode = 0x70; - Sense->Valid = 1; - Sense->AdditionalSenseCodeQualifier = 0; - Sense->SenseKey = SCSI_SENSE_NO_SENSE; - Sense->AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE; - Srb->DataTransferLength = sizeof(SENSE_DATA); - Srb->SrbStatus = SRB_STATUS_SUCCESS; -} - -static DECLSPEC_NOINLINE VOID -PdoReportLuns( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - ULONG Length; - ULONG Offset; - ULONG AllocLength = Cdb_AllocationLength(Srb); - PUCHAR Buffer = Srb->DataBuffer; - - UNREFERENCED_PARAMETER(Pdo); - - if (!__ValidateSrbBuffer(__FUNCTION__, Srb, 8)) { - Srb->ScsiStatus = 0x40; - Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; - Srb->DataTransferLength = 0; - return; - } - - RtlZeroMemory(Buffer, AllocLength); - - Length = 0; - Offset = 8; - - if (Offset + 8 <= AllocLength) { - Buffer[Offset] = 0; - Offset += 8; - Length += 8; - } - - if (Offset + 8 <= AllocLength) { - Buffer[Offset] = XENVBD_MAX_TARGETS; - Offset += 8; - Length += 8; - } - - REVERSE_BYTES(Buffer, &Length); - - Srb->DataTransferLength = __min(Length, AllocLength); - Srb->SrbStatus = SRB_STATUS_SUCCESS; -} - -static DECLSPEC_NOINLINE VOID -PdoReadCapacity( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PREAD_CAPACITY_DATA Capacity = Srb->DataBuffer; - PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Pdo->Frontend); - ULONG64 SectorCount; - ULONG SectorSize; - ULONG LastBlock; - - if (Cdb_PMI(Srb) == 0 && Cdb_LogicalBlock(Srb) != 0) { - Srb->ScsiStatus = 0x02; // CHECK_CONDITION - return; - } - - SectorCount = DiskInfo->SectorCount; - SectorSize = DiskInfo->SectorSize; - - if (SectorCount == (ULONG)SectorCount) - LastBlock = (ULONG)SectorCount - 1; - else - LastBlock = ~(ULONG)0; - - if (Capacity) { - Capacity->LogicalBlockAddress = _byteswap_ulong(LastBlock); - Capacity->BytesPerBlock = _byteswap_ulong(SectorSize); - } - - Srb->SrbStatus = SRB_STATUS_SUCCESS; -} - -static DECLSPEC_NOINLINE VOID -PdoReadCapacity16( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PREAD_CAPACITY16_DATA Capacity = Srb->DataBuffer; - PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Pdo->Frontend); - ULONG64 SectorCount; - ULONG SectorSize; - ULONG PhysSectorSize; - ULONG LogicalPerPhysical; - ULONG LogicalPerPhysicalExponent; - - if (Cdb_PMI(Srb) == 0 && Cdb_LogicalBlock(Srb) != 0) { - Srb->ScsiStatus = 0x02; // CHECK_CONDITION - return; - } - - SectorCount = DiskInfo->SectorCount; - SectorSize = DiskInfo->SectorSize; - PhysSectorSize = DiskInfo->PhysSectorSize; - - LogicalPerPhysical = PhysSectorSize / SectorSize; - - if (!_BitScanReverse(&LogicalPerPhysicalExponent, LogicalPerPhysical)) - LogicalPerPhysicalExponent = 0; - - if (Capacity) { - Capacity->LogicalBlockAddress.QuadPart = _byteswap_uint64(SectorCount - 1); - Capacity->BytesPerBlock = _byteswap_ulong(SectorSize); - Capacity->LogicalPerPhysicalExponent = (UCHAR)LogicalPerPhysicalExponent; - } - - Srb->SrbStatus = SRB_STATUS_SUCCESS; -} - -//============================================================================= -// StorPort Methods -__checkReturn -static FORCEINLINE BOOLEAN -__PdoExecuteScsi( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - const UCHAR Operation = Cdb_OperationEx(Srb); - PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Pdo->Frontend); - - if (DiskInfo->DiskInfo & VDISK_READONLY) { - Trace("Target[%d] : (%08x) Read-Only, fail SRB (%02x:%s)\n", PdoGetTargetId(Pdo), - DiskInfo->DiskInfo, Operation, Cdb_OperationName(Operation)); - Srb->ScsiStatus = 0x40; // SCSI_ABORT - return TRUE; - } - - // idea: check pdo state here. still push to freshsrbs - switch (Operation) { - case SCSIOP_READ: - case SCSIOP_WRITE: - return PdoReadWrite(Pdo, Srb); - break; - - case SCSIOP_SYNCHRONIZE_CACHE: - return PdoSyncCache(Pdo, Srb); - break; - - case SCSIOP_UNMAP: - return PdoUnmap(Pdo, Srb); - break; - - case SCSIOP_INQUIRY: - if (!StorPortSetDeviceQueueDepth(PdoGetAdapter(Pdo), - 0, - (UCHAR)PdoGetTargetId(Pdo), - 0, - XENVBD_MAX_QUEUE_DEPTH)) - Verbose("Target[%d] : Failed to set queue depth\n", - PdoGetTargetId(Pdo)); - PdoInquiry(PdoGetTargetId(Pdo), FrontendGetInquiry(Pdo->Frontend), Srb, Pdo->DeviceType); - break; - case SCSIOP_MODE_SENSE: - PdoModeSense(Pdo, Srb); - break; - case SCSIOP_REQUEST_SENSE: - PdoRequestSense(Pdo, Srb); - break; - case SCSIOP_REPORT_LUNS: - PdoReportLuns(Pdo, Srb); - break; - case SCSIOP_READ_CAPACITY: - PdoReadCapacity(Pdo, Srb); - break; - case SCSIOP_READ_CAPACITY16: - PdoReadCapacity16(Pdo, Srb); - break; - case SCSIOP_MEDIUM_REMOVAL: - case SCSIOP_TEST_UNIT_READY: - case SCSIOP_RESERVE_UNIT: - case SCSIOP_RESERVE_UNIT10: - case SCSIOP_RELEASE_UNIT: - case SCSIOP_RELEASE_UNIT10: - case SCSIOP_VERIFY: - case SCSIOP_VERIFY16: - Srb->SrbStatus = SRB_STATUS_SUCCESS; - break; - case SCSIOP_START_STOP_UNIT: - Trace("Target[%d] : Start/Stop Unit (%02X)\n", PdoGetTargetId(Pdo), Srb->Cdb[4]); - Srb->SrbStatus = SRB_STATUS_SUCCESS; - break; - default: - Trace("Target[%d] : Unsupported CDB (%02x:%s)\n", PdoGetTargetId(Pdo), Operation, Cdb_OperationName(Operation)); - break; - } - return TRUE; -} - -static FORCEINLINE BOOLEAN -__PdoQueueShutdown( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); - PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Pdo->Frontend); - - QueueAppend(&Pdo->ShutdownSrbs, &SrbExt->Entry); - NotifierKick(Notifier); - - return FALSE; -} - -static FORCEINLINE BOOLEAN -__PdoReset( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - Verbose("Target[%u] ====>\n", PdoGetTargetId(Pdo)); - - PdoReset(Pdo); - Srb->SrbStatus = SRB_STATUS_SUCCESS; - - Verbose("Target[%u] <====\n", PdoGetTargetId(Pdo)); - return TRUE; -} - -__checkReturn -static FORCEINLINE BOOLEAN -__ValidateSrbForPdo( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - const UCHAR Operation = Cdb_OperationEx(Srb); - - if (Pdo == NULL) { - Error("Invalid Pdo(NULL) (%02x:%s)\n", - Operation, Cdb_OperationName(Operation)); - Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID; - return FALSE; - } - - if (Srb->PathId != 0) { - Error("Target[%d] : Invalid PathId(%d) (%02x:%s)\n", - PdoGetTargetId(Pdo), Srb->PathId, Operation, Cdb_OperationName(Operation)); - Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID; - return FALSE; - } - - if (Srb->Lun != 0) { - Error("Target[%d] : Invalid Lun(%d) (%02x:%s)\n", - PdoGetTargetId(Pdo), Srb->Lun, Operation, Cdb_OperationName(Operation)); - Srb->SrbStatus = SRB_STATUS_INVALID_LUN; - return FALSE; - } - - if (PdoIsMissing(Pdo)) { - Error("Target[%d] : %s (%s) (%02x:%s)\n", - PdoGetTargetId(Pdo), Pdo->Missing ? "MISSING" : "NOT_MISSING", Pdo->Reason, Operation, Cdb_OperationName(Operation)); - Srb->SrbStatus = SRB_STATUS_NO_DEVICE; - return FALSE; - } - - return TRUE; -} - -__checkReturn -BOOLEAN -PdoStartIo( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - if (!__ValidateSrbForPdo(Pdo, Srb)) - return TRUE; - - switch (Srb->Function) { - case SRB_FUNCTION_EXECUTE_SCSI: - return __PdoExecuteScsi(Pdo, Srb); - - case SRB_FUNCTION_RESET_DEVICE: - return __PdoReset(Pdo, Srb); - - case SRB_FUNCTION_FLUSH: - case SRB_FUNCTION_SHUTDOWN: - return __PdoQueueShutdown(Pdo, Srb); - - default: - return TRUE; - } -} - -static FORCEINLINE VOID -__PdoCleanupSubmittedReqs( - IN PXENVBD_PDO Pdo - ) -{ - // Fail PreparedReqs - for (;;) { - PXENVBD_SRBEXT SrbExt; - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry = QueuePop(&Pdo->SubmittedReqs); - if (Entry == NULL) - break; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - SrbExt = GetSrbExt(Request->Srb); - - Verbose("Target[%d] : SubmittedReq 0x%p -> FAILED\n", PdoGetTargetId(Pdo), Request); - - PdoPutRequest(Pdo, Request); - - if (InterlockedDecrement(&SrbExt->Count) == 0) { - SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; - SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED - AdapterCompleteSrb(PdoGetAdapter(Pdo), SrbExt->Srb); - } - } -} - -VOID -PdoReset( - __in PXENVBD_PDO Pdo - ) -{ - Trace("Target[%d] ====> (Irql=%d)\n", PdoGetTargetId(Pdo), KeGetCurrentIrql()); - - __PdoPauseDataPath(Pdo, TRUE); - - if (QueueCount(&Pdo->SubmittedReqs)) { - Error("Target[%d] : backend has %u outstanding requests after a PdoReset\n", - PdoGetTargetId(Pdo), QueueCount(&Pdo->SubmittedReqs)); - } - - __PdoUnpauseDataPath(Pdo); - - Trace("Target[%d] <==== (Irql=%d)\n", PdoGetTargetId(Pdo), KeGetCurrentIrql()); -} - - -VOID -PdoSrbPnp( - __in PXENVBD_PDO Pdo, - __in PSCSI_PNP_REQUEST_BLOCK Srb - ) -{ - switch (Srb->PnPAction) { - case StorQueryCapabilities: { - PSTOR_DEVICE_CAPABILITIES DeviceCaps = Srb->DataBuffer; - PXENVBD_CAPS Caps = FrontendGetCaps(Pdo->Frontend); - - if (Caps->Removable) - DeviceCaps->Removable = 1; - if (Caps->Removable) - DeviceCaps->EjectSupported = 1; - if (Caps->SurpriseRemovable) - DeviceCaps->SurpriseRemovalOK = 1; - - DeviceCaps->UniqueID = 1; - - } break; - - default: - break; - } -} - -//============================================================================= -// PnP Handler -static FORCEINLINE VOID -__PdoDeviceUsageNotification( - __in PXENVBD_PDO Pdo, - __in PIRP Irp - ) -{ - PIO_STACK_LOCATION StackLocation; - BOOLEAN Value; - DEVICE_USAGE_NOTIFICATION_TYPE Type; - PXENVBD_CAPS Caps = FrontendGetCaps(Pdo->Frontend); - - StackLocation = IoGetCurrentIrpStackLocation(Irp); - Value = StackLocation->Parameters.UsageNotification.InPath; - Type = StackLocation->Parameters.UsageNotification.Type; - - switch (Type) { - case DeviceUsageTypePaging: - if (Caps->Paging == Value) - return; - Caps->Paging = Value; - break; - - case DeviceUsageTypeHibernation: - if (Caps->Hibernation == Value) - return; - Caps->Hibernation = Value; - break; - - case DeviceUsageTypeDumpFile: - if (Caps->DumpFile == Value) - return; - Caps->DumpFile = Value; - break; - - default: - return; - } - FrontendWriteUsage(Pdo->Frontend); -} - -static FORCEINLINE VOID -__PdoCheckEjectPending( - __in PXENVBD_PDO Pdo - ) -{ - KIRQL Irql; - BOOLEAN EjectPending = FALSE; - - KeAcquireSpinLock(&Pdo->Lock, &Irql); - if (Pdo->EjectPending) { - EjectPending = TRUE; - Pdo->EjectPending = FALSE; - Pdo->EjectRequested = TRUE; - } - KeReleaseSpinLock(&Pdo->Lock, Irql); - - if (EjectPending) { - Verbose("Target[%d] : IoRequestDeviceEject(0x%p)\n", PdoGetTargetId(Pdo), Pdo->DeviceObject); - IoRequestDeviceEject(Pdo->DeviceObject); - } -} - -static FORCEINLINE VOID -__PdoCheckEjectFailed( - __in PXENVBD_PDO Pdo - ) -{ - KIRQL Irql; - BOOLEAN EjectFailed = FALSE; - - KeAcquireSpinLock(&Pdo->Lock, &Irql); - if (Pdo->EjectRequested) { - EjectFailed = TRUE; - Pdo->EjectRequested = FALSE; - } - KeReleaseSpinLock(&Pdo->Lock, Irql); - - if (EjectFailed) { - Error("Target[%d] : Unplug failed due to open handle(s)!\n", PdoGetTargetId(Pdo)); - FrontendStoreWriteFrontend(Pdo->Frontend, "error", "Unplug failed due to open handle(s)!"); - } -} - -static FORCEINLINE VOID -__PdoRemoveDevice( - __in PXENVBD_PDO Pdo - ) -{ - PdoD0ToD3(Pdo); - - switch (PdoGetDevicePnpState(Pdo)) { - case SurpriseRemovePending: - PdoSetMissing(Pdo, "Surprise Remove"); - PdoSetDevicePnpState(Pdo, Deleted); - StorPortNotification(BusChangeDetected, PdoGetAdapter(Pdo), 0); - break; - - default: - PdoSetMissing(Pdo, "Removed"); - PdoSetDevicePnpState(Pdo, Deleted); - StorPortNotification(BusChangeDetected, PdoGetAdapter(Pdo), 0); - break; - } -} - -static FORCEINLINE VOID -__PdoEject( - __in PXENVBD_PDO Pdo - ) -{ - PdoSetMissing(Pdo, "Ejected"); - PdoSetDevicePnpState(Pdo, Deleted); - StorPortNotification(BusChangeDetected, PdoGetAdapter(Pdo), 0); -} - -__checkReturn -NTSTATUS -PdoDispatchPnp( - __in PXENVBD_PDO Pdo, - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp - ) -{ - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); - - __PdoCheckEjectPending(Pdo); - - switch (Stack->MinorFunction) { - case IRP_MN_START_DEVICE: - (VOID) PdoD3ToD0(Pdo); - PdoSetDevicePnpState(Pdo, Started); - break; - - case IRP_MN_QUERY_STOP_DEVICE: - PdoSetDevicePnpState(Pdo, StopPending); - break; - - case IRP_MN_CANCEL_STOP_DEVICE: - __PdoRestoreDevicePnpState(Pdo, StopPending); - break; - - case IRP_MN_STOP_DEVICE: - PdoD0ToD3(Pdo); - PdoSetDevicePnpState(Pdo, Stopped); - break; - - case IRP_MN_QUERY_REMOVE_DEVICE: - PdoSetDevicePnpState(Pdo, RemovePending); - break; - - case IRP_MN_CANCEL_REMOVE_DEVICE: - __PdoCheckEjectFailed(Pdo); - __PdoRestoreDevicePnpState(Pdo, RemovePending); - break; - - case IRP_MN_SURPRISE_REMOVAL: - PdoSetDevicePnpState(Pdo, SurpriseRemovePending); - break; - - case IRP_MN_REMOVE_DEVICE: - __PdoRemoveDevice(Pdo); - break; - - case IRP_MN_EJECT: - __PdoEject(Pdo); - break; - - case IRP_MN_DEVICE_USAGE_NOTIFICATION: - __PdoDeviceUsageNotification(Pdo, Irp); - break; - - default: - break; - } - PdoDereference(Pdo); - return DriverDispatchPnp(DeviceObject, Irp); -} - -__drv_maxIRQL(DISPATCH_LEVEL) -VOID -PdoIssueDeviceEject( - __in PXENVBD_PDO Pdo, - __in __nullterminated const CHAR* Reason - ) -{ - KIRQL Irql; - BOOLEAN DoEject = FALSE; - - KeAcquireSpinLock(&Pdo->Lock, &Irql); - if (Pdo->DeviceObject) { - DoEject = TRUE; - Pdo->EjectRequested = TRUE; - } else { - Pdo->EjectPending = TRUE; - } - KeReleaseSpinLock(&Pdo->Lock, Irql); - - Verbose("Target[%d] : Ejecting (%s - %s)\n", PdoGetTargetId(Pdo), DoEject ? "Now" : "Next PnP IRP", Reason); - if (!Pdo->WrittenEjected) { - Pdo->WrittenEjected = TRUE; - FrontendStoreWriteFrontend(Pdo->Frontend, "ejected", "1"); - } - if (DoEject) { - Verbose("Target[%d] : IoRequestDeviceEject(0x%p)\n", PdoGetTargetId(Pdo), Pdo->DeviceObject); - IoRequestDeviceEject(Pdo->DeviceObject); - } else { - Verbose("Target[%d] : Triggering BusChangeDetected to detect device\n", PdoGetTargetId(Pdo)); - StorPortNotification(BusChangeDetected, PdoGetAdapter(Pdo), 0); - } -} - -__checkReturn -NTSTATUS -PdoD3ToD0( - __in PXENVBD_PDO Pdo - ) -{ - NTSTATUS Status; - const ULONG TargetId = PdoGetTargetId(Pdo); - - if (!PdoSetDevicePowerState(Pdo, PowerDeviceD0)) - return STATUS_SUCCESS; - - Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); - Verbose("Target[%d] : D3->D0\n", TargetId); - - // power up frontend - Status = FrontendD3ToD0(Pdo->Frontend); - if (!NT_SUCCESS(Status)) - goto fail1; - - // connect frontend - Status = FrontendSetState(Pdo->Frontend, XENVBD_ENABLED); - if (!NT_SUCCESS(Status)) - goto fail2; - __PdoUnpauseDataPath(Pdo); - - Trace("Target[%d] @ (%d) <=====\n", TargetId, KeGetCurrentIrql()); - return STATUS_SUCCESS; - -fail2: - Error("Fail2\n"); - FrontendD0ToD3(Pdo->Frontend); - -fail1: - Error("Fail1 (%08x)\n", Status); - - Pdo->DevicePowerState = PowerDeviceD3; - - return Status; -} - -VOID -PdoD0ToD3( - __in PXENVBD_PDO Pdo - ) -{ - const ULONG TargetId = PdoGetTargetId(Pdo); - - if (!PdoSetDevicePowerState(Pdo, PowerDeviceD3)) - return; - - Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); - Verbose("Target[%d] : D0->D3\n", TargetId); - - // close frontend - __PdoPauseDataPath(Pdo, FALSE); - (VOID) FrontendSetState(Pdo->Frontend, XENVBD_CLOSED); - ASSERT3U(QueueCount(&Pdo->SubmittedReqs), ==, 0); - - // power down frontend - FrontendD0ToD3(Pdo->Frontend); - - Trace("Target[%d] @ (%d) <=====\n", TargetId, KeGetCurrentIrql()); -} - -__checkReturn -BOOLEAN -PdoCreate( - __in PXENVBD_ADAPTER Adapter, - __in __nullterminated PCHAR DeviceId, - __in ULONG TargetId, - __in XENVBD_DEVICE_TYPE DeviceType - ) -{ - NTSTATUS Status; - PXENVBD_PDO Pdo; - - Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); - - Status = STATUS_INSUFFICIENT_RESOURCES; -#pragma warning(suppress: 6014) - Pdo = __PdoAlloc(sizeof(XENVBD_PDO)); - if (!Pdo) - goto fail1; - - Verbose("Target[%d] : Creating\n", TargetId); - Pdo->Signature = PDO_SIGNATURE; - Pdo->Adapter = Adapter; - Pdo->DeviceObject = NULL; // filled in later - KeInitializeEvent(&Pdo->RemoveEvent, SynchronizationEvent, FALSE); - Pdo->ReferenceCount = 1; - Pdo->Paused = 1; // Paused until D3->D0 transition - Pdo->DevicePnpState = Present; - Pdo->DevicePowerState = PowerDeviceD3; - Pdo->DeviceType = DeviceType; - - KeInitializeSpinLock(&Pdo->Lock); - QueueInit(&Pdo->FreshSrbs); - QueueInit(&Pdo->PreparedReqs); - QueueInit(&Pdo->SubmittedReqs); - QueueInit(&Pdo->ShutdownSrbs); - __LookasideInit(&Pdo->RequestList, sizeof(XENVBD_REQUEST), REQUEST_POOL_TAG); - __LookasideInit(&Pdo->SegmentList, sizeof(XENVBD_SEGMENT), SEGMENT_POOL_TAG); - __LookasideInit(&Pdo->IndirectList, sizeof(XENVBD_INDIRECT), INDIRECT_POOL_TAG); - - Status = FrontendCreate(Pdo, DeviceId, TargetId, &Pdo->Frontend); - if (!NT_SUCCESS(Status)) - goto fail2; - - Status = PdoD3ToD0(Pdo); - if (!NT_SUCCESS(Status)) - goto fail3; - - if (!AdapterLinkPdo(Adapter, Pdo)) - goto fail4; - - Verbose("Target[%d] : Created (%s)\n", TargetId, Pdo); - Trace("Target[%d] @ (%d) <=====\n", TargetId, KeGetCurrentIrql()); - return TRUE; - -fail4: - Error("Fail4\n"); - PdoD0ToD3(Pdo); - -fail3: - Error("Fail3\n"); - FrontendDestroy(Pdo->Frontend); - Pdo->Frontend = NULL; - -fail2: - Error("Fail2\n"); - __LookasideTerm(&Pdo->IndirectList); - __LookasideTerm(&Pdo->SegmentList); - __LookasideTerm(&Pdo->RequestList); - __PdoFree(Pdo); - -fail1: - Error("Fail1 (%08x)\n", Status); - return FALSE; -} - -VOID -PdoDestroy( - __in PXENVBD_PDO Pdo - ) -{ - const ULONG TargetId = PdoGetTargetId(Pdo); - PVOID Objects[4]; - PKWAIT_BLOCK WaitBlock; - - Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); - Verbose("Target[%d] : Destroying\n", TargetId); - - ASSERT3U(Pdo->Signature, ==, PDO_SIGNATURE); - if (!AdapterUnlinkPdo(PdoGetAdapter(Pdo), Pdo)) { - Error("Target[%d] : PDO 0x%p not linked to ADAPTER 0x%p\n", TargetId, Pdo, PdoGetAdapter(Pdo)); - } - - PdoD0ToD3(Pdo); - PdoDereference(Pdo); // drop initial ref count - - // Wait for ReferenceCount == 0 and RequestListUsed == 0 - Verbose("Target[%d] : ReferenceCount %d, RequestListUsed %d\n", TargetId, Pdo->ReferenceCount, Pdo->RequestList.Used); - Objects[0] = &Pdo->RemoveEvent; - Objects[1] = &Pdo->RequestList.Empty; - Objects[2] = &Pdo->SegmentList.Empty; - Objects[3] = &Pdo->IndirectList.Empty; - - WaitBlock = (PKWAIT_BLOCK)__PdoAlloc(sizeof(KWAIT_BLOCK) * ARRAYSIZE(Objects)); - if (WaitBlock == NULL) { - ULONG Index; - - Error("Unable to allocate resources for KWAIT_BLOCK\n"); - - for (Index = 0; Index < ARRAYSIZE(Objects); Index++) - KeWaitForSingleObject(Objects[Index], - Executive, - KernelMode, - FALSE, - NULL); - } else { - KeWaitForMultipleObjects(ARRAYSIZE(Objects), - Objects, - WaitAll, - Executive, - KernelMode, - FALSE, - NULL, - WaitBlock); -#pragma prefast(suppress:6102) - __PdoFree(WaitBlock); - } - - ASSERT3S(Pdo->ReferenceCount, ==, 0); - ASSERT3U(PdoGetDevicePnpState(Pdo), ==, Deleted); - - FrontendDestroy(Pdo->Frontend); - Pdo->Frontend = NULL; - - __LookasideTerm(&Pdo->IndirectList); - __LookasideTerm(&Pdo->SegmentList); - __LookasideTerm(&Pdo->RequestList); - - ASSERT3U(Pdo->Signature, ==, PDO_SIGNATURE); - RtlZeroMemory(Pdo, sizeof(XENVBD_PDO)); - __PdoFree(Pdo); - - Verbose("Target[%d] : Destroyed\n", TargetId); - Trace("Target[%d] @ (%d) <=====\n", TargetId, KeGetCurrentIrql()); -} diff --git a/src/xenvbd/pdo.h b/src/xenvbd/pdo.h deleted file mode 100644 index 6003fee..0000000 --- a/src/xenvbd/pdo.h +++ /dev/null @@ -1,229 +0,0 @@ -/* Copyright (c) Citrix Systems Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, - * with or without modification, are permitted provided - * that the following conditions are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _XENVBD_PDO_H -#define _XENVBD_PDO_H - -typedef struct _XENVBD_PDO XENVBD_PDO, *PXENVBD_PDO; - -#include -#include -#include -#include "adapter.h" -#include "srbext.h" -#include "types.h" -#include - -extern VOID -PdoDebugCallback( - __in PXENVBD_PDO Pdo, - __in PXENBUS_DEBUG_INTERFACE Debug - ); - -// Creation/Deletion -__checkReturn -extern BOOLEAN -PdoCreate( - __in PXENVBD_ADAPTER Adapter, - __in __nullterminated PCHAR DeviceId, - __in ULONG TargetId, - __in XENVBD_DEVICE_TYPE DeviceType - ); - -extern VOID -PdoDestroy( - __in PXENVBD_PDO Pdo - ); - -__checkReturn -extern NTSTATUS -PdoD3ToD0( - __in PXENVBD_PDO Pdo - ); - -extern VOID -PdoD0ToD3( - __in PXENVBD_PDO Pdo - ); - -// PnP States -extern VOID -PdoSetMissing( - __in PXENVBD_PDO Pdo, - __in __nullterminated const CHAR* Reason - ); - -__checkReturn -extern BOOLEAN -PdoIsMissing( - __in PXENVBD_PDO Pdo - ); - -extern const CHAR* -PdoMissingReason( - __in PXENVBD_PDO Pdo - ); - -__checkReturn -extern BOOLEAN -PdoIsEmulatedUnplugged( - __in PXENVBD_PDO Pdo - ); - -extern VOID -PdoSetDevicePnpState( - __in PXENVBD_PDO Pdo, - __in DEVICE_PNP_STATE State - ); - -__checkReturn -extern DEVICE_PNP_STATE -PdoGetDevicePnpState( - __in PXENVBD_PDO Pdo - ); - -// Reference Counting -extern LONG -__PdoReference( - __in PXENVBD_PDO Pdo, - __in PCHAR Caller - ); - -#define PdoReference(_x_) __PdoReference(_x_, __FUNCTION__) - -extern LONG -__PdoDereference( - __in PXENVBD_PDO Pdo, - __in PCHAR Caller - ); - -#define PdoDereference(_x_) __PdoDereference(_x_, __FUNCTION__) - -// Query Methods -extern ULONG -PdoGetTargetId( - __in PXENVBD_PDO Pdo - ); - -__checkReturn -extern PDEVICE_OBJECT -PdoGetDeviceObject( - __in PXENVBD_PDO Pdo - ); - -extern VOID -PdoSetDeviceObject( - __in PXENVBD_PDO Pdo, - __in PDEVICE_OBJECT DeviceObject - ); - -__checkReturn -extern BOOLEAN -PdoIsPaused( - __in PXENVBD_PDO Pdo - ); - -__checkReturn -extern ULONG -PdoOutstandingReqs( - __in PXENVBD_PDO Pdo - ); - -__checkReturn -extern PXENVBD_ADAPTER -PdoGetAdapter( - __in PXENVBD_PDO Pdo - ); - -extern ULONG -PdoSectorSize( - __in PXENVBD_PDO Pdo - ); - -// Queue-Related -extern VOID -PdoSubmitRequests( - __in PXENVBD_PDO Pdo - ); - -extern VOID -PdoCompleteResponse( - __in PXENVBD_PDO Pdo, - __in ULONG Tag, - __in SHORT Status - ); - -extern VOID -PdoPreResume( - __in PXENVBD_PDO Pdo - ); - -extern VOID -PdoPostResume( - __in PXENVBD_PDO Pdo - ); - -// StorPort Methods -extern VOID -PdoReset( - __in PXENVBD_PDO Pdo - ); - -__checkReturn -extern BOOLEAN -PdoStartIo( - __in PXENVBD_PDO Pdo, - __in PSCSI_REQUEST_BLOCK Srb - ); - -extern VOID -PdoSrbPnp( - __in PXENVBD_PDO Pdo, - __in PSCSI_PNP_REQUEST_BLOCK Srb - ); - -// PnP Handler -__checkReturn -extern NTSTATUS -PdoDispatchPnp( - __in PXENVBD_PDO Pdo, - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp - ); - -__drv_maxIRQL(DISPATCH_LEVEL) -extern VOID -PdoIssueDeviceEject( - __in PXENVBD_PDO Pdo, - __in __nullterminated const CHAR* Reason - ); - -#endif // _XENVBD_PDO_H diff --git a/src/xenvbd/target.c b/src/xenvbd/target.c new file mode 100644 index 0000000..a504e5a --- /dev/null +++ b/src/xenvbd/target.c @@ -0,0 +1,2732 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "target.h" +#include "driver.h" +#include "adapter.h" +#include "frontend.h" +#include "queue.h" +#include "srbext.h" +#include "buffer.h" +#include "pdoinquiry.h" +#include "debug.h" +#include "assert.h" +#include "util.h" +#include +#include +#include +#include +#include +#include +#include + +typedef struct _XENVBD_SG_LIST { + // SGList from SRB + PSTOR_SCATTER_GATHER_LIST SGList; + // "current" values + STOR_PHYSICAL_ADDRESS PhysAddr; + ULONG PhysLen; + // iteration + ULONG Index; + ULONG Offset; + ULONG Length; +} XENVBD_SG_LIST, *PXENVBD_SG_LIST; + +#define TARGET_SIGNATURE 'odpX' + +typedef struct _XENVBD_LOOKASIDE { + KEVENT Empty; + LONG Used; + LONG Max; + ULONG Failed; + ULONG Size; + NPAGED_LOOKASIDE_LIST List; +} XENVBD_LOOKASIDE, *PXENVBD_LOOKASIDE; + +struct _XENVBD_TARGET { + ULONG Signature; + PXENVBD_ADAPTER Adapter; + PDEVICE_OBJECT DeviceObject; + KEVENT RemoveEvent; + LONG ReferenceCount; + DEVICE_PNP_STATE DevicePnpState; + DEVICE_PNP_STATE PrevPnpState; + DEVICE_POWER_STATE DevicePowerState; + KSPIN_LOCK Lock; + + // Frontend (Ring, includes XenBus interfaces) + PXENVBD_FRONTEND Frontend; + XENVBD_DEVICE_TYPE DeviceType; + + // State + LONG Paused; + + // Eject + BOOLEAN WrittenEjected; + BOOLEAN EjectRequested; + BOOLEAN EjectPending; + BOOLEAN Missing; + const CHAR* Reason; + + // SRBs + XENVBD_LOOKASIDE RequestList; + XENVBD_LOOKASIDE SegmentList; + XENVBD_LOOKASIDE IndirectList; + XENVBD_QUEUE FreshSrbs; + XENVBD_QUEUE PreparedReqs; + XENVBD_QUEUE SubmittedReqs; + XENVBD_QUEUE ShutdownSrbs; + ULONG NextTag; + + // Stats - SRB Counts by BLKIF_OP_ + ULONG BlkOpRead; + ULONG BlkOpWrite; + ULONG BlkOpIndirectRead; + ULONG BlkOpIndirectWrite; + ULONG BlkOpBarrier; + ULONG BlkOpDiscard; + ULONG BlkOpFlush; + // Stats - Failures + ULONG FailedMaps; + ULONG FailedBounces; + ULONG FailedGrants; + // Stats - Segments + ULONG64 SegsGranted; + ULONG64 SegsBounced; +}; + +//============================================================================= +#define TARGET_POOL_TAG 'odPX' +#define REQUEST_POOL_TAG 'qeRX' +#define SEGMENT_POOL_TAG 'geSX' +#define INDIRECT_POOL_TAG 'dnIX' + +__checkReturn +__drv_allocatesMem(mem) +__bcount(Size) +static FORCEINLINE PVOID +#pragma warning(suppress: 28195) +__TargetAlloc( + __in ULONG Size + ) +{ + return __AllocatePoolWithTag(NonPagedPool, Size, TARGET_POOL_TAG); +} + +static FORCEINLINE VOID +#pragma warning(suppress: 28197) +__TargetFree( + __in __drv_freesMem(mem) PVOID Buffer + ) +{ + if (Buffer) + __FreePoolWithTag(Buffer, TARGET_POOL_TAG); +} + +//============================================================================= +// Lookasides +static FORCEINLINE VOID +__LookasideInit( + IN OUT PXENVBD_LOOKASIDE Lookaside, + IN ULONG Size, + IN ULONG Tag + ) +{ + RtlZeroMemory(Lookaside, sizeof(XENVBD_LOOKASIDE)); + Lookaside->Size = Size; + KeInitializeEvent(&Lookaside->Empty, SynchronizationEvent, TRUE); + ExInitializeNPagedLookasideList(&Lookaside->List, NULL, NULL, 0, + Size, Tag, 0); +} + +static FORCEINLINE VOID +__LookasideTerm( + IN PXENVBD_LOOKASIDE Lookaside + ) +{ + ASSERT3U(Lookaside->Used, ==, 0); + ExDeleteNPagedLookasideList(&Lookaside->List); + RtlZeroMemory(Lookaside, sizeof(XENVBD_LOOKASIDE)); +} + +static FORCEINLINE PVOID +__LookasideAlloc( + IN PXENVBD_LOOKASIDE Lookaside + ) +{ + LONG Result; + PVOID Buffer; + + Buffer = ExAllocateFromNPagedLookasideList(&Lookaside->List); + if (Buffer == NULL) { + ++Lookaside->Failed; + return NULL; + } + + RtlZeroMemory(Buffer, Lookaside->Size); + Result = InterlockedIncrement(&Lookaside->Used); + ASSERT3S(Result, >, 0); + if (Result > Lookaside->Max) + Lookaside->Max = Result; + KeClearEvent(&Lookaside->Empty); + + return Buffer; +} + +static FORCEINLINE VOID +__LookasideFree( + IN PXENVBD_LOOKASIDE Lookaside, + IN PVOID Buffer + ) +{ + LONG Result; + + ExFreeToNPagedLookasideList(&Lookaside->List, Buffer); + Result = InterlockedDecrement(&Lookaside->Used); + ASSERT3S(Result, >=, 0); + + if (Result == 0) { + KeSetEvent(&Lookaside->Empty, IO_NO_INCREMENT, FALSE); + } +} + +static FORCEINLINE VOID +__LookasideDebug( + IN PXENVBD_LOOKASIDE Lookaside, + IN PXENBUS_DEBUG_INTERFACE Debug, + IN PCHAR Name + ) +{ + XENBUS_DEBUG(Printf, Debug, + "LOOKASIDE: %s: %u / %u (%u failed)\n", + Name, Lookaside->Used, + Lookaside->Max, Lookaside->Failed); + + Lookaside->Max = Lookaside->Used; + Lookaside->Failed = 0; +} + +//============================================================================= +// Debug +static FORCEINLINE PCHAR +__PnpStateName( + __in DEVICE_PNP_STATE State + ) +{ + switch (State) { + case Invalid: return "Invalid"; + case Present: return "Present"; + case Enumerated: return "Enumerated"; + case Added: return "Added"; + case Started: return "Started"; + case StopPending: return "StopPending"; + case Stopped: return "Stopped"; + case RemovePending: return "RemovePending"; + case SurpriseRemovePending: return "SurpriseRemovePending"; + case Deleted: return "Deleted"; + default: return "UNKNOWN"; + } +} + +DECLSPEC_NOINLINE VOID +TargetDebugCallback( + __in PXENVBD_TARGET Target, + __in PXENBUS_DEBUG_INTERFACE DebugInterface + ) +{ + if (Target == NULL || DebugInterface == NULL) + return; + if (Target->Signature != TARGET_SIGNATURE) + return; + + XENBUS_DEBUG(Printf, DebugInterface, + "TARGET: Adapter 0x%p DeviceObject 0x%p\n", + Target->Adapter, + Target->DeviceObject); + XENBUS_DEBUG(Printf, DebugInterface, + "TARGET: ReferenceCount %d\n", + Target->ReferenceCount); + XENBUS_DEBUG(Printf, DebugInterface, + "TARGET: DevicePnpState %s (%s)\n", + __PnpStateName(Target->DevicePnpState), + __PnpStateName(Target->PrevPnpState)); + XENBUS_DEBUG(Printf, DebugInterface, + "TARGET: DevicePowerState %s\n", + PowerDeviceStateName(Target->DevicePowerState)); + XENBUS_DEBUG(Printf, DebugInterface, + "TARGET: %s\n", + Target->Missing ? Target->Reason : "Not Missing"); + + XENBUS_DEBUG(Printf, DebugInterface, + "TARGET: BLKIF_OPs: READ=%u WRITE=%u\n", + Target->BlkOpRead, Target->BlkOpWrite); + XENBUS_DEBUG(Printf, DebugInterface, + "TARGET: BLKIF_OPs: INDIRECT_READ=%u INDIRECT_WRITE=%u\n", + Target->BlkOpIndirectRead, Target->BlkOpIndirectWrite); + XENBUS_DEBUG(Printf, DebugInterface, + "TARGET: BLKIF_OPs: BARRIER=%u DISCARD=%u FLUSH=%u\n", + Target->BlkOpBarrier, Target->BlkOpDiscard, Target->BlkOpFlush); + XENBUS_DEBUG(Printf, DebugInterface, + "TARGET: Failed: Maps=%u Bounces=%u Grants=%u\n", + Target->FailedMaps, Target->FailedBounces, Target->FailedGrants); + XENBUS_DEBUG(Printf, DebugInterface, + "TARGET: Segments Granted=%llu Bounced=%llu\n", + Target->SegsGranted, Target->SegsBounced); + + __LookasideDebug(&Target->RequestList, DebugInterface, "REQUESTs"); + __LookasideDebug(&Target->SegmentList, DebugInterface, "SEGMENTs"); + __LookasideDebug(&Target->IndirectList, DebugInterface, "INDIRECTs"); + + QueueDebugCallback(&Target->FreshSrbs, "Fresh ", DebugInterface); + QueueDebugCallback(&Target->PreparedReqs, "Prepared ", DebugInterface); + QueueDebugCallback(&Target->SubmittedReqs, "Submitted", DebugInterface); + QueueDebugCallback(&Target->ShutdownSrbs, "Shutdown ", DebugInterface); + + FrontendDebugCallback(Target->Frontend, DebugInterface); + + Target->BlkOpRead = Target->BlkOpWrite = 0; + Target->BlkOpIndirectRead = Target->BlkOpIndirectWrite = 0; + Target->BlkOpBarrier = Target->BlkOpDiscard = Target->BlkOpFlush = 0; + Target->FailedMaps = Target->FailedBounces = Target->FailedGrants = 0; + Target->SegsGranted = Target->SegsBounced = 0; +} + +//============================================================================= +// Power States +__checkReturn +static FORCEINLINE BOOLEAN +TargetSetDevicePowerState( + __in PXENVBD_TARGET Target, + __in DEVICE_POWER_STATE State + ) +{ + KIRQL Irql; + BOOLEAN Changed = FALSE; + + KeAcquireSpinLock(&Target->Lock, &Irql); + if (Target->DevicePowerState != State) { + Verbose("Target[%d] : POWER %s to %s\n", TargetGetTargetId(Target), PowerDeviceStateName(Target->DevicePowerState), PowerDeviceStateName(State)); + Target->DevicePowerState = State; + Changed = TRUE; + } + KeReleaseSpinLock(&Target->Lock, Irql); + + return Changed; +} + +//============================================================================= +// PnP States +FORCEINLINE VOID +TargetSetMissing( + __in PXENVBD_TARGET Target, + __in __nullterminated const CHAR* Reason + ) +{ + KIRQL Irql; + + ASSERT3P(Reason, !=, NULL); + + KeAcquireSpinLock(&Target->Lock, &Irql); + if (Target->Missing) { + Verbose("Target[%d] : Already MISSING (%s) when trying to set (%s)\n", TargetGetTargetId(Target), Target->Reason, Reason); + } else { + Verbose("Target[%d] : MISSING %s\n", TargetGetTargetId(Target), Reason); + Target->Missing = TRUE; + Target->Reason = Reason; + } + KeReleaseSpinLock(&Target->Lock, Irql); +} + +__checkReturn +FORCEINLINE BOOLEAN +TargetIsMissing( + __in PXENVBD_TARGET Target + ) +{ + KIRQL Irql; + BOOLEAN Missing; + + KeAcquireSpinLock(&Target->Lock, &Irql); + Missing = Target->Missing; + KeReleaseSpinLock(&Target->Lock, Irql); + + return Missing; +} + +FORCEINLINE const CHAR* +TargetMissingReason( + __in PXENVBD_TARGET Target + ) +{ + KIRQL Irql; + const CHAR* Reason; + + KeAcquireSpinLock(&Target->Lock, &Irql); + Reason = Target->Reason; + KeReleaseSpinLock(&Target->Lock, Irql); + + return Reason; +} + +FORCEINLINE VOID +TargetSetDevicePnpState( + __in PXENVBD_TARGET Target, + __in DEVICE_PNP_STATE State + ) +{ + Verbose("Target[%d] : PNP %s to %s\n", + TargetGetTargetId(Target), + __PnpStateName(Target->DevicePnpState), + __PnpStateName(State)); + + if (Target->DevicePnpState == Deleted) + return; + + Target->PrevPnpState = Target->DevicePnpState; + Target->DevicePnpState = State; +} + +__checkReturn +FORCEINLINE DEVICE_PNP_STATE +TargetGetDevicePnpState( + __in PXENVBD_TARGET Target + ) +{ + return Target->DevicePnpState; +} + +static FORCEINLINE VOID +__TargetRestoreDevicePnpState( + __in PXENVBD_TARGET Target, + __in DEVICE_PNP_STATE State + ) +{ + if (Target->DevicePnpState == State) { + Verbose("Target[%d] : PNP %s to %s\n", TargetGetTargetId(Target), __PnpStateName(Target->DevicePnpState), __PnpStateName(Target->PrevPnpState)); + Target->DevicePnpState = Target->PrevPnpState; + } +} + +//============================================================================= +// Reference Counting +FORCEINLINE LONG +__TargetReference( + __in PXENVBD_TARGET Target, + __in PCHAR Caller + ) +{ + LONG Result; + + ASSERT3P(Target, !=, NULL); + Result = InterlockedIncrement(&Target->ReferenceCount); + ASSERTREFCOUNT(Result, >, 0, Caller); + + if (Result == 1) { + Result = InterlockedDecrement(&Target->ReferenceCount); + Error("Target[%d] : %s: Attempting to take reference of removed TARGET from %d\n", TargetGetTargetId(Target), Caller, Result); + return 0; + } else { + ASSERTREFCOUNT(Result, >, 1, Caller); + return Result; + } +} + +FORCEINLINE LONG +__TargetDereference( + __in PXENVBD_TARGET Target, + __in PCHAR Caller + ) +{ + LONG Result; + + ASSERT3P(Target, !=, NULL); + Result = InterlockedDecrement(&Target->ReferenceCount); + ASSERTREFCOUNT(Result, >=, 0, Caller); + + if (Result == 0) { + Verbose("Final ReferenceCount dropped, Target[%d] able to be removed\n", TargetGetTargetId(Target)); + KeSetEvent(&Target->RemoveEvent, IO_NO_INCREMENT, FALSE); + } + return Result; +} + +//============================================================================= +// Query Methods +FORCEINLINE ULONG +TargetGetTargetId( + __in PXENVBD_TARGET Target + ) +{ + ASSERT3P(Target, !=, NULL); + return FrontendGetTargetId(Target->Frontend); +} + +__checkReturn +FORCEINLINE PDEVICE_OBJECT +TargetGetDeviceObject( + __in PXENVBD_TARGET Target + ) +{ + ASSERT3P(Target, !=, NULL); + return Target->DeviceObject; +} + +FORCEINLINE VOID +TargetSetDeviceObject( + __in PXENVBD_TARGET Target, + __in PDEVICE_OBJECT DeviceObject + ) +{ + Verbose("Target[%d] : Setting DeviceObject = 0x%p\n", TargetGetTargetId(Target), DeviceObject); + + ASSERT3P(Target->DeviceObject, ==, NULL); + Target->DeviceObject = DeviceObject; +} + +__checkReturn +FORCEINLINE BOOLEAN +TargetIsPaused( + __in PXENVBD_TARGET Target + ) +{ + BOOLEAN Paused; + KIRQL Irql; + + KeAcquireSpinLock(&Target->Lock, &Irql); + Paused = (Target->Paused > 0); + KeReleaseSpinLock(&Target->Lock, Irql); + + return Paused; +} + +__checkReturn +FORCEINLINE ULONG +TargetOutstandingReqs( + __in PXENVBD_TARGET Target + ) +{ + return QueueCount(&Target->SubmittedReqs); +} + +__checkReturn +FORCEINLINE PXENVBD_ADAPTER +TargetGetAdapter( + __in PXENVBD_TARGET Target + ) +{ + return Target->Adapter; +} + +FORCEINLINE ULONG +TargetSectorSize( + __in PXENVBD_TARGET Target + ) +{ + return FrontendGetDiskInfo(Target->Frontend)->SectorSize; +} + +//============================================================================= +static PXENVBD_INDIRECT +TargetGetIndirect( + IN PXENVBD_TARGET Target + ) +{ + PXENVBD_INDIRECT Indirect; + NTSTATUS status; + PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); + + Indirect = __LookasideAlloc(&Target->IndirectList); + if (Indirect == NULL) + goto fail1; + + RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); + + Indirect->Mdl = __AllocatePage(); + if (Indirect->Mdl == NULL) + goto fail2; + + Indirect->Page = MmGetSystemAddressForMdlSafe(Indirect->Mdl, + NormalPagePriority); + + status = GranterGet(Granter, + MmGetMdlPfnArray(Indirect->Mdl)[0], + TRUE, + &Indirect->Grant); + if (!NT_SUCCESS(status)) + goto fail3; + + return Indirect; + +fail3: + __FreePage(Indirect->Mdl); +fail2: + __LookasideFree(&Target->IndirectList, Indirect); +fail1: + return NULL; +} + +static VOID +TargetPutIndirect( + IN PXENVBD_TARGET Target, + IN PXENVBD_INDIRECT Indirect + ) +{ + PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); + + if (Indirect->Grant) + GranterPut(Granter, Indirect->Grant); + if (Indirect->Page) + __FreePage(Indirect->Mdl); + + RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); + __LookasideFree(&Target->IndirectList, Indirect); +} + +static PXENVBD_SEGMENT +TargetGetSegment( + IN PXENVBD_TARGET Target + ) +{ + PXENVBD_SEGMENT Segment; + + Segment = __LookasideAlloc(&Target->SegmentList); + if (Segment == NULL) + goto fail1; + + RtlZeroMemory(Segment, sizeof(XENVBD_SEGMENT)); + return Segment; + +fail1: + return NULL; +} + +static VOID +TargetPutSegment( + IN PXENVBD_TARGET Target, + IN PXENVBD_SEGMENT Segment + ) +{ + PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); + + if (Segment->Grant) + GranterPut(Granter, Segment->Grant); + + if (Segment->BufferId) + BufferPut(Segment->BufferId); + + if (Segment->Buffer) + MmUnmapLockedPages(Segment->Buffer, &Segment->Mdl); + + RtlZeroMemory(Segment, sizeof(XENVBD_SEGMENT)); + __LookasideFree(&Target->SegmentList, Segment); +} + +static PXENVBD_REQUEST +TargetGetRequest( + IN PXENVBD_TARGET Target + ) +{ + PXENVBD_REQUEST Request; + + Request = __LookasideAlloc(&Target->RequestList); + if (Request == NULL) + goto fail1; + + RtlZeroMemory(Request, sizeof(XENVBD_REQUEST)); + Request->Id = (ULONG)InterlockedIncrement((PLONG)&Target->NextTag); + InitializeListHead(&Request->Segments); + InitializeListHead(&Request->Indirects); + + return Request; + +fail1: + return NULL; +} + +static VOID +TargetPutRequest( + IN PXENVBD_TARGET Target, + IN PXENVBD_REQUEST Request + ) +{ + PLIST_ENTRY Entry; + + for (;;) { + PXENVBD_SEGMENT Segment; + + Entry = RemoveHeadList(&Request->Segments); + if (Entry == &Request->Segments) + break; + Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); + TargetPutSegment(Target, Segment); + } + + for (;;) { + PXENVBD_INDIRECT Indirect; + + Entry = RemoveHeadList(&Request->Indirects); + if (Entry == &Request->Indirects) + break; + Indirect = CONTAINING_RECORD(Entry, XENVBD_INDIRECT, Entry); + TargetPutIndirect(Target, Indirect); + } + + RtlZeroMemory(Request, sizeof(XENVBD_REQUEST)); + __LookasideFree(&Target->RequestList, Request); +} + +static FORCEINLINE PXENVBD_REQUEST +TargetRequestFromTag( + IN PXENVBD_TARGET Target, + IN ULONG Tag + ) +{ + KIRQL Irql; + PLIST_ENTRY Entry; + PXENVBD_QUEUE Queue = &Target->SubmittedReqs; + + KeAcquireSpinLock(&Queue->Lock, &Irql); + + for (Entry = Queue->List.Flink; Entry != &Queue->List; Entry = Entry->Flink) { + PXENVBD_REQUEST Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + if (Request->Id == Tag) { + RemoveEntryList(&Request->Entry); + --Queue->Current; + KeReleaseSpinLock(&Queue->Lock, Irql); + return Request; + } + } + + KeReleaseSpinLock(&Queue->Lock, Irql); + Warning("Target[%d] : Tag %x not found in submitted list (%u items)\n", + TargetGetTargetId(Target), Tag, QueueCount(Queue)); + return NULL; +} + +static FORCEINLINE VOID +__TargetIncBlkifOpCount( + __in PXENVBD_TARGET Target, + __in PXENVBD_REQUEST Request + ) +{ + switch (Request->Operation) { + case BLKIF_OP_READ: + if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) + ++Target->BlkOpIndirectRead; + else + ++Target->BlkOpRead; + break; + case BLKIF_OP_WRITE: + if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) + ++Target->BlkOpIndirectWrite; + else + ++Target->BlkOpWrite; + break; + case BLKIF_OP_WRITE_BARRIER: + ++Target->BlkOpBarrier; + break; + case BLKIF_OP_DISCARD: + ++Target->BlkOpDiscard; + break; + case BLKIF_OP_FLUSH_DISKCACHE: + ++Target->BlkOpFlush; + break; + default: + ASSERT(FALSE); + break; + } +} + +static FORCEINLINE ULONG +__SectorsPerPage( + __in ULONG SectorSize + ) +{ + ASSERT3U(SectorSize, !=, 0); + return PAGE_SIZE / SectorSize; +} + +static FORCEINLINE VOID +__Operation( + __in UCHAR CdbOp, + __out PUCHAR RingOp, + __out PBOOLEAN ReadOnly + ) +{ + switch (CdbOp) { + case SCSIOP_READ: + *RingOp = BLKIF_OP_READ; + *ReadOnly = FALSE; + break; + case SCSIOP_WRITE: + *RingOp = BLKIF_OP_WRITE; + *ReadOnly = TRUE; + break; + default: + ASSERT(FALSE); + } +} + +static FORCEINLINE ULONG +__Offset( + __in STOR_PHYSICAL_ADDRESS PhysAddr + ) +{ + return (ULONG)(PhysAddr.QuadPart & (PAGE_SIZE - 1)); +} + +static FORCEINLINE PFN_NUMBER +__Phys2Pfn( + __in STOR_PHYSICAL_ADDRESS PhysAddr + ) +{ + return (PFN_NUMBER)(PhysAddr.QuadPart >> PAGE_SHIFT); +} + +static FORCEINLINE PFN_NUMBER +__Virt2Pfn( + __in PVOID VirtAddr + ) +{ + return (PFN_NUMBER)(MmGetPhysicalAddress(VirtAddr).QuadPart >> PAGE_SHIFT); +} + +static FORCEINLINE MM_PAGE_PRIORITY +__TargetPriority( + __in PXENVBD_TARGET Target + ) +{ + PXENVBD_CAPS Caps = FrontendGetCaps(Target->Frontend); + if (!(Caps->Paging || + Caps->Hibernation || + Caps->DumpFile)) + return NormalPagePriority; + + return HighPagePriority; +} + +#define __min(_x, _y) ((_x) < (_y)) ? (_x) : (_y) + +static FORCEINLINE VOID +SGListGet( + IN OUT PXENVBD_SG_LIST SGList + ) +{ + PSTOR_SCATTER_GATHER_ELEMENT SGElement; + + ASSERT3U(SGList->Index, <, SGList->SGList->NumberOfElements); + + SGElement = &SGList->SGList->List[SGList->Index]; + + SGList->PhysAddr.QuadPart = SGElement->PhysicalAddress.QuadPart + SGList->Offset; + SGList->PhysLen = __min(PAGE_SIZE - __Offset(SGList->PhysAddr) - SGList->Length, SGElement->Length - SGList->Offset); + + ASSERT3U(SGList->PhysLen, <=, PAGE_SIZE); + ASSERT3U(SGList->Offset, <, SGElement->Length); + + SGList->Length = SGList->PhysLen; // gets reset every time for Granted, every 1or2 times for Bounced + SGList->Offset = SGList->Offset + SGList->PhysLen; + if (SGList->Offset >= SGElement->Length) { + SGList->Index = SGList->Index + 1; + SGList->Offset = 0; + } +} + +static FORCEINLINE BOOLEAN +SGListNext( + IN OUT PXENVBD_SG_LIST SGList, + IN ULONG AlignmentMask + ) +{ + SGList->Length = 0; + SGListGet(SGList); // get next PhysAddr and PhysLen + return !((SGList->PhysAddr.QuadPart & AlignmentMask) || (SGList->PhysLen & AlignmentMask)); +} + +static FORCEINLINE BOOLEAN +MapSegmentBuffer( + IN PXENVBD_TARGET Target, + IN PXENVBD_SEGMENT Segment, + IN PXENVBD_SG_LIST SGList, + IN ULONG SectorSize, + IN ULONG SectorsNow + ) +{ + PMDL Mdl; + + // map PhysAddr to 1 or 2 pages and lock for VirtAddr +#pragma warning(push) +#pragma warning(disable:28145) + Mdl = &Segment->Mdl; + Mdl->Next = NULL; + Mdl->Size = (SHORT)(sizeof(MDL) + sizeof(PFN_NUMBER)); + Mdl->MdlFlags = MDL_PAGES_LOCKED; + Mdl->Process = NULL; + Mdl->MappedSystemVa = NULL; + Mdl->StartVa = NULL; + Mdl->ByteCount = SGList->PhysLen; + Mdl->ByteOffset = __Offset(SGList->PhysAddr); + Segment->Pfn[0] = __Phys2Pfn(SGList->PhysAddr); + + if (SGList->PhysLen < SectorsNow * SectorSize) { + SGListGet(SGList); + Mdl->Size += sizeof(PFN_NUMBER); + Mdl->ByteCount = Mdl->ByteCount + SGList->PhysLen; + Segment->Pfn[1] = __Phys2Pfn(SGList->PhysAddr); + } +#pragma warning(pop) + + ASSERT((Mdl->ByteCount & (SectorSize - 1)) == 0); + ASSERT3U(Mdl->ByteCount, <=, PAGE_SIZE); + ASSERT3U(SectorsNow, ==, (Mdl->ByteCount / SectorSize)); + + Segment->Length = __min(Mdl->ByteCount, PAGE_SIZE); + Segment->Buffer = MmMapLockedPagesSpecifyCache(Mdl, KernelMode, + MmCached, NULL, FALSE, __TargetPriority(Target)); + if (!Segment->Buffer) { + goto fail; + } + + ASSERT3P(MmGetMdlPfnArray(Mdl)[0], ==, Segment->Pfn[0]); + ASSERT3P(MmGetMdlPfnArray(Mdl)[1], ==, Segment->Pfn[1]); + + return TRUE; + +fail: + return FALSE; +} + +static FORCEINLINE VOID +RequestCopyOutput( + __in PXENVBD_REQUEST Request + ) +{ + PLIST_ENTRY Entry; + + if (Request->Operation != BLKIF_OP_READ) + return; + + for (Entry = Request->Segments.Flink; + Entry != &Request->Segments; + Entry = Entry->Flink) { + PXENVBD_SEGMENT Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); + + if (Segment->BufferId) + BufferCopyOut(Segment->BufferId, Segment->Buffer, Segment->Length); + } +} + +static BOOLEAN +PrepareSegment( + IN PXENVBD_TARGET Target, + IN PXENVBD_SEGMENT Segment, + IN PXENVBD_SG_LIST SGList, + IN BOOLEAN ReadOnly, + IN ULONG SectorsLeft, + OUT PULONG SectorsNow + ) +{ + PFN_NUMBER Pfn; + NTSTATUS Status; + PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); + const ULONG SectorSize = TargetSectorSize(Target); + const ULONG SectorsPerPage = __SectorsPerPage(SectorSize); + + if (SGListNext(SGList, SectorSize - 1)) { + ++Target->SegsGranted; + // get first sector, last sector and count + Segment->FirstSector = (UCHAR)((__Offset(SGList->PhysAddr) + SectorSize - 1) / SectorSize); + *SectorsNow = __min(SectorsLeft, SectorsPerPage - Segment->FirstSector); + Segment->LastSector = (UCHAR)(Segment->FirstSector + *SectorsNow - 1); + Segment->BufferId = NULL; // granted, ensure its null + Segment->Buffer = NULL; // granted, ensure its null + Segment->Length = 0; // granted, ensure its 0 + Pfn = __Phys2Pfn(SGList->PhysAddr); + + ASSERT3U((SGList->PhysLen / SectorSize), ==, *SectorsNow); + ASSERT3U((SGList->PhysLen & (SectorSize - 1)), ==, 0); + } else { + ++Target->SegsBounced; + // get first sector, last sector and count + Segment->FirstSector = 0; + *SectorsNow = __min(SectorsLeft, SectorsPerPage); + Segment->LastSector = (UCHAR)(*SectorsNow - 1); + + // map SGList to Virtual Address. Populates Segment->Buffer and Segment->Length + if (!MapSegmentBuffer(Target, Segment, SGList, SectorSize, *SectorsNow)) { + ++Target->FailedMaps; + goto fail1; + } + + // get a buffer + if (!BufferGet(Segment, &Segment->BufferId, &Pfn)) { + ++Target->FailedBounces; + goto fail2; + } + + // copy contents in + if (ReadOnly) { // Operation == BLKIF_OP_WRITE + BufferCopyIn(Segment->BufferId, Segment->Buffer, Segment->Length); + } + } + + // Grant segment's page + Status = GranterGet(Granter, Pfn, ReadOnly, &Segment->Grant); + if (!NT_SUCCESS(Status)) { + ++Target->FailedGrants; + goto fail3; + } + + return TRUE; + +fail3: +fail2: +fail1: + return FALSE; +} + +static BOOLEAN +PrepareBlkifReadWrite( + IN PXENVBD_TARGET Target, + IN PXENVBD_REQUEST Request, + IN PXENVBD_SG_LIST SGList, + IN ULONG MaxSegments, + IN ULONG64 SectorStart, + IN ULONG SectorsLeft, + OUT PULONG SectorsDone + ) +{ + UCHAR Operation; + BOOLEAN ReadOnly; + ULONG Index; + __Operation(Cdb_OperationEx(Request->Srb), &Operation, &ReadOnly); + + Request->Operation = Operation; + Request->NrSegments = 0; + Request->FirstSector = SectorStart; + + for (Index = 0; + Index < MaxSegments && + SectorsLeft > 0; + ++Index) { + PXENVBD_SEGMENT Segment; + ULONG SectorsNow; + + Segment = TargetGetSegment(Target); + if (Segment == NULL) + goto fail1; + + InsertTailList(&Request->Segments, &Segment->Entry); + ++Request->NrSegments; + + if (!PrepareSegment(Target, + Segment, + SGList, + ReadOnly, + SectorsLeft, + &SectorsNow)) + goto fail2; + + *SectorsDone += SectorsNow; + SectorsLeft -= SectorsNow; + } + ASSERT3U(Request->NrSegments, >, 0); + ASSERT3U(Request->NrSegments, <=, MaxSegments); + + return TRUE; + +fail2: +fail1: + return FALSE; +} + +static BOOLEAN +PrepareBlkifIndirect( + IN PXENVBD_TARGET Target, + IN PXENVBD_REQUEST Request + ) +{ + ULONG Index; + ULONG NrSegments = 0; + + for (Index = 0; + Index < BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST && + NrSegments < Request->NrSegments; + ++Index) { + PXENVBD_INDIRECT Indirect; + + Indirect = TargetGetIndirect(Target); + if (Indirect == NULL) + goto fail1; + InsertTailList(&Request->Indirects, &Indirect->Entry); + + NrSegments += XENVBD_MAX_SEGMENTS_PER_PAGE; + } + + return TRUE; + +fail1: + return FALSE; +} + +static FORCEINLINE ULONG +UseIndirect( + IN PXENVBD_TARGET Target, + IN ULONG SectorsLeft + ) +{ + const ULONG SectorsPerPage = __SectorsPerPage(TargetSectorSize(Target)); + const ULONG MaxIndirectSegs = FrontendGetFeatures(Target->Frontend)->Indirect; + + if (MaxIndirectSegs <= BLKIF_MAX_SEGMENTS_PER_REQUEST) + return BLKIF_MAX_SEGMENTS_PER_REQUEST; // not supported + + if (SectorsLeft < BLKIF_MAX_SEGMENTS_PER_REQUEST * SectorsPerPage) + return BLKIF_MAX_SEGMENTS_PER_REQUEST; // first into a single BLKIF_OP_{READ/WRITE} + + return MaxIndirectSegs; +} + +static FORCEINLINE ULONG +TargetQueueRequestList( + IN PXENVBD_TARGET Target, + IN PLIST_ENTRY List + ) +{ + ULONG Count = 0; + for (;;) { + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry; + + Entry = RemoveHeadList(List); + if (Entry == List) + break; + + ++Count; + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + __TargetIncBlkifOpCount(Target, Request); + QueueAppend(&Target->PreparedReqs, &Request->Entry); + } + return Count; +} + +static FORCEINLINE VOID +TargetCancelRequestList( + IN PXENVBD_TARGET Target, + IN PLIST_ENTRY List + ) +{ + for (;;) { + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry; + + Entry = RemoveHeadList(List); + if (Entry == List) + break; + + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + TargetPutRequest(Target, Request); + } +} + +__checkReturn +static BOOLEAN +PrepareReadWrite( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); + ULONG64 SectorStart = Cdb_LogicalBlock(Srb); + ULONG SectorsLeft = Cdb_TransferBlock(Srb); + LIST_ENTRY List; + XENVBD_SG_LIST SGList; + ULONG DebugCount; + + Srb->SrbStatus = SRB_STATUS_PENDING; + + InitializeListHead(&List); + SrbExt->Count = 0; + + RtlZeroMemory(&SGList, sizeof(SGList)); + SGList.SGList = StorPortGetScatterGatherList(TargetGetAdapter(Target), Srb); + + while (SectorsLeft > 0) { + ULONG MaxSegments; + ULONG SectorsDone = 0; + PXENVBD_REQUEST Request; + + Request = TargetGetRequest(Target); + if (Request == NULL) + goto fail1; + InsertTailList(&List, &Request->Entry); + InterlockedIncrement(&SrbExt->Count); + + Request->Srb = Srb; + MaxSegments = UseIndirect(Target, SectorsLeft); + + if (!PrepareBlkifReadWrite(Target, + Request, + &SGList, + MaxSegments, + SectorStart, + SectorsLeft, + &SectorsDone)) + goto fail2; + + if (MaxSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { + if (!PrepareBlkifIndirect(Target, Request)) + goto fail3; + } + + SectorsLeft -= SectorsDone; + SectorStart += SectorsDone; + } + + DebugCount = TargetQueueRequestList(Target, &List); + if (DebugCount != (ULONG)SrbExt->Count) { + Trace("[%u] %d != %u\n", TargetGetTargetId(Target), SrbExt->Count, DebugCount); + } + return TRUE; + +fail3: +fail2: +fail1: + TargetCancelRequestList(Target, &List); + SrbExt->Count = 0; + Srb->SrbStatus = SRB_STATUS_ERROR; + return FALSE; +} + +__checkReturn +static BOOLEAN +PrepareSyncCache( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); + PXENVBD_REQUEST Request; + LIST_ENTRY List; + UCHAR Operation; + ULONG DebugCount; + + Srb->SrbStatus = SRB_STATUS_PENDING; + + if (FrontendGetDiskInfo(Target->Frontend)->FlushCache) + Operation = BLKIF_OP_FLUSH_DISKCACHE; + else + Operation = BLKIF_OP_WRITE_BARRIER; + + InitializeListHead(&List); + SrbExt->Count = 0; + + Request = TargetGetRequest(Target); + if (Request == NULL) + goto fail1; + InsertTailList(&List, &Request->Entry); + InterlockedIncrement(&SrbExt->Count); + + Request->Srb = Srb; + Request->Operation = Operation; + Request->FirstSector = Cdb_LogicalBlock(Srb); + + DebugCount = TargetQueueRequestList(Target, &List); + if (DebugCount != (ULONG)SrbExt->Count) { + Trace("[%u] %d != %u\n", TargetGetTargetId(Target), SrbExt->Count, DebugCount); + } + return TRUE; + +fail1: + TargetCancelRequestList(Target, &List); + SrbExt->Count = 0; + Srb->SrbStatus = SRB_STATUS_ERROR; + return FALSE; +} + +__checkReturn +static BOOLEAN +PrepareUnmap( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); + PUNMAP_LIST_HEADER Unmap = Srb->DataBuffer; + ULONG Count = _byteswap_ushort(*(PUSHORT)Unmap->BlockDescrDataLength) / sizeof(UNMAP_BLOCK_DESCRIPTOR); + ULONG Index; + LIST_ENTRY List; + ULONG DebugCount; + + Srb->SrbStatus = SRB_STATUS_PENDING; + + InitializeListHead(&List); + SrbExt->Count = 0; + + for (Index = 0; Index < Count; ++Index) { + PUNMAP_BLOCK_DESCRIPTOR Descr = &Unmap->Descriptors[Index]; + PXENVBD_REQUEST Request; + + Request = TargetGetRequest(Target); + if (Request == NULL) + goto fail1; + InsertTailList(&List, &Request->Entry); + InterlockedIncrement(&SrbExt->Count); + + Request->Srb = Srb; + Request->Operation = BLKIF_OP_DISCARD; + Request->FirstSector = _byteswap_uint64(*(PULONG64)Descr->StartingLba); + Request->NrSectors = _byteswap_ulong(*(PULONG)Descr->LbaCount); + Request->Flags = 0; + } + + DebugCount = TargetQueueRequestList(Target, &List); + if (DebugCount != (ULONG)SrbExt->Count) { + Trace("[%u] %d != %u\n", TargetGetTargetId(Target), SrbExt->Count, DebugCount); + } + return TRUE; + +fail1: + TargetCancelRequestList(Target, &List); + SrbExt->Count = 0; + Srb->SrbStatus = SRB_STATUS_ERROR; + return FALSE; +} + +//============================================================================= +// Queue-Related +static FORCEINLINE VOID +__TargetPauseDataPath( + __in PXENVBD_TARGET Target, + __in BOOLEAN Timeout + ) +{ + KIRQL Irql; + ULONG Requests; + ULONG Count = 0; + PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend); + PXENVBD_BLOCKRING BlockRing = FrontendGetBlockRing(Target->Frontend); + + KeAcquireSpinLock(&Target->Lock, &Irql); + ++Target->Paused; + KeReleaseSpinLock(&Target->Lock, Irql); + + Requests = QueueCount(&Target->SubmittedReqs); + KeMemoryBarrier(); + + Verbose("Target[%d] : Waiting for %d Submitted requests\n", TargetGetTargetId(Target), Requests); + + // poll ring and send event channel notification every 1ms (for up to 3 minutes) + while (QueueCount(&Target->SubmittedReqs)) { + if (Timeout && Count > 180000) + break; + KeRaiseIrql(DISPATCH_LEVEL, &Irql); + BlockRingPoll(BlockRing); + KeLowerIrql(Irql); + NotifierSend(Notifier); // let backend know it needs to do some work + StorPortStallExecution(1000); // 1000 micro-seconds + ++Count; + } + + Verbose("Target[%d] : %u/%u Submitted requests left (%u iterrations)\n", + TargetGetTargetId(Target), QueueCount(&Target->SubmittedReqs), Requests, Count); + + // Abort Fresh SRBs + for (;;) { + PXENVBD_SRBEXT SrbExt; + PLIST_ENTRY Entry = QueuePop(&Target->FreshSrbs); + if (Entry == NULL) + break; + SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); + + Verbose("Target[%d] : FreshSrb 0x%p -> SCSI_ABORTED\n", TargetGetTargetId(Target), SrbExt->Srb); + SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; + SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED; + AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt->Srb); + } + + // Fail PreparedReqs + for (;;) { + PXENVBD_SRBEXT SrbExt; + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry = QueuePop(&Target->PreparedReqs); + if (Entry == NULL) + break; + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + SrbExt = GetSrbExt(Request->Srb); + + Verbose("Target[%d] : PreparedReq 0x%p -> FAILED\n", TargetGetTargetId(Target), Request); + + SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; + TargetPutRequest(Target, Request); + + if (InterlockedDecrement(&SrbExt->Count) == 0) { + SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED + AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt->Srb); + } + } +} + +static FORCEINLINE VOID +__TargetUnpauseDataPath( + __in PXENVBD_TARGET Target + ) +{ + KIRQL Irql; + + KeAcquireSpinLock(&Target->Lock, &Irql); + --Target->Paused; + KeReleaseSpinLock(&Target->Lock, Irql); +} + +static FORCEINLINE BOOLEAN +TargetPrepareFresh( + IN PXENVBD_TARGET Target + ) +{ + PXENVBD_SRBEXT SrbExt; + PLIST_ENTRY Entry; + + Entry = QueuePop(&Target->FreshSrbs); + if (Entry == NULL) + return FALSE; // fresh queue is empty + + SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); + + switch (Cdb_OperationEx(SrbExt->Srb)) { + case SCSIOP_READ: + case SCSIOP_WRITE: + if (PrepareReadWrite(Target, SrbExt->Srb)) + return TRUE; // prepared this SRB + break; + case SCSIOP_SYNCHRONIZE_CACHE: + if (PrepareSyncCache(Target, SrbExt->Srb)) + return TRUE; // prepared this SRB + break; + case SCSIOP_UNMAP: + if (PrepareUnmap(Target, SrbExt->Srb)) + return TRUE; // prepared this SRB + break; + default: + ASSERT(FALSE); + break; + } + QueueUnPop(&Target->FreshSrbs, &SrbExt->Entry); + + return FALSE; // prepare failed +} + +static FORCEINLINE BOOLEAN +TargetSubmitPrepared( + __in PXENVBD_TARGET Target + ) +{ + PXENVBD_BLOCKRING BlockRing = FrontendGetBlockRing(Target->Frontend); + if (TargetIsPaused(Target)) { + if (QueueCount(&Target->PreparedReqs)) + Warning("Target[%d] : Paused, not submitting new requests (%u)\n", + TargetGetTargetId(Target), + QueueCount(&Target->PreparedReqs)); + return FALSE; + } + + for (;;) { + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry; + + Entry = QueuePop(&Target->PreparedReqs); + if (Entry == NULL) + break; + + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + + QueueAppend(&Target->SubmittedReqs, &Request->Entry); + KeMemoryBarrier(); + + if (BlockRingSubmit(BlockRing, Request)) + continue; + + QueueRemove(&Target->SubmittedReqs, &Request->Entry); + QueueUnPop(&Target->PreparedReqs, &Request->Entry); + return FALSE; // ring full + } + + return TRUE; +} + +static FORCEINLINE VOID +TargetCompleteShutdown( + __in PXENVBD_TARGET Target + ) +{ + if (QueueCount(&Target->ShutdownSrbs) == 0) + return; + + if (QueueCount(&Target->FreshSrbs) || + QueueCount(&Target->PreparedReqs) || + QueueCount(&Target->SubmittedReqs)) + return; + + for (;;) { + PXENVBD_SRBEXT SrbExt; + PLIST_ENTRY Entry = QueuePop(&Target->ShutdownSrbs); + if (Entry == NULL) + break; + SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); + SrbExt->Srb->SrbStatus = SRB_STATUS_SUCCESS; + AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt->Srb); + } +} + +static FORCEINLINE PCHAR +BlkifOperationName( + IN UCHAR Operation + ) +{ + switch (Operation) { + case BLKIF_OP_READ: return "READ"; + case BLKIF_OP_WRITE: return "WRITE"; + case BLKIF_OP_WRITE_BARRIER: return "WRITE_BARRIER"; + case BLKIF_OP_FLUSH_DISKCACHE: return "FLUSH_DISKCACHE"; + case BLKIF_OP_RESERVED_1: return "RESERVED_1"; + case BLKIF_OP_DISCARD: return "DISCARD"; + case BLKIF_OP_INDIRECT: return "INDIRECT"; + default: return ""; + } +} + +VOID +TargetSubmitRequests( + __in PXENVBD_TARGET Target + ) +{ + for (;;) { + // submit all prepared requests (0 or more requests) + // return TRUE if submitted 0 or more requests from prepared queue + // return FALSE iff ring is full + if (!TargetSubmitPrepared(Target)) + break; + + // prepare a single SRB (into 1 or more requests) + // return TRUE if prepare succeeded + // return FALSE if prepare failed or fresh queue empty + if (!TargetPrepareFresh(Target)) + break; + } + + // if no requests/SRBs outstanding, complete any shutdown SRBs + TargetCompleteShutdown(Target); +} + +VOID +TargetCompleteResponse( + __in PXENVBD_TARGET Target, + __in ULONG Tag, + __in SHORT Status + ) +{ + PXENVBD_REQUEST Request; + PSCSI_REQUEST_BLOCK Srb; + PXENVBD_SRBEXT SrbExt; + + Request = TargetRequestFromTag(Target, Tag); + if (Request == NULL) + return; + + Srb = Request->Srb; + SrbExt = GetSrbExt(Srb); + ASSERT3P(SrbExt, !=, NULL); + + switch (Status) { + case BLKIF_RSP_OKAY: + RequestCopyOutput(Request); + break; + + case BLKIF_RSP_EOPNOTSUPP: + // Remove appropriate feature support + FrontendRemoveFeature(Target->Frontend, Request->Operation); + // Succeed this SRB, subsiquent SRBs will be succeeded instead of being passed to the backend. + Srb->SrbStatus = SRB_STATUS_SUCCESS; + break; + + case BLKIF_RSP_ERROR: + default: + Warning("Target[%d] : %s BLKIF_RSP_ERROR (Tag %x)\n", + TargetGetTargetId(Target), BlkifOperationName(Request->Operation), Tag); + Srb->SrbStatus = SRB_STATUS_ERROR; + break; + } + + TargetPutRequest(Target, Request); + + // complete srb + if (InterlockedDecrement(&SrbExt->Count) == 0) { + if (Srb->SrbStatus == SRB_STATUS_PENDING) { + // SRB has not hit a failure condition (BLKIF_RSP_ERROR | BLKIF_RSP_EOPNOTSUPP) + // from any of its responses. SRB must have succeeded + Srb->SrbStatus = SRB_STATUS_SUCCESS; + Srb->ScsiStatus = 0x00; // SCSI_GOOD + } else { + // Srb->SrbStatus has already been set by 1 or more requests with Status != BLKIF_RSP_OKAY + Srb->ScsiStatus = 0x40; // SCSI_ABORTED + } + + AdapterCompleteSrb(TargetGetAdapter(Target), Srb); + } +} + +VOID +TargetPreResume( + __in PXENVBD_TARGET Target + ) +{ + LIST_ENTRY List; + + InitializeListHead(&List); + + // pop all submitted requests, cleanup and add associated SRB to a list + for (;;) { + PXENVBD_SRBEXT SrbExt; + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry = QueuePop(&Target->SubmittedReqs); + if (Entry == NULL) + break; + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + SrbExt = GetSrbExt(Request->Srb); + + TargetPutRequest(Target, Request); + + if (InterlockedDecrement(&SrbExt->Count) == 0) { + InsertTailList(&List, &SrbExt->Entry); + } + } + + // pop all prepared requests, cleanup and add associated SRB to a list + for (;;) { + PXENVBD_SRBEXT SrbExt; + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry = QueuePop(&Target->PreparedReqs); + if (Entry == NULL) + break; + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + SrbExt = GetSrbExt(Request->Srb); + + TargetPutRequest(Target, Request); + + if (InterlockedDecrement(&SrbExt->Count) == 0) { + InsertTailList(&List, &SrbExt->Entry); + } + } + + // foreach SRB in list, put on start of FreshSrbs + for (;;) { + PXENVBD_SRBEXT SrbExt; + PLIST_ENTRY Entry = RemoveTailList(&List); + if (Entry == &List) + break; + SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); + + QueueUnPop(&Target->FreshSrbs, &SrbExt->Entry); + } + + // now the first set of requests popped off submitted list is the next SRB + // to be popped off the fresh list +} + +VOID +TargetPostResume( + __in PXENVBD_TARGET Target + ) +{ + KIRQL Irql; + + Verbose("Target[%d] : %d Fresh SRBs\n", TargetGetTargetId(Target), QueueCount(&Target->FreshSrbs)); + + // clear missing flag + KeAcquireSpinLock(&Target->Lock, &Irql); + Verbose("Target[%d] : %s (%s)\n", TargetGetTargetId(Target), Target->Missing ? "MISSING" : "NOT_MISSING", Target->Reason); + Target->Missing = FALSE; + Target->Reason = NULL; + KeReleaseSpinLock(&Target->Lock, Irql); +} + +//============================================================================= +// SRBs +__checkReturn +static FORCEINLINE BOOLEAN +__ValidateSectors( + __in ULONG64 SectorCount, + __in ULONG64 Start, + __in ULONG Length + ) +{ + // Deal with overflow + return (Start < SectorCount) && ((Start + Length) <= SectorCount); +} + +__checkReturn +static FORCEINLINE BOOLEAN +__ValidateSrbBuffer( + __in PCHAR Caller, + __in PSCSI_REQUEST_BLOCK Srb, + __in ULONG MinLength + ) +{ + if (Srb->DataBuffer == NULL) { + Error("%s: Srb[0x%p].DataBuffer = NULL\n", Caller, Srb); + return FALSE; + } + if (MinLength) { + if (Srb->DataTransferLength < MinLength) { + Error("%s: Srb[0x%p].DataTransferLength < %d\n", Caller, Srb, MinLength); + return FALSE; + } + } else { + if (Srb->DataTransferLength == 0) { + Error("%s: Srb[0x%p].DataTransferLength = 0\n", Caller, Srb); + return FALSE; + } + } + + return TRUE; +} + +__checkReturn +static DECLSPEC_NOINLINE BOOLEAN +TargetReadWrite( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Target->Frontend); + PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); + PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend); + + if (FrontendGetCaps(Target->Frontend)->Connected == FALSE) { + Trace("Target[%d] : Not Ready, fail SRB\n", TargetGetTargetId(Target)); + Srb->ScsiStatus = 0x40; // SCSI_ABORT; + return TRUE; + } + + // check valid sectors + if (!__ValidateSectors(DiskInfo->SectorCount, Cdb_LogicalBlock(Srb), Cdb_TransferBlock(Srb))) { + Trace("Target[%d] : Invalid Sector (%d @ %lld < %lld)\n", TargetGetTargetId(Target), Cdb_TransferBlock(Srb), Cdb_LogicalBlock(Srb), DiskInfo->SectorCount); + Srb->ScsiStatus = 0x40; // SCSI_ABORT + return TRUE; // Complete now + } + + QueueAppend(&Target->FreshSrbs, &SrbExt->Entry); + NotifierKick(Notifier); + + return FALSE; +} + +__checkReturn +static DECLSPEC_NOINLINE BOOLEAN +TargetSyncCache( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); + PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend); + + if (FrontendGetCaps(Target->Frontend)->Connected == FALSE) { + Trace("Target[%d] : Not Ready, fail SRB\n", TargetGetTargetId(Target)); + Srb->ScsiStatus = 0x40; // SCSI_ABORT; + return TRUE; + } + + if (FrontendGetDiskInfo(Target->Frontend)->FlushCache == FALSE && + FrontendGetDiskInfo(Target->Frontend)->Barrier == FALSE) { + Trace("Target[%d] : FLUSH and BARRIER not supported, suppressing\n", TargetGetTargetId(Target)); + Srb->ScsiStatus = 0x00; // SCSI_GOOD + Srb->SrbStatus = SRB_STATUS_SUCCESS; + return TRUE; + } + + QueueAppend(&Target->FreshSrbs, &SrbExt->Entry); + NotifierKick(Notifier); + + return FALSE; +} + +__checkReturn +static DECLSPEC_NOINLINE BOOLEAN +TargetUnmap( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); + PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend); + + if (FrontendGetCaps(Target->Frontend)->Connected == FALSE) { + Trace("Target[%d] : Not Ready, fail SRB\n", TargetGetTargetId(Target)); + Srb->ScsiStatus = 0x40; // SCSI_ABORT; + return TRUE; + } + + if (FrontendGetDiskInfo(Target->Frontend)->Discard == FALSE) { + Trace("Target[%d] : DISCARD not supported, suppressing\n", TargetGetTargetId(Target)); + Srb->ScsiStatus = 0x00; // SCSI_GOOD + Srb->SrbStatus = SRB_STATUS_SUCCESS; + return TRUE; + } + + QueueAppend(&Target->FreshSrbs, &SrbExt->Entry); + NotifierKick(Notifier); + + return FALSE; +} + +#define MODE_CACHING_PAGE_LENGTH 20 +static DECLSPEC_NOINLINE VOID +TargetModeSense( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PMODE_PARAMETER_HEADER Header = Srb->DataBuffer; + const UCHAR PageCode = Cdb_PageCode(Srb); + ULONG LengthLeft = Cdb_AllocationLength(Srb); + PVOID CurrentPage = Srb->DataBuffer; + + UNREFERENCED_PARAMETER(Target); + + RtlZeroMemory(Srb->DataBuffer, Srb->DataTransferLength); + + if (!__ValidateSrbBuffer(__FUNCTION__, Srb, (ULONG)sizeof(struct _MODE_SENSE))) { + Srb->ScsiStatus = 0x40; + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + Srb->DataTransferLength = 0; + return; + } + + // TODO : CDROM requires more ModePage entries + // Header + Header->ModeDataLength = sizeof(MODE_PARAMETER_HEADER) - 1; + Header->MediumType = 0; + Header->DeviceSpecificParameter = 0; + Header->BlockDescriptorLength = 0; + LengthLeft -= sizeof(MODE_PARAMETER_HEADER); + CurrentPage = ((PUCHAR)CurrentPage + sizeof(MODE_PARAMETER_HEADER)); + + // Fill in Block Parameters (if Specified and space) + // when the DBD (Disable Block Descriptor) is set, ignore the block page + if (Cdb_Dbd(Srb) == 0 && + LengthLeft >= sizeof(MODE_PARAMETER_BLOCK)) { + PMODE_PARAMETER_BLOCK Block = (PMODE_PARAMETER_BLOCK)CurrentPage; + // Fill in BlockParams + Block->DensityCode = 0; + Block->NumberOfBlocks[0] = 0; + Block->NumberOfBlocks[1] = 0; + Block->NumberOfBlocks[2] = 0; + Block->BlockLength[0] = 0; + Block->BlockLength[1] = 0; + Block->BlockLength[2] = 0; + + Header->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); + Header->ModeDataLength += sizeof(MODE_PARAMETER_BLOCK); + LengthLeft -= sizeof(MODE_PARAMETER_BLOCK); + CurrentPage = ((PUCHAR)CurrentPage + sizeof(MODE_PARAMETER_BLOCK)); + } + + // Fill in Cache Parameters (if Specified and space) + if ((PageCode == MODE_PAGE_CACHING || PageCode == MODE_SENSE_RETURN_ALL) && + LengthLeft >= MODE_CACHING_PAGE_LENGTH) { + PMODE_CACHING_PAGE Caching = (PMODE_CACHING_PAGE)CurrentPage; + // Fill in CachingParams + Caching->PageCode = MODE_PAGE_CACHING; + Caching->PageSavable = 0; + Caching->PageLength = MODE_CACHING_PAGE_LENGTH; + Caching->ReadDisableCache = 0; + Caching->MultiplicationFactor = 0; + Caching->WriteCacheEnable = FrontendGetDiskInfo(Target->Frontend)->FlushCache ? 1 : 0; + Caching->WriteRetensionPriority = 0; + Caching->ReadRetensionPriority = 0; + Caching->DisablePrefetchTransfer[0] = 0; + Caching->DisablePrefetchTransfer[1] = 0; + Caching->MinimumPrefetch[0] = 0; + Caching->MinimumPrefetch[1] = 0; + Caching->MaximumPrefetch[0] = 0; + Caching->MaximumPrefetch[1] = 0; + Caching->MaximumPrefetchCeiling[0] = 0; + Caching->MaximumPrefetchCeiling[1] = 0; + + Header->ModeDataLength += MODE_CACHING_PAGE_LENGTH; + LengthLeft -= MODE_CACHING_PAGE_LENGTH; + CurrentPage = ((PUCHAR)CurrentPage + MODE_CACHING_PAGE_LENGTH); + } + + // Fill in Informational Exception Parameters (if Specified and space) + if ((PageCode == MODE_PAGE_FAULT_REPORTING || PageCode == MODE_SENSE_RETURN_ALL) && + LengthLeft >= sizeof(MODE_INFO_EXCEPTIONS)) { + PMODE_INFO_EXCEPTIONS Exceptions = (PMODE_INFO_EXCEPTIONS)CurrentPage; + // Fill in Exceptions + Exceptions->PageCode = MODE_PAGE_FAULT_REPORTING; + Exceptions->PSBit = 0; + Exceptions->PageLength = sizeof(MODE_INFO_EXCEPTIONS); + Exceptions->Flags = 0; + Exceptions->Dexcpt = 1; // disabled + Exceptions->ReportMethod = 0; + Exceptions->IntervalTimer[0] = 0; + Exceptions->IntervalTimer[1] = 0; + Exceptions->IntervalTimer[2] = 0; + Exceptions->IntervalTimer[3] = 0; + Exceptions->ReportCount[0] = 0; + Exceptions->ReportCount[1] = 0; + Exceptions->ReportCount[2] = 0; + Exceptions->ReportCount[3] = 0; + + Header->ModeDataLength += sizeof(MODE_INFO_EXCEPTIONS); + LengthLeft -= sizeof(MODE_INFO_EXCEPTIONS); + CurrentPage = ((PUCHAR)CurrentPage + sizeof(MODE_INFO_EXCEPTIONS)); + } + + // Finish this SRB + Srb->SrbStatus = SRB_STATUS_SUCCESS; + Srb->DataTransferLength = __min(Cdb_AllocationLength(Srb), (ULONG)(Header->ModeDataLength + 1)); +} + +static DECLSPEC_NOINLINE VOID +TargetRequestSense( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PSENSE_DATA Sense = Srb->DataBuffer; + + UNREFERENCED_PARAMETER(Target); + + if (!__ValidateSrbBuffer(__FUNCTION__, Srb, (ULONG)sizeof(SENSE_DATA))) { + Srb->ScsiStatus = 0x40; + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + return; + } + + RtlZeroMemory(Sense, sizeof(SENSE_DATA)); + + Sense->ErrorCode = 0x70; + Sense->Valid = 1; + Sense->AdditionalSenseCodeQualifier = 0; + Sense->SenseKey = SCSI_SENSE_NO_SENSE; + Sense->AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE; + Srb->DataTransferLength = sizeof(SENSE_DATA); + Srb->SrbStatus = SRB_STATUS_SUCCESS; +} + +static DECLSPEC_NOINLINE VOID +TargetReportLuns( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + ULONG Length; + ULONG Offset; + ULONG AllocLength = Cdb_AllocationLength(Srb); + PUCHAR Buffer = Srb->DataBuffer; + + UNREFERENCED_PARAMETER(Target); + + if (!__ValidateSrbBuffer(__FUNCTION__, Srb, 8)) { + Srb->ScsiStatus = 0x40; + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + Srb->DataTransferLength = 0; + return; + } + + RtlZeroMemory(Buffer, AllocLength); + + Length = 0; + Offset = 8; + + if (Offset + 8 <= AllocLength) { + Buffer[Offset] = 0; + Offset += 8; + Length += 8; + } + + if (Offset + 8 <= AllocLength) { + Buffer[Offset] = XENVBD_MAX_TARGETS; + Offset += 8; + Length += 8; + } + + REVERSE_BYTES(Buffer, &Length); + + Srb->DataTransferLength = __min(Length, AllocLength); + Srb->SrbStatus = SRB_STATUS_SUCCESS; +} + +static DECLSPEC_NOINLINE VOID +TargetReadCapacity( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PREAD_CAPACITY_DATA Capacity = Srb->DataBuffer; + PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Target->Frontend); + ULONG64 SectorCount; + ULONG SectorSize; + ULONG LastBlock; + + if (Cdb_PMI(Srb) == 0 && Cdb_LogicalBlock(Srb) != 0) { + Srb->ScsiStatus = 0x02; // CHECK_CONDITION + return; + } + + SectorCount = DiskInfo->SectorCount; + SectorSize = DiskInfo->SectorSize; + + if (SectorCount == (ULONG)SectorCount) + LastBlock = (ULONG)SectorCount - 1; + else + LastBlock = ~(ULONG)0; + + if (Capacity) { + Capacity->LogicalBlockAddress = _byteswap_ulong(LastBlock); + Capacity->BytesPerBlock = _byteswap_ulong(SectorSize); + } + + Srb->SrbStatus = SRB_STATUS_SUCCESS; +} + +static DECLSPEC_NOINLINE VOID +TargetReadCapacity16( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PREAD_CAPACITY16_DATA Capacity = Srb->DataBuffer; + PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Target->Frontend); + ULONG64 SectorCount; + ULONG SectorSize; + ULONG PhysSectorSize; + ULONG LogicalPerPhysical; + ULONG LogicalPerPhysicalExponent; + + if (Cdb_PMI(Srb) == 0 && Cdb_LogicalBlock(Srb) != 0) { + Srb->ScsiStatus = 0x02; // CHECK_CONDITION + return; + } + + SectorCount = DiskInfo->SectorCount; + SectorSize = DiskInfo->SectorSize; + PhysSectorSize = DiskInfo->PhysSectorSize; + + LogicalPerPhysical = PhysSectorSize / SectorSize; + + if (!_BitScanReverse(&LogicalPerPhysicalExponent, LogicalPerPhysical)) + LogicalPerPhysicalExponent = 0; + + if (Capacity) { + Capacity->LogicalBlockAddress.QuadPart = _byteswap_uint64(SectorCount - 1); + Capacity->BytesPerBlock = _byteswap_ulong(SectorSize); + Capacity->LogicalPerPhysicalExponent = (UCHAR)LogicalPerPhysicalExponent; + } + + Srb->SrbStatus = SRB_STATUS_SUCCESS; +} + +//============================================================================= +// StorPort Methods +__checkReturn +static FORCEINLINE BOOLEAN +__TargetExecuteScsi( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + const UCHAR Operation = Cdb_OperationEx(Srb); + PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Target->Frontend); + + if (DiskInfo->DiskInfo & VDISK_READONLY) { + Trace("Target[%d] : (%08x) Read-Only, fail SRB (%02x:%s)\n", TargetGetTargetId(Target), + DiskInfo->DiskInfo, Operation, Cdb_OperationName(Operation)); + Srb->ScsiStatus = 0x40; // SCSI_ABORT + return TRUE; + } + + // idea: check pdo state here. still push to freshsrbs + switch (Operation) { + case SCSIOP_READ: + case SCSIOP_WRITE: + return TargetReadWrite(Target, Srb); + break; + + case SCSIOP_SYNCHRONIZE_CACHE: + return TargetSyncCache(Target, Srb); + break; + + case SCSIOP_UNMAP: + return TargetUnmap(Target, Srb); + break; + + case SCSIOP_INQUIRY: + if (!StorPortSetDeviceQueueDepth(TargetGetAdapter(Target), + 0, + (UCHAR)TargetGetTargetId(Target), + 0, + XENVBD_MAX_QUEUE_DEPTH)) + Verbose("Target[%d] : Failed to set queue depth\n", + TargetGetTargetId(Target)); + PdoInquiry(TargetGetTargetId(Target), FrontendGetInquiry(Target->Frontend), Srb, Target->DeviceType); + break; + case SCSIOP_MODE_SENSE: + TargetModeSense(Target, Srb); + break; + case SCSIOP_REQUEST_SENSE: + TargetRequestSense(Target, Srb); + break; + case SCSIOP_REPORT_LUNS: + TargetReportLuns(Target, Srb); + break; + case SCSIOP_READ_CAPACITY: + TargetReadCapacity(Target, Srb); + break; + case SCSIOP_READ_CAPACITY16: + TargetReadCapacity16(Target, Srb); + break; + case SCSIOP_MEDIUM_REMOVAL: + case SCSIOP_TEST_UNIT_READY: + case SCSIOP_RESERVE_UNIT: + case SCSIOP_RESERVE_UNIT10: + case SCSIOP_RELEASE_UNIT: + case SCSIOP_RELEASE_UNIT10: + case SCSIOP_VERIFY: + case SCSIOP_VERIFY16: + Srb->SrbStatus = SRB_STATUS_SUCCESS; + break; + case SCSIOP_START_STOP_UNIT: + Trace("Target[%d] : Start/Stop Unit (%02X)\n", TargetGetTargetId(Target), Srb->Cdb[4]); + Srb->SrbStatus = SRB_STATUS_SUCCESS; + break; + default: + Trace("Target[%d] : Unsupported CDB (%02x:%s)\n", TargetGetTargetId(Target), Operation, Cdb_OperationName(Operation)); + break; + } + return TRUE; +} + +static FORCEINLINE BOOLEAN +__TargetQueueShutdown( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); + PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend); + + QueueAppend(&Target->ShutdownSrbs, &SrbExt->Entry); + NotifierKick(Notifier); + + return FALSE; +} + +static FORCEINLINE BOOLEAN +__TargetReset( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + Verbose("Target[%u] ====>\n", TargetGetTargetId(Target)); + + TargetReset(Target); + Srb->SrbStatus = SRB_STATUS_SUCCESS; + + Verbose("Target[%u] <====\n", TargetGetTargetId(Target)); + return TRUE; +} + +__checkReturn +static FORCEINLINE BOOLEAN +__ValidateSrbForTarget( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + const UCHAR Operation = Cdb_OperationEx(Srb); + + if (Target == NULL) { + Error("Invalid Target(NULL) (%02x:%s)\n", + Operation, Cdb_OperationName(Operation)); + Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID; + return FALSE; + } + + if (Srb->PathId != 0) { + Error("Target[%d] : Invalid PathId(%d) (%02x:%s)\n", + TargetGetTargetId(Target), Srb->PathId, Operation, Cdb_OperationName(Operation)); + Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID; + return FALSE; + } + + if (Srb->Lun != 0) { + Error("Target[%d] : Invalid Lun(%d) (%02x:%s)\n", + TargetGetTargetId(Target), Srb->Lun, Operation, Cdb_OperationName(Operation)); + Srb->SrbStatus = SRB_STATUS_INVALID_LUN; + return FALSE; + } + + if (TargetIsMissing(Target)) { + Error("Target[%d] : %s (%s) (%02x:%s)\n", + TargetGetTargetId(Target), Target->Missing ? "MISSING" : "NOT_MISSING", Target->Reason, Operation, Cdb_OperationName(Operation)); + Srb->SrbStatus = SRB_STATUS_NO_DEVICE; + return FALSE; + } + + return TRUE; +} + +__checkReturn +BOOLEAN +TargetStartIo( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ) +{ + if (!__ValidateSrbForTarget(Target, Srb)) + return TRUE; + + switch (Srb->Function) { + case SRB_FUNCTION_EXECUTE_SCSI: + return __TargetExecuteScsi(Target, Srb); + + case SRB_FUNCTION_RESET_DEVICE: + return __TargetReset(Target, Srb); + + case SRB_FUNCTION_FLUSH: + case SRB_FUNCTION_SHUTDOWN: + return __TargetQueueShutdown(Target, Srb); + + default: + return TRUE; + } +} + +static FORCEINLINE VOID +__TargetCleanupSubmittedReqs( + IN PXENVBD_TARGET Target + ) +{ + // Fail PreparedReqs + for (;;) { + PXENVBD_SRBEXT SrbExt; + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry = QueuePop(&Target->SubmittedReqs); + if (Entry == NULL) + break; + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + SrbExt = GetSrbExt(Request->Srb); + + Verbose("Target[%d] : SubmittedReq 0x%p -> FAILED\n", TargetGetTargetId(Target), Request); + + TargetPutRequest(Target, Request); + + if (InterlockedDecrement(&SrbExt->Count) == 0) { + SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; + SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED + AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt->Srb); + } + } +} + +VOID +TargetReset( + __in PXENVBD_TARGET Target + ) +{ + Trace("Target[%d] ====> (Irql=%d)\n", TargetGetTargetId(Target), KeGetCurrentIrql()); + + __TargetPauseDataPath(Target, TRUE); + + if (QueueCount(&Target->SubmittedReqs)) { + Error("Target[%d] : backend has %u outstanding requests after a TargetReset\n", + TargetGetTargetId(Target), QueueCount(&Target->SubmittedReqs)); + } + + __TargetUnpauseDataPath(Target); + + Trace("Target[%d] <==== (Irql=%d)\n", TargetGetTargetId(Target), KeGetCurrentIrql()); +} + + +VOID +TargetSrbPnp( + __in PXENVBD_TARGET Target, + __in PSCSI_PNP_REQUEST_BLOCK Srb + ) +{ + switch (Srb->PnPAction) { + case StorQueryCapabilities: { + PSTOR_DEVICE_CAPABILITIES DeviceCaps = Srb->DataBuffer; + PXENVBD_CAPS Caps = FrontendGetCaps(Target->Frontend); + + if (Caps->Removable) + DeviceCaps->Removable = 1; + if (Caps->Removable) + DeviceCaps->EjectSupported = 1; + if (Caps->SurpriseRemovable) + DeviceCaps->SurpriseRemovalOK = 1; + + DeviceCaps->UniqueID = 1; + + } break; + + default: + break; + } +} + +//============================================================================= +// PnP Handler +static FORCEINLINE VOID +__TargetDeviceUsageNotification( + __in PXENVBD_TARGET Target, + __in PIRP Irp + ) +{ + PIO_STACK_LOCATION StackLocation; + BOOLEAN Value; + DEVICE_USAGE_NOTIFICATION_TYPE Type; + PXENVBD_CAPS Caps = FrontendGetCaps(Target->Frontend); + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + Value = StackLocation->Parameters.UsageNotification.InPath; + Type = StackLocation->Parameters.UsageNotification.Type; + + switch (Type) { + case DeviceUsageTypePaging: + if (Caps->Paging == Value) + return; + Caps->Paging = Value; + break; + + case DeviceUsageTypeHibernation: + if (Caps->Hibernation == Value) + return; + Caps->Hibernation = Value; + break; + + case DeviceUsageTypeDumpFile: + if (Caps->DumpFile == Value) + return; + Caps->DumpFile = Value; + break; + + default: + return; + } + FrontendWriteUsage(Target->Frontend); +} + +static FORCEINLINE VOID +__TargetCheckEjectPending( + __in PXENVBD_TARGET Target + ) +{ + KIRQL Irql; + BOOLEAN EjectPending = FALSE; + + KeAcquireSpinLock(&Target->Lock, &Irql); + if (Target->EjectPending) { + EjectPending = TRUE; + Target->EjectPending = FALSE; + Target->EjectRequested = TRUE; + } + KeReleaseSpinLock(&Target->Lock, Irql); + + if (EjectPending) { + Verbose("Target[%d] : IoRequestDeviceEject(0x%p)\n", TargetGetTargetId(Target), Target->DeviceObject); + IoRequestDeviceEject(Target->DeviceObject); + } +} + +static FORCEINLINE VOID +__TargetCheckEjectFailed( + __in PXENVBD_TARGET Target + ) +{ + KIRQL Irql; + BOOLEAN EjectFailed = FALSE; + + KeAcquireSpinLock(&Target->Lock, &Irql); + if (Target->EjectRequested) { + EjectFailed = TRUE; + Target->EjectRequested = FALSE; + } + KeReleaseSpinLock(&Target->Lock, Irql); + + if (EjectFailed) { + Error("Target[%d] : Unplug failed due to open handle(s)!\n", TargetGetTargetId(Target)); + FrontendStoreWriteFrontend(Target->Frontend, "error", "Unplug failed due to open handle(s)!"); + } +} + +static FORCEINLINE VOID +__TargetRemoveDevice( + __in PXENVBD_TARGET Target + ) +{ + TargetD0ToD3(Target); + + switch (TargetGetDevicePnpState(Target)) { + case SurpriseRemovePending: + TargetSetMissing(Target, "Surprise Remove"); + TargetSetDevicePnpState(Target, Deleted); + StorPortNotification(BusChangeDetected, TargetGetAdapter(Target), 0); + break; + + default: + TargetSetMissing(Target, "Removed"); + TargetSetDevicePnpState(Target, Deleted); + StorPortNotification(BusChangeDetected, TargetGetAdapter(Target), 0); + break; + } +} + +static FORCEINLINE VOID +__TargetEject( + __in PXENVBD_TARGET Target + ) +{ + TargetSetMissing(Target, "Ejected"); + TargetSetDevicePnpState(Target, Deleted); + StorPortNotification(BusChangeDetected, TargetGetAdapter(Target), 0); +} + +__checkReturn +NTSTATUS +TargetDispatchPnp( + __in PXENVBD_TARGET Target, + __in PDEVICE_OBJECT DeviceObject, + __in PIRP Irp + ) +{ + PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); + + __TargetCheckEjectPending(Target); + + switch (Stack->MinorFunction) { + case IRP_MN_START_DEVICE: + (VOID) TargetD3ToD0(Target); + TargetSetDevicePnpState(Target, Started); + break; + + case IRP_MN_QUERY_STOP_DEVICE: + TargetSetDevicePnpState(Target, StopPending); + break; + + case IRP_MN_CANCEL_STOP_DEVICE: + __TargetRestoreDevicePnpState(Target, StopPending); + break; + + case IRP_MN_STOP_DEVICE: + TargetD0ToD3(Target); + TargetSetDevicePnpState(Target, Stopped); + break; + + case IRP_MN_QUERY_REMOVE_DEVICE: + TargetSetDevicePnpState(Target, RemovePending); + break; + + case IRP_MN_CANCEL_REMOVE_DEVICE: + __TargetCheckEjectFailed(Target); + __TargetRestoreDevicePnpState(Target, RemovePending); + break; + + case IRP_MN_SURPRISE_REMOVAL: + TargetSetDevicePnpState(Target, SurpriseRemovePending); + break; + + case IRP_MN_REMOVE_DEVICE: + __TargetRemoveDevice(Target); + break; + + case IRP_MN_EJECT: + __TargetEject(Target); + break; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: + __TargetDeviceUsageNotification(Target, Irp); + break; + + default: + break; + } + TargetDereference(Target); + return DriverDispatchPnp(DeviceObject, Irp); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +TargetIssueDeviceEject( + __in PXENVBD_TARGET Target, + __in __nullterminated const CHAR* Reason + ) +{ + KIRQL Irql; + BOOLEAN DoEject = FALSE; + + KeAcquireSpinLock(&Target->Lock, &Irql); + if (Target->DeviceObject) { + DoEject = TRUE; + Target->EjectRequested = TRUE; + } else { + Target->EjectPending = TRUE; + } + KeReleaseSpinLock(&Target->Lock, Irql); + + Verbose("Target[%d] : Ejecting (%s - %s)\n", TargetGetTargetId(Target), DoEject ? "Now" : "Next PnP IRP", Reason); + if (!Target->WrittenEjected) { + Target->WrittenEjected = TRUE; + FrontendStoreWriteFrontend(Target->Frontend, "ejected", "1"); + } + if (DoEject) { + Verbose("Target[%d] : IoRequestDeviceEject(0x%p)\n", TargetGetTargetId(Target), Target->DeviceObject); + IoRequestDeviceEject(Target->DeviceObject); + } else { + Verbose("Target[%d] : Triggering BusChangeDetected to detect device\n", TargetGetTargetId(Target)); + StorPortNotification(BusChangeDetected, TargetGetAdapter(Target), 0); + } +} + +__checkReturn +NTSTATUS +TargetD3ToD0( + __in PXENVBD_TARGET Target + ) +{ + NTSTATUS Status; + const ULONG TargetId = TargetGetTargetId(Target); + + if (!TargetSetDevicePowerState(Target, PowerDeviceD0)) + return STATUS_SUCCESS; + + Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); + Verbose("Target[%d] : D3->D0\n", TargetId); + + // power up frontend + Status = FrontendD3ToD0(Target->Frontend); + if (!NT_SUCCESS(Status)) + goto fail1; + + // connect frontend + Status = FrontendSetState(Target->Frontend, XENVBD_ENABLED); + if (!NT_SUCCESS(Status)) + goto fail2; + __TargetUnpauseDataPath(Target); + + Trace("Target[%d] @ (%d) <=====\n", TargetId, KeGetCurrentIrql()); + return STATUS_SUCCESS; + +fail2: + Error("Fail2\n"); + FrontendD0ToD3(Target->Frontend); + +fail1: + Error("Fail1 (%08x)\n", Status); + + Target->DevicePowerState = PowerDeviceD3; + + return Status; +} + +VOID +TargetD0ToD3( + __in PXENVBD_TARGET Target + ) +{ + const ULONG TargetId = TargetGetTargetId(Target); + + if (!TargetSetDevicePowerState(Target, PowerDeviceD3)) + return; + + Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); + Verbose("Target[%d] : D0->D3\n", TargetId); + + // close frontend + __TargetPauseDataPath(Target, FALSE); + (VOID) FrontendSetState(Target->Frontend, XENVBD_CLOSED); + ASSERT3U(QueueCount(&Target->SubmittedReqs), ==, 0); + + // power down frontend + FrontendD0ToD3(Target->Frontend); + + Trace("Target[%d] @ (%d) <=====\n", TargetId, KeGetCurrentIrql()); +} + +__checkReturn +BOOLEAN +TargetCreate( + __in PXENVBD_ADAPTER Adapter, + __in __nullterminated PCHAR DeviceId, + __in ULONG TargetId, + __in XENVBD_DEVICE_TYPE DeviceType + ) +{ + NTSTATUS Status; + PXENVBD_TARGET Target; + + Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); + + Status = STATUS_INSUFFICIENT_RESOURCES; +#pragma warning(suppress: 6014) + Target = __TargetAlloc(sizeof(XENVBD_TARGET)); + if (!Target) + goto fail1; + + Verbose("Target[%d] : Creating\n", TargetId); + Target->Signature = TARGET_SIGNATURE; + Target->Adapter = Adapter; + Target->DeviceObject = NULL; // filled in later + KeInitializeEvent(&Target->RemoveEvent, SynchronizationEvent, FALSE); + Target->ReferenceCount = 1; + Target->Paused = 1; // Paused until D3->D0 transition + Target->DevicePnpState = Present; + Target->DevicePowerState = PowerDeviceD3; + Target->DeviceType = DeviceType; + + KeInitializeSpinLock(&Target->Lock); + QueueInit(&Target->FreshSrbs); + QueueInit(&Target->PreparedReqs); + QueueInit(&Target->SubmittedReqs); + QueueInit(&Target->ShutdownSrbs); + __LookasideInit(&Target->RequestList, sizeof(XENVBD_REQUEST), REQUEST_POOL_TAG); + __LookasideInit(&Target->SegmentList, sizeof(XENVBD_SEGMENT), SEGMENT_POOL_TAG); + __LookasideInit(&Target->IndirectList, sizeof(XENVBD_INDIRECT), INDIRECT_POOL_TAG); + + Status = FrontendCreate(Target, DeviceId, TargetId, &Target->Frontend); + if (!NT_SUCCESS(Status)) + goto fail2; + + Status = TargetD3ToD0(Target); + if (!NT_SUCCESS(Status)) + goto fail3; + + if (!AdapterLinkTarget(Adapter, Target)) + goto fail4; + + Verbose("Target[%d] : Created (%s)\n", TargetId, Target); + Trace("Target[%d] @ (%d) <=====\n", TargetId, KeGetCurrentIrql()); + return TRUE; + +fail4: + Error("Fail4\n"); + TargetD0ToD3(Target); + +fail3: + Error("Fail3\n"); + FrontendDestroy(Target->Frontend); + Target->Frontend = NULL; + +fail2: + Error("Fail2\n"); + __LookasideTerm(&Target->IndirectList); + __LookasideTerm(&Target->SegmentList); + __LookasideTerm(&Target->RequestList); + __TargetFree(Target); + +fail1: + Error("Fail1 (%08x)\n", Status); + return FALSE; +} + +VOID +TargetDestroy( + __in PXENVBD_TARGET Target + ) +{ + const ULONG TargetId = TargetGetTargetId(Target); + PVOID Objects[4]; + PKWAIT_BLOCK WaitBlock; + + Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); + Verbose("Target[%d] : Destroying\n", TargetId); + + ASSERT3U(Target->Signature, ==, TARGET_SIGNATURE); + if (!AdapterUnlinkTarget(TargetGetAdapter(Target), Target)) { + Error("Target[%d] : TARGET 0x%p not linked to ADAPTER 0x%p\n", TargetId, Target, TargetGetAdapter(Target)); + } + + TargetD0ToD3(Target); + TargetDereference(Target); // drop initial ref count + + // Wait for ReferenceCount == 0 and RequestListUsed == 0 + Verbose("Target[%d] : ReferenceCount %d, RequestListUsed %d\n", TargetId, Target->ReferenceCount, Target->RequestList.Used); + Objects[0] = &Target->RemoveEvent; + Objects[1] = &Target->RequestList.Empty; + Objects[2] = &Target->SegmentList.Empty; + Objects[3] = &Target->IndirectList.Empty; + + WaitBlock = (PKWAIT_BLOCK)__TargetAlloc(sizeof(KWAIT_BLOCK) * ARRAYSIZE(Objects)); + if (WaitBlock == NULL) { + ULONG Index; + + Error("Unable to allocate resources for KWAIT_BLOCK\n"); + + for (Index = 0; Index < ARRAYSIZE(Objects); Index++) + KeWaitForSingleObject(Objects[Index], + Executive, + KernelMode, + FALSE, + NULL); + } else { + KeWaitForMultipleObjects(ARRAYSIZE(Objects), + Objects, + WaitAll, + Executive, + KernelMode, + FALSE, + NULL, + WaitBlock); +#pragma prefast(suppress:6102) + __TargetFree(WaitBlock); + } + + ASSERT3S(Target->ReferenceCount, ==, 0); + ASSERT3U(TargetGetDevicePnpState(Target), ==, Deleted); + + FrontendDestroy(Target->Frontend); + Target->Frontend = NULL; + + __LookasideTerm(&Target->IndirectList); + __LookasideTerm(&Target->SegmentList); + __LookasideTerm(&Target->RequestList); + + ASSERT3U(Target->Signature, ==, TARGET_SIGNATURE); + RtlZeroMemory(Target, sizeof(XENVBD_TARGET)); + __TargetFree(Target); + + Verbose("Target[%d] : Destroyed\n", TargetId); + Trace("Target[%d] @ (%d) <=====\n", TargetId, KeGetCurrentIrql()); +} diff --git a/src/xenvbd/target.h b/src/xenvbd/target.h new file mode 100644 index 0000000..941b464 --- /dev/null +++ b/src/xenvbd/target.h @@ -0,0 +1,229 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _XENVBD_TARGET_H +#define _XENVBD_TARGET_H + +typedef struct _XENVBD_TARGET XENVBD_TARGET, *PXENVBD_TARGET; + +#include +#include +#include +#include "adapter.h" +#include "srbext.h" +#include "types.h" +#include + +extern VOID +TargetDebugCallback( + __in PXENVBD_TARGET Target, + __in PXENBUS_DEBUG_INTERFACE Debug + ); + +// Creation/Deletion +__checkReturn +extern BOOLEAN +TargetCreate( + __in PXENVBD_ADAPTER Adapter, + __in __nullterminated PCHAR DeviceId, + __in ULONG TargetId, + __in XENVBD_DEVICE_TYPE DeviceType + ); + +extern VOID +TargetDestroy( + __in PXENVBD_TARGET Target + ); + +__checkReturn +extern NTSTATUS +TargetD3ToD0( + __in PXENVBD_TARGET Target + ); + +extern VOID +TargetD0ToD3( + __in PXENVBD_TARGET Target + ); + +// PnP States +extern VOID +TargetSetMissing( + __in PXENVBD_TARGET Target, + __in __nullterminated const CHAR* Reason + ); + +__checkReturn +extern BOOLEAN +TargetIsMissing( + __in PXENVBD_TARGET Target + ); + +extern const CHAR* +TargetMissingReason( + __in PXENVBD_TARGET Target + ); + +__checkReturn +extern BOOLEAN +TargetIsEmulatedUnplugged( + __in PXENVBD_TARGET Target + ); + +extern VOID +TargetSetDevicePnpState( + __in PXENVBD_TARGET Target, + __in DEVICE_PNP_STATE State + ); + +__checkReturn +extern DEVICE_PNP_STATE +TargetGetDevicePnpState( + __in PXENVBD_TARGET Target + ); + +// Reference Counting +extern LONG +__TargetReference( + __in PXENVBD_TARGET Target, + __in PCHAR Caller + ); + +#define TargetReference(_x_) __TargetReference(_x_, __FUNCTION__) + +extern LONG +__TargetDereference( + __in PXENVBD_TARGET Target, + __in PCHAR Caller + ); + +#define TargetDereference(_x_) __TargetDereference(_x_, __FUNCTION__) + +// Query Methods +extern ULONG +TargetGetTargetId( + __in PXENVBD_TARGET Target + ); + +__checkReturn +extern PDEVICE_OBJECT +TargetGetDeviceObject( + __in PXENVBD_TARGET Target + ); + +extern VOID +TargetSetDeviceObject( + __in PXENVBD_TARGET Target, + __in PDEVICE_OBJECT DeviceObject + ); + +__checkReturn +extern BOOLEAN +TargetIsPaused( + __in PXENVBD_TARGET Target + ); + +__checkReturn +extern ULONG +TargetOutstandingReqs( + __in PXENVBD_TARGET Target + ); + +__checkReturn +extern PXENVBD_ADAPTER +TargetGetAdapter( + __in PXENVBD_TARGET Target + ); + +extern ULONG +TargetSectorSize( + __in PXENVBD_TARGET Target + ); + +// Queue-Related +extern VOID +TargetSubmitRequests( + __in PXENVBD_TARGET Target + ); + +extern VOID +TargetCompleteResponse( + __in PXENVBD_TARGET Target, + __in ULONG Tag, + __in SHORT Status + ); + +extern VOID +TargetPreResume( + __in PXENVBD_TARGET Target + ); + +extern VOID +TargetPostResume( + __in PXENVBD_TARGET Target + ); + +// StorPort Methods +extern VOID +TargetReset( + __in PXENVBD_TARGET Target + ); + +__checkReturn +extern BOOLEAN +TargetStartIo( + __in PXENVBD_TARGET Target, + __in PSCSI_REQUEST_BLOCK Srb + ); + +extern VOID +TargetSrbPnp( + __in PXENVBD_TARGET Target, + __in PSCSI_PNP_REQUEST_BLOCK Srb + ); + +// PnP Handler +__checkReturn +extern NTSTATUS +TargetDispatchPnp( + __in PXENVBD_TARGET Target, + __in PDEVICE_OBJECT DeviceObject, + __in PIRP Irp + ); + +__drv_maxIRQL(DISPATCH_LEVEL) +extern VOID +TargetIssueDeviceEject( + __in PXENVBD_TARGET Target, + __in __nullterminated const CHAR* Reason + ); + +#endif // _XENVBD_TARGET_H diff --git a/vs2015/xenvbd/xenvbd.vcxproj b/vs2015/xenvbd/xenvbd.vcxproj index abd4b26..4ae5159 100644 --- a/vs2015/xenvbd/xenvbd.vcxproj +++ b/vs2015/xenvbd/xenvbd.vcxproj @@ -69,7 +69,7 @@ - +