[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH 06/26] Refactor target.c
From: Owen Smith <owen.smith@xxxxxxxxxx> Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx> --- src/xenvbd/adapter.c | 52 +- src/xenvbd/blockring.c | 783 +++++--- src/xenvbd/blockring.h | 46 +- src/xenvbd/frontend.c | 1769 ----------------- src/xenvbd/frontend.h | 198 -- src/xenvbd/granter.c | 167 +- src/xenvbd/granter.h | 48 +- src/xenvbd/notifier.c | 334 ---- src/xenvbd/notifier.h | 101 - src/xenvbd/pdoinquiry.c | 530 ----- src/xenvbd/pdoinquiry.h | 64 - src/xenvbd/queue.c | 139 -- src/xenvbd/queue.h | 86 - src/xenvbd/srbext.h | 53 +- src/xenvbd/target.c | 4370 +++++++++++++++++++++++------------------- src/xenvbd/target.h | 188 +- vs2012/xenvbd/xenvbd.vcxproj | 4 - vs2013/xenvbd/xenvbd.vcxproj | 4 - vs2015/xenvbd/xenvbd.vcxproj | 4 - 19 files changed, 3164 insertions(+), 5776 deletions(-) delete mode 100644 src/xenvbd/frontend.c delete mode 100644 src/xenvbd/frontend.h delete mode 100644 src/xenvbd/notifier.c delete mode 100644 src/xenvbd/notifier.h delete mode 100644 src/xenvbd/pdoinquiry.c delete mode 100644 src/xenvbd/pdoinquiry.h delete mode 100644 src/xenvbd/queue.c delete mode 100644 src/xenvbd/queue.h diff --git a/src/xenvbd/adapter.c b/src/xenvbd/adapter.c index 3c5229b..4ce9711 100644 --- a/src/xenvbd/adapter.c +++ b/src/xenvbd/adapter.c @@ -111,7 +111,8 @@ __AdapterFree( IN PVOID Buffer ) { - ExFreePoolWithTag(Buffer, ADAPTER_POOL_TAG); + if (Buffer) + ExFreePoolWithTag(Buffer, ADAPTER_POOL_TAG); } static FORCEINLINE PANSI_STRING @@ -449,7 +450,7 @@ __AdapterEnumerate( } } - if (Missing && !TargetIsMissing(Target)) { + if (Missing && !TargetGetMissing(Target)) { TargetSetMissing(Target, "Device Disappeared"); if (TargetGetDevicePnpState(Target) == Present) TargetSetDevicePnpState(Target, Deleted); @@ -480,7 +481,7 @@ __AdapterEnumerate( continue; status = TargetCreate(Adapter, - Device->Buffer, + Device, &Target); if (status == STATUS_RETRY) NeedReboot = TRUE; @@ -881,7 +882,6 @@ AdapterDebugCallback( ) { PXENVBD_ADAPTER Adapter = Context; - ULONG TargetId; XENBUS_DEBUG(Printf, &Adapter->DebugInterface, @@ -911,24 +911,6 @@ AdapterDebugCallback( Adapter->Completed); BufferDebugCallback(&Adapter->DebugInterface); - - for (TargetId = 0; TargetId < XENVBD_MAX_TARGETS; ++TargetId) { - // no need to use AdapterGetTarget (which is locked at DISPATCH) as called at HIGH_LEVEL - PXENVBD_TARGET Target = Adapter->TargetList[TargetId]; - if (Target == NULL) - continue; - - XENBUS_DEBUG(Printf, &Adapter->DebugInterface, - "ADAPTER: ====> Target[%-3d] : 0x%p\n", - TargetId, Target); - - // call Target's debug callback directly - TargetDebugCallback(Target, &Adapter->DebugInterface); - - XENBUS_DEBUG(Printf, &Adapter->DebugInterface, - "ADAPTER: <==== Target[%-3d] : 0x%p\n", - TargetId, Target); - } } static NTSTATUS @@ -1476,13 +1458,27 @@ __AdapterSrbPnp( IN PSCSI_PNP_REQUEST_BLOCK Srb ) { - if (!(Srb->SrbPnPFlags & SRB_PNP_FLAGS_ADAPTER_REQUEST)) { - PXENVBD_TARGET Target; + PXENVBD_TARGET Target; - Target = AdapterGetTarget(Adapter, Srb->TargetId); - if (Target) { - TargetSrbPnp(Target, Srb); - } + if (Srb->SrbPnPFlags & SRB_PNP_FLAGS_ADAPTER_REQUEST) + return; + + Target = AdapterGetTarget(Adapter, Srb->TargetId); + if (Target == NULL) + return; + + switch (Srb->PnPAction) { + case StorQueryCapabilities: { + PSTOR_DEVICE_CAPABILITIES DeviceCaps = Srb->DataBuffer; + + DeviceCaps->Removable = TargetGetRemovable(Target); + DeviceCaps->EjectSupported = TargetGetRemovable(Target); + DeviceCaps->SurpriseRemovalOK = TargetGetRemovable(Target); + DeviceCaps->UniqueID = 1; + + } break; + default: + break; } } diff --git a/src/xenvbd/blockring.c b/src/xenvbd/blockring.c index bcef877..dac03b5 100644 --- a/src/xenvbd/blockring.c +++ b/src/xenvbd/blockring.c @@ -29,227 +29,218 @@ * SUCH DAMAGE. */ +#include <ntddk.h> +#include <ntstrsafe.h> +#include <stdlib.h> + +#include <xen.h> +#include <gnttab_interface.h> +#include <debug_interface.h> +#include <evtchn_interface.h> + #include "blockring.h" -#include "frontend.h" #include "target.h" #include "adapter.h" +#include "granter.h" +#include "adapter.h" + #include "util.h" #include "debug.h" -#include "srbext.h" -#include "driver.h" -#include <stdlib.h> -#include <xenvbd-ntstrsafe.h> +#include "assert.h" -#define TAG_HEADER 'gaTX' +#define XEN_IO_PROTO_ABI "x86_64-abi" #define XENVBD_MAX_RING_PAGE_ORDER (4) #define XENVBD_MAX_RING_PAGES (1 << XENVBD_MAX_RING_PAGE_ORDER) struct _XENVBD_BLOCKRING { - PXENVBD_FRONTEND Frontend; - BOOLEAN Connected; - BOOLEAN Enabled; - - XENBUS_STORE_INTERFACE StoreInterface; - - KSPIN_LOCK Lock; - PMDL Mdl; - blkif_sring_t* SharedRing; - blkif_front_ring_t FrontRing; - ULONG DeviceId; - ULONG Order; - PVOID Grants[XENVBD_MAX_RING_PAGES]; - ULONG Submitted; - ULONG Received; + PXENVBD_TARGET Target; + BOOLEAN Connected; + BOOLEAN Enabled; + + XENBUS_STORE_INTERFACE StoreInterface; + XENBUS_DEBUG_INTERFACE DebugInterface; + XENBUS_EVTCHN_INTERFACE EvtchnInterface; + + PXENBUS_DEBUG_CALLBACK DebugCallback; + + KSPIN_LOCK Lock; + PMDL Mdl; + blkif_sring_t* Shared; + blkif_front_ring_t Front; + ULONG Order; + PVOID Grants[XENVBD_MAX_RING_PAGES]; + + PXENBUS_EVTCHN_CHANNEL Channel; + KDPC Dpc; + + ULONG Submitted; + ULONG Completed; + ULONG Interrupts; + ULONG Dpcs; }; -#define MAX_NAME_LEN 64 -#define BLOCKRING_POOL_TAG 'gnRX' - -#define XEN_IO_PROTO_ABI "x86_64-abi" +#define BLOCKRING_POOL_TAG 'gnRX' +#define xen_mb KeMemoryBarrier +#define xen_wmb KeMemoryBarrier +#define xen_rmb KeMemoryBarrier static FORCEINLINE PVOID __BlockRingAllocate( - IN ULONG Length + IN ULONG Size ) { - return __AllocatePoolWithTag(NonPagedPool, Length, BLOCKRING_POOL_TAG); + PVOID Buffer; + Buffer = ExAllocatePoolWithTag(NonPagedPool, + Size, + BLOCKRING_POOL_TAG); + if (Buffer) + RtlZeroMemory(Buffer, Size); + return Buffer; } static FORCEINLINE VOID __BlockRingFree( - IN PVOID Buffer + IN PVOID Buffer ) { if (Buffer) - __FreePoolWithTag(Buffer, BLOCKRING_POOL_TAG); -} - -static FORCEINLINE VOID -xen_mb() -{ - KeMemoryBarrier(); - _ReadWriteBarrier(); + ExFreePoolWithTag(Buffer, BLOCKRING_POOL_TAG); } -static FORCEINLINE VOID -xen_wmb() -{ - KeMemoryBarrier(); - _WriteBarrier(); -} +KSERVICE_ROUTINE BlockRingInterrupt; -static FORCEINLINE PFN_NUMBER -__Pfn( - __in PVOID VirtAddr +BOOLEAN +BlockRingInterrupt( + __in PKINTERRUPT Interrupt, + _In_opt_ PVOID Context ) { - return (PFN_NUMBER)(ULONG_PTR)(MmGetPhysicalAddress(VirtAddr).QuadPart >> PAGE_SHIFT); -} + PXENVBD_BLOCKRING BlockRing = Context; + + UNREFERENCED_PARAMETER(Interrupt); -static FORCEINLINE ULONG64 -__BlockRingGetTag( - IN PXENVBD_BLOCKRING BlockRing, - IN PXENVBD_REQUEST Request - ) -{ - UNREFERENCED_PARAMETER(BlockRing); - return ((ULONG64)TAG_HEADER << 32) | (ULONG64)Request->Id; + ASSERT(BlockRing != NULL); + + ++BlockRing->Interrupts; + if (KeInsertQueueDpc(&BlockRing->Dpc, NULL, NULL)) + ++BlockRing->Dpcs; + + return TRUE; } -static FORCEINLINE BOOLEAN -__BlockRingPutTag( - IN PXENVBD_BLOCKRING BlockRing, - IN ULONG64 Id, - OUT PULONG Tag +KDEFERRED_ROUTINE BlockRingDpc; + +VOID +BlockRingDpc( + __in PKDPC Dpc, + __in_opt PVOID Context, + __in_opt PVOID Arg1, + __in_opt PVOID Arg2 ) { - ULONG Header = (ULONG)((Id >> 32) & 0xFFFFFFFF); + PXENVBD_BLOCKRING BlockRing = Context; - UNREFERENCED_PARAMETER(BlockRing); + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(Arg1); + UNREFERENCED_PARAMETER(Arg2); - *Tag = (ULONG)(Id & 0xFFFFFFFF); - if (Header != TAG_HEADER) { - Error("PUT_TAG (%llx) TAG_HEADER (%08x%08x)\n", Id, Header, *Tag); - return FALSE; - } + ASSERT(BlockRing != NULL); - return TRUE; + (VOID) BlockRingPoll(BlockRing); + + XENBUS_EVTCHN(Unmask, + &BlockRing->EvtchnInterface, + BlockRing->Channel, + FALSE); } -static FORCEINLINE VOID -__BlockRingInsert( - IN PXENVBD_BLOCKRING BlockRing, - IN PXENVBD_REQUEST Request, - IN blkif_request_t* req +static DECLSPEC_NOINLINE VOID +BlockRingDebugCallback( + IN PVOID Context, + IN BOOLEAN Crashing ) { - PXENVBD_GRANTER Granter = FrontendGetGranter(BlockRing->Frontend); + PXENVBD_BLOCKRING BlockRing = Context; + PXENVBD_GRANTER Granter; + ULONG Port; + ULONG Grant; + ULONG Index; - switch (Request->Operation) { - case BLKIF_OP_READ: - case BLKIF_OP_WRITE: - if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { - // Indirect - ULONG PageIdx; - ULONG SegIdx; - PLIST_ENTRY PageEntry; - PLIST_ENTRY SegEntry; - blkif_request_indirect_t* req_indirect; - - req_indirect = (blkif_request_indirect_t*)req; - req_indirect->operation = BLKIF_OP_INDIRECT; - req_indirect->indirect_op = Request->Operation; - req_indirect->nr_segments = Request->NrSegments; - req_indirect->id = __BlockRingGetTag(BlockRing, Request); - req_indirect->sector_number = Request->FirstSector; - req_indirect->handle = (USHORT)BlockRing->DeviceId; - - for (PageIdx = 0, - PageEntry = Request->Indirects.Flink, - SegEntry = Request->Segments.Flink; - PageIdx < BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST && - PageEntry != &Request->Indirects && - SegEntry != &Request->Segments; - ++PageIdx, PageEntry = PageEntry->Flink) { - PXENVBD_INDIRECT Page = CONTAINING_RECORD(PageEntry, XENVBD_INDIRECT, Entry); - - req_indirect->indirect_grefs[PageIdx] = GranterReference(Granter, Page->Grant); - - for (SegIdx = 0; - SegIdx < XENVBD_MAX_SEGMENTS_PER_PAGE && - SegEntry != &Request->Segments; - ++SegIdx, SegEntry = SegEntry->Flink) { - PXENVBD_SEGMENT Segment = CONTAINING_RECORD(SegEntry, XENVBD_SEGMENT, Entry); + UNREFERENCED_PARAMETER(Crashing); - Page->Page[SegIdx].GrantRef = GranterReference(Granter, Segment->Grant); - Page->Page[SegIdx].First = Segment->FirstSector; - Page->Page[SegIdx].Last = Segment->LastSector; - } - } - } else { - // Direct - ULONG Index; - PLIST_ENTRY Entry; - - req->operation = Request->Operation; - req->nr_segments = (UCHAR)Request->NrSegments; - req->handle = (USHORT)BlockRing->DeviceId; - req->id = __BlockRingGetTag(BlockRing, Request); - req->sector_number = Request->FirstSector; - - for (Index = 0, Entry = Request->Segments.Flink; - Index < BLKIF_MAX_SEGMENTS_PER_REQUEST && - Entry != &Request->Segments; - ++Index, Entry = Entry->Flink) { - PXENVBD_SEGMENT Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); - req->seg[Index].gref = GranterReference(Granter, Segment->Grant); - req->seg[Index].first_sect = Segment->FirstSector; - req->seg[Index].last_sect = Segment->LastSector; - } - } - break; - - case BLKIF_OP_WRITE_BARRIER: - case BLKIF_OP_FLUSH_DISKCACHE: - req->operation = Request->Operation; - req->nr_segments = 0; - req->handle = (USHORT)BlockRing->DeviceId; - req->id = __BlockRingGetTag(BlockRing, Request); - req->sector_number = Request->FirstSector; - break; + XENBUS_DEBUG(Printf, + &BlockRing->DebugInterface, + "Order: %u\n", + BlockRing->Order); - case BLKIF_OP_DISCARD: { - blkif_request_discard_t* req_discard; - req_discard = (blkif_request_discard_t*)req; - req_discard->operation = BLKIF_OP_DISCARD; - req_discard->flag = Request->Flags; - req_discard->handle = (USHORT)BlockRing->DeviceId; - req_discard->id = __BlockRingGetTag(BlockRing, Request); - req_discard->sector_number = Request->FirstSector; - req_discard->nr_sectors = Request->NrSectors; - } break; + Granter = TargetGetGranter(BlockRing->Target); + for (Index = 0; Index < (1ul << BlockRing->Order); ++Index) { + Grant = GranterReference(Granter, BlockRing->Grants[Index]); - default: - ASSERT(FALSE); - break; + XENBUS_DEBUG(Printf, + &BlockRing->DebugInterface, + "Grant[%02u] : 0x%p (%u)\n", + Index, + BlockRing->Grants[Index], + Grant); } - ++BlockRing->Submitted; + + XENBUS_DEBUG(Printf, + &BlockRing->DebugInterface, + "Shared:0x%p : req_prod:%u, req_event:%u, rsp_prod:%u, rsp_event:%u\n", + BlockRing->Shared, + BlockRing->Shared->req_prod, + BlockRing->Shared->req_event, + BlockRing->Shared->rsp_prod, + BlockRing->Shared->rsp_event); + + XENBUS_DEBUG(Printf, + &BlockRing->DebugInterface, + "Front: req_prod_pvt:%u, rsp_cons:%u, nr_ents:%u, sring:0x%p\n", + BlockRing->Front.req_prod_pvt, + BlockRing->Front.rsp_cons, + BlockRing->Front.nr_ents, + BlockRing->Front.sring); + + XENBUS_DEBUG(Printf, + &BlockRing->DebugInterface, + "Submitted: %u, Completed: %u\n", + BlockRing->Submitted, + BlockRing->Completed); + + Port = XENBUS_EVTCHN(GetPort, + &BlockRing->EvtchnInterface, + BlockRing->Channel); + + XENBUS_DEBUG(Printf, + &BlockRing->DebugInterface, + "Channel: 0x%p (%u)\n", + BlockRing->Channel, + Port); + + XENBUS_DEBUG(Printf, + &BlockRing->DebugInterface, + "Interrupts: %u, DPCs: %u\n", + BlockRing->Interrupts, + BlockRing->Dpcs); + + BlockRing->Interrupts = 0; + BlockRing->Dpcs = 0; } NTSTATUS BlockRingCreate( - IN PXENVBD_FRONTEND Frontend, - IN ULONG DeviceId, - OUT PXENVBD_BLOCKRING* BlockRing + IN PXENVBD_TARGET Target, + OUT PXENVBD_BLOCKRING* BlockRing ) { *BlockRing = __BlockRingAllocate(sizeof(XENVBD_BLOCKRING)); if (*BlockRing == NULL) goto fail1; - (*BlockRing)->Frontend = Frontend; - (*BlockRing)->DeviceId = DeviceId; + (*BlockRing)->Target = Target; KeInitializeSpinLock(&(*BlockRing)->Lock); + KeInitializeDpc(&(*BlockRing)->Dpc, BlockRingDpc, *BlockRing); return STATUS_SUCCESS; @@ -259,12 +250,12 @@ fail1: VOID BlockRingDestroy( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ) { - BlockRing->Frontend = NULL; - BlockRing->DeviceId = 0; + BlockRing->Target = NULL; RtlZeroMemory(&BlockRing->Lock, sizeof(KSPIN_LOCK)); + RtlZeroMemory(&BlockRing->Dpc, sizeof(KDPC)); ASSERT(IsZeroMemory(BlockRing, sizeof(XENVBD_BLOCKRING))); @@ -273,122 +264,201 @@ BlockRingDestroy( NTSTATUS BlockRingConnect( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ) { - NTSTATUS status; - PCHAR Value; - ULONG Index, RingPages; - PXENVBD_ADAPTER Adapter = TargetGetAdapter(FrontendGetTarget(BlockRing->Frontend)); - PXENVBD_GRANTER Granter = FrontendGetGranter(BlockRing->Frontend); + PXENVBD_GRANTER Granter; + PXENVBD_ADAPTER Adapter; + PCHAR Buffer; + ULONG Index; + NTSTATUS status; ASSERT(BlockRing->Connected == FALSE); + Adapter = TargetGetAdapter(BlockRing->Target); + AdapterGetStoreInterface(Adapter, &BlockRing->StoreInterface); - + AdapterGetDebugInterface(Adapter, &BlockRing->DebugInterface); + AdapterGetEvtchnInterface(Adapter, &BlockRing->EvtchnInterface); + status = XENBUS_STORE(Acquire, &BlockRing->StoreInterface); if (!NT_SUCCESS(status)) goto fail1; - status = FrontendStoreReadBackend(BlockRing->Frontend, "max-ring-page-order", &Value); + status = XENBUS_DEBUG(Acquire, &BlockRing->DebugInterface); + if (!NT_SUCCESS(status)) + goto fail2; + + status = XENBUS_EVTCHN(Acquire, &BlockRing->EvtchnInterface); + if (!NT_SUCCESS(status)) + goto fail3; + + status = XENBUS_STORE(Read, + &BlockRing->StoreInterface, + NULL, + TargetGetBackendPath(BlockRing->Target), + "max-ring-page-order", + &Buffer); if (NT_SUCCESS(status)) { - BlockRing->Order = __min(strtoul(Value, NULL, 10), XENVBD_MAX_RING_PAGE_ORDER); - FrontendStoreFree(BlockRing->Frontend, Value); + BlockRing->Order = strtoul(Buffer, NULL, 10); + BlockRing->Order = min(BlockRing->Order, XENVBD_MAX_RING_PAGE_ORDER); + + XENBUS_STORE(Free, + &BlockRing->StoreInterface, + Buffer); } else { BlockRing->Order = 0; } - BlockRing->Mdl = __AllocatePages(1 << BlockRing->Order); - status = STATUS_NO_MEMORY; + BlockRing->Mdl = __AllocatePages(1 << BlockRing->Order); if (BlockRing->Mdl == NULL) - goto fail2; + goto fail4; - BlockRing->SharedRing = MmGetSystemAddressForMdlSafe(BlockRing->Mdl, - NormalPagePriority); - ASSERT(BlockRing->SharedRing != NULL); + BlockRing->Shared = MmGetSystemAddressForMdlSafe(BlockRing->Mdl, NormalPagePriority); + ASSERT(BlockRing->Shared != NULL); #pragma warning(push) #pragma warning(disable: 4305) #pragma warning(disable: 4311) - SHARED_RING_INIT(BlockRing->SharedRing); - FRONT_RING_INIT(&BlockRing->FrontRing, BlockRing->SharedRing, PAGE_SIZE << BlockRing->Order); + SHARED_RING_INIT(BlockRing->Shared); + FRONT_RING_INIT(&BlockRing->Front, BlockRing->Shared, PAGE_SIZE << BlockRing->Order); #pragma warning(pop) - RingPages = (1 << BlockRing->Order); - for (Index = 0; Index < RingPages; ++Index) { - status = GranterGet(Granter, __Pfn((PUCHAR)BlockRing->SharedRing + (Index * PAGE_SIZE)), - FALSE, &BlockRing->Grants[Index]); + Granter = TargetGetGranter(BlockRing->Target); + for (Index = 0; Index < (1ul << BlockRing->Order); ++Index) { + status = GranterGet(Granter, + MmGetMdlPfnArray(BlockRing->Mdl)[Index], + FALSE, + &BlockRing->Grants[Index]); if (!NT_SUCCESS(status)) - goto fail3; + goto fail5; } + status = STATUS_NO_MEMORY; + BlockRing->Channel = XENBUS_EVTCHN(Open, + &BlockRing->EvtchnInterface, + XENBUS_EVTCHN_TYPE_UNBOUND, + BlockRingInterrupt, + BlockRing, + TargetGetBackendId(BlockRing->Target), + TRUE); + if (BlockRing->Channel == NULL) + goto fail6; + + status = XENBUS_DEBUG(Register, + &BlockRing->DebugInterface, + __MODULE__, + BlockRingDebugCallback, + BlockRing, + &BlockRing->DebugCallback); + if (!NT_SUCCESS(status)) + goto fail7; + + XENBUS_EVTCHN(Unmask, + &BlockRing->EvtchnInterface, + BlockRing->Channel, + FALSE); + BlockRing->Connected = TRUE; return STATUS_SUCCESS; -fail3: - for (Index = 0; Index < XENVBD_MAX_RING_PAGES; ++Index) { - if (BlockRing->Grants[Index]) - GranterPut(Granter, BlockRing->Grants[Index]); - BlockRing->Grants[Index] = 0; +fail7: + Error("fail7\n"); + XENBUS_EVTCHN(Close, + &BlockRing->EvtchnInterface, + BlockRing->Channel); + BlockRing->Channel = NULL; +fail6: + Error("fail6\n"); +fail5: + Error("fail5\n"); + for (Index = 0; Index < (1ul << BlockRing->Order); ++Index) { + if (BlockRing->Grants[Index] == NULL) + continue; + + GranterPut(Granter, BlockRing->Grants[Index]); + BlockRing->Grants[Index] = NULL; } - RtlZeroMemory(&BlockRing->FrontRing, sizeof(BlockRing->FrontRing)); + RtlZeroMemory(&BlockRing->Front, sizeof(blkif_front_ring_t)); + BlockRing->Shared = NULL; + __FreePages(BlockRing->Mdl); - BlockRing->SharedRing = NULL; BlockRing->Mdl = NULL; - +fail4: + Error("fail4\n"); + XENBUS_EVTCHN(Release, &BlockRing->EvtchnInterface); + RtlZeroMemory(&BlockRing->EvtchnInterface, sizeof(XENBUS_EVTCHN_INTERFACE)); +fail3: + Error("fail3\n"); + XENBUS_DEBUG(Release, &BlockRing->DebugInterface); + RtlZeroMemory(&BlockRing->DebugInterface, sizeof(XENBUS_DEBUG_INTERFACE)); fail2: + Error("fail2\n"); + XENBUS_STORE(Release, &BlockRing->StoreInterface); + RtlZeroMemory(&BlockRing->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); fail1: - return status; + Error("fail1 %08x\n", status); + return status; } NTSTATUS BlockRingStoreWrite( - IN PXENVBD_BLOCKRING BlockRing, - IN PXENBUS_STORE_TRANSACTION Transaction, - IN PCHAR FrontendPath + IN PXENVBD_BLOCKRING BlockRing, + IN PVOID Transaction ) { - PXENVBD_GRANTER Granter = FrontendGetGranter(BlockRing->Frontend); - NTSTATUS status; + PXENVBD_GRANTER Granter; + ULONG Port; + ULONG Grant; + NTSTATUS status; + Granter = TargetGetGranter(BlockRing->Target); if (BlockRing->Order == 0) { + Grant = GranterReference(Granter, BlockRing->Grants[0]); + status = XENBUS_STORE(Printf, &BlockRing->StoreInterface, Transaction, - FrontendPath, + TargetGetPath(BlockRing->Target), "ring-ref", "%u", - GranterReference(Granter, BlockRing->Grants[0])); + Grant); if (!NT_SUCCESS(status)) return status; } else { - ULONG Index, RingPages; + ULONG Index; status = XENBUS_STORE(Printf, &BlockRing->StoreInterface, Transaction, - FrontendPath, + TargetGetPath(BlockRing->Target), "ring-page-order", "%u", BlockRing->Order); if (!NT_SUCCESS(status)) return status; - RingPages = (1 << BlockRing->Order); - for (Index = 0; Index < RingPages; ++Index) { - CHAR Name[MAX_NAME_LEN+1]; - status = RtlStringCchPrintfA(Name, MAX_NAME_LEN, "ring-ref%u", Index); + for (Index = 0; Index < (1ul << BlockRing->Order); ++Index) { + CHAR Name[sizeof("ring-refXX")]; + + status = RtlStringCbPrintfA(Name, + sizeof(Name), + "ring-ref%u", + Index); if (!NT_SUCCESS(status)) return status; + + Grant = GranterReference(Granter, BlockRing->Grants[Index]); + status = XENBUS_STORE(Printf, &BlockRing->StoreInterface, Transaction, - FrontendPath, + TargetGetPath(BlockRing->Target), Name, "%u", - GranterReference(Granter, BlockRing->Grants[Index])); + Grant); if (!NT_SUCCESS(status)) return status; } @@ -397,28 +467,46 @@ BlockRingStoreWrite( status = XENBUS_STORE(Printf, &BlockRing->StoreInterface, Transaction, - FrontendPath, + TargetGetPath(BlockRing->Target), "protocol", + "%s", XEN_IO_PROTO_ABI); if (!NT_SUCCESS(status)) return status; + Port = XENBUS_EVTCHN(GetPort, + &BlockRing->EvtchnInterface, + BlockRing->Channel); + + status = XENBUS_STORE(Printf, + &BlockRing->StoreInterface, + Transaction, + TargetGetPath(BlockRing->Target), + "event-channel", + "%u", + Port); + if (!NT_SUCCESS(status)) + return status; + return STATUS_SUCCESS; } VOID BlockRingEnable( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ) { ASSERT(BlockRing->Enabled == FALSE); - BlockRing->Enabled = TRUE; + + XENBUS_EVTCHN(Trigger, + &BlockRing->EvtchnInterface, + BlockRing->Channel); } VOID BlockRingDisable( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ) { ASSERT(BlockRing->Enabled == TRUE); @@ -428,30 +516,44 @@ BlockRingDisable( VOID BlockRingDisconnect( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ) { - ULONG Index; - PXENVBD_GRANTER Granter = FrontendGetGranter(BlockRing->Frontend); + PXENVBD_GRANTER Granter; + ULONG Index; ASSERT(BlockRing->Connected == TRUE); - BlockRing->Submitted = 0; - BlockRing->Received = 0; + XENBUS_DEBUG(Deregister, + &BlockRing->DebugInterface, + BlockRing->DebugCallback); + BlockRing->DebugCallback = NULL; - for (Index = 0; Index < XENVBD_MAX_RING_PAGES; ++Index) { - if (BlockRing->Grants[Index]) { - GranterPut(Granter, BlockRing->Grants[Index]); - } - BlockRing->Grants[Index] = 0; + XENBUS_EVTCHN(Close, + &BlockRing->EvtchnInterface, + BlockRing->Channel); + BlockRing->Channel = NULL; + + Granter = TargetGetGranter(BlockRing->Target); + for (Index = 0; Index < (1ul << BlockRing->Order); ++Index) { + if (BlockRing->Grants[Index] == NULL) + continue; + + GranterPut(Granter, BlockRing->Grants[Index]); + BlockRing->Grants[Index] = NULL; } - RtlZeroMemory(&BlockRing->FrontRing, sizeof(BlockRing->FrontRing)); + RtlZeroMemory(&BlockRing->Front, sizeof(blkif_front_ring_t)); + BlockRing->Shared = NULL; + __FreePages(BlockRing->Mdl); - BlockRing->SharedRing = NULL; BlockRing->Mdl = NULL; - BlockRing->Order = 0; + XENBUS_EVTCHN(Release, &BlockRing->EvtchnInterface); + RtlZeroMemory(&BlockRing->EvtchnInterface, sizeof(XENBUS_EVTCHN_INTERFACE)); + + XENBUS_DEBUG(Release, &BlockRing->DebugInterface); + RtlZeroMemory(&BlockRing->DebugInterface, sizeof(XENBUS_DEBUG_INTERFACE)); XENBUS_STORE(Release, &BlockRing->StoreInterface); RtlZeroMemory(&BlockRing->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); @@ -459,60 +561,11 @@ BlockRingDisconnect( BlockRing->Connected = FALSE; } -VOID -BlockRingDebugCallback( - IN PXENVBD_BLOCKRING BlockRing, - IN PXENBUS_DEBUG_INTERFACE Debug - ) -{ - ULONG Index; - PXENVBD_GRANTER Granter = FrontendGetGranter(BlockRing->Frontend); - - XENBUS_DEBUG(Printf, Debug, - "BLOCKRING: Requests : %d / %d\n", - BlockRing->Submitted, - BlockRing->Received); - - XENBUS_DEBUG(Printf, Debug, - "BLOCKRING: SharedRing : 0x%p\n", - BlockRing->SharedRing); - - if (BlockRing->SharedRing) { - XENBUS_DEBUG(Printf, Debug, - "BLOCKRING: SharedRing : %d / %d - %d / %d\n", - BlockRing->SharedRing->req_prod, - BlockRing->SharedRing->req_event, - BlockRing->SharedRing->rsp_prod, - BlockRing->SharedRing->rsp_event); - } - - XENBUS_DEBUG(Printf, Debug, - "BLOCKRING: FrontRing : %d / %d (%d)\n", - BlockRing->FrontRing.req_prod_pvt, - BlockRing->FrontRing.rsp_cons, - BlockRing->FrontRing.nr_ents); - - XENBUS_DEBUG(Printf, Debug, - "BLOCKRING: Order : %d\n", - BlockRing->Order); - for (Index = 0; Index < (1ul << BlockRing->Order); ++Index) { - XENBUS_DEBUG(Printf, Debug, - "BLOCKRING: Grants[%-2d] : 0x%p (%u)\n", - Index, - BlockRing->Grants[Index], - GranterReference(Granter, BlockRing->Grants[Index])); - } - - BlockRing->Submitted = BlockRing->Received = 0; -} - -VOID +ULONG BlockRingPoll( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ) { - PXENVBD_TARGET Target = FrontendGetTarget(BlockRing->Frontend); - ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL); KeAcquireSpinLockAtDpcLevel(&BlockRing->Lock); @@ -527,8 +580,8 @@ BlockRingPoll( KeMemoryBarrier(); - rsp_prod = BlockRing->SharedRing->rsp_prod; - rsp_cons = BlockRing->FrontRing.rsp_cons; + rsp_prod = BlockRing->Shared->rsp_prod; + rsp_cons = BlockRing->Front.rsp_cons; KeMemoryBarrier(); @@ -536,56 +589,170 @@ BlockRingPoll( break; while (rsp_cons != rsp_prod) { - blkif_response_t* Response; - ULONG Tag; - - Response = RING_GET_RESPONSE(&BlockRing->FrontRing, rsp_cons); - ++rsp_cons; - - if (__BlockRingPutTag(BlockRing, Response->id, &Tag)) { - ++BlockRing->Received; - TargetCompleteResponse(Target, Tag, Response->status); + blkif_response_t* rsp; + + rsp = RING_GET_RESPONSE(&BlockRing->Front, rsp_cons); + if (rsp->id == 0) { + Warning("Bad Response (%llu, %u, &d) @ slot %u\n", + rsp->id, + rsp->operation, + rsp->status, + rsp_cons & (RING_SIZE(&BlockRing->Front) - 1)); + // dump submitted reqs? + } else { + TargetCompleteResponse(BlockRing->Target, + rsp->id, + rsp->status); + ++BlockRing->Completed; } + ++rsp_cons; - RtlZeroMemory(Response, sizeof(union blkif_sring_entry)); + RtlZeroMemory(rsp, sizeof(union blkif_sring_entry)); } KeMemoryBarrier(); - BlockRing->FrontRing.rsp_cons = rsp_cons; - BlockRing->SharedRing->rsp_event = rsp_cons + 1; + BlockRing->Front.rsp_cons = rsp_cons; + BlockRing->Shared->rsp_event = rsp_cons + 1; } done: KeReleaseSpinLockFromDpcLevel(&BlockRing->Lock); + + // submit all prepared requests, prepare the next srb + TargetSubmitRequests(BlockRing->Target); + + return BlockRing->Submitted - BlockRing->Completed; } BOOLEAN BlockRingSubmit( - IN PXENVBD_BLOCKRING BlockRing, - IN PXENVBD_REQUEST Request + IN PXENVBD_BLOCKRING BlockRing, + IN PXENVBD_REQUEST Request ) { - KIRQL Irql; - blkif_request_t* req; - BOOLEAN Notify; + PLIST_ENTRY ListEntry; + ULONG Index; + PXENVBD_GRANTER Granter; + KIRQL Irql; + blkif_request_t* req; + BOOLEAN Notify; KeAcquireSpinLock(&BlockRing->Lock, &Irql); - if (RING_FULL(&BlockRing->FrontRing)) { + if (RING_FULL(&BlockRing->Front)) { KeReleaseSpinLock(&BlockRing->Lock, Irql); return FALSE; } - req = RING_GET_REQUEST(&BlockRing->FrontRing, BlockRing->FrontRing.req_prod_pvt); - __BlockRingInsert(BlockRing, Request, req); + req = RING_GET_REQUEST(&BlockRing->Front, BlockRing->Front.req_prod_pvt); + ++BlockRing->Front.req_prod_pvt; + ++BlockRing->Submitted; + + Granter = TargetGetGranter(BlockRing->Target); + switch (Request->Operation) { + case BLKIF_OP_DISCARD: { + blkif_request_discard_t* req_d; + req_d = (blkif_request_discard_t*)req; + req_d->operation = BLKIF_OP_DISCARD; + req_d->flag = Request->Flags; + req_d->handle = (USHORT)TargetGetDeviceId(BlockRing->Target); + req_d->id = Request->Id; + req_d->sector_number = Request->FirstSector; + req_d->nr_sectors = Request->NrSectors; + } break; + + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { + // Indirect + blkif_request_indirect_t* req_i; + ULONG PageIdx; + ULONG SegIdx; + PLIST_ENTRY PageEntry; + PLIST_ENTRY SegEntry; + + req_i = (blkif_request_indirect_t*)req; + req_i->operation = BLKIF_OP_INDIRECT; + req_i->indirect_op = Request->Operation; + req_i->nr_segments = Request->NrSegments; + req_i->id = Request->Id; + req_i->sector_number = Request->FirstSector; + req_i->handle = (USHORT)TargetGetDeviceId(BlockRing->Target); + + PageEntry = Request->Indirects.Flink; + SegEntry = Request->Segments.Flink; + for (PageIdx = 0; PageIdx < BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST; ++PageIdx) { + PXENVBD_INDIRECT Page; + + if (PageEntry != &Request->Indirects) + break; + if (SegEntry != &Request->Segments) + break; + + Page = CONTAINING_RECORD(PageEntry, XENVBD_INDIRECT, ListEntry); + req_i->indirect_grefs[PageIdx] = GranterReference(Granter, Page->Grant); + + for (SegIdx = 0; SegIdx < XENVBD_MAX_SEGMENTS_PER_PAGE; ++SegIdx) { + PXENVBD_SEGMENT Segment; + + if (SegEntry != &Request->Segments) + break; + + Segment = CONTAINING_RECORD(SegEntry, XENVBD_SEGMENT, ListEntry); + Page->Page[SegIdx].GrantRef = GranterReference(Granter, Segment->Grant); + Page->Page[SegIdx].First = Segment->FirstSector; + Page->Page[SegIdx].Last = Segment->LastSector; + + SegEntry = SegEntry->Flink; + } + + PageEntry = PageEntry->Flink; + } + break; // out of switch + } + // intentional fall through + case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + default: + req->operation = Request->Operation; + req->nr_segments = (UCHAR)Request->NrSegments; + req->handle = (USHORT)TargetGetDeviceId(BlockRing->Target); + req->id = Request->Id; + req->sector_number = Request->FirstSector; + + for (ListEntry = Request->Segments.Flink, Index = 0; + ListEntry != &Request->Segments && Index < BLKIF_MAX_SEGMENTS_PER_REQUEST; + ListEntry = ListEntry->Flink, ++Index) { + PXENVBD_SEGMENT Segment = CONTAINING_RECORD(ListEntry, XENVBD_SEGMENT, ListEntry); + ULONG Grant; + + Grant = GranterReference(Granter, Segment->Grant); + + req->seg[Index].first_sect = Segment->FirstSector; + req->seg[Index].last_sect = Segment->LastSector; + req->seg[Index].gref = Grant; + } + break; + } + KeMemoryBarrier(); - ++BlockRing->FrontRing.req_prod_pvt; - RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&BlockRing->FrontRing, Notify); + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&BlockRing->Front, Notify); KeReleaseSpinLock(&BlockRing->Lock, Irql); - if (Notify) - NotifierSend(FrontendGetNotifier(BlockRing->Frontend)); + if (Notify) { + XENBUS_EVTCHN(Send, + &BlockRing->EvtchnInterface, + BlockRing->Channel); + } return TRUE; } + +VOID +BlockRingKick( + IN PXENVBD_BLOCKRING BlockRing + ) +{ + KeInsertQueueDpc(&BlockRing->Dpc, NULL, NULL); +} diff --git a/src/xenvbd/blockring.h b/src/xenvbd/blockring.h index 1117d73..2660e47 100644 --- a/src/xenvbd/blockring.h +++ b/src/xenvbd/blockring.h @@ -32,66 +32,64 @@ #ifndef _XENVBD_BLOCKRING_H #define _XENVBD_BLOCKRING_H +#include <ntddk.h> + typedef struct _XENVBD_BLOCKRING XENVBD_BLOCKRING, *PXENVBD_BLOCKRING; -#include "frontend.h" -#include <debug_interface.h> -#include <store_interface.h> +#include "target.h" +#include "srbext.h" extern NTSTATUS BlockRingCreate( - IN PXENVBD_FRONTEND Frontend, - IN ULONG DeviceId, - OUT PXENVBD_BLOCKRING* BlockRing + IN PXENVBD_TARGET Target, + OUT PXENVBD_BLOCKRING* BlockRing ); extern VOID BlockRingDestroy( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ); extern NTSTATUS BlockRingConnect( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ); extern NTSTATUS BlockRingStoreWrite( - IN PXENVBD_BLOCKRING BlockRing, - IN PXENBUS_STORE_TRANSACTION Transaction, - IN PCHAR FrontendPath + IN PXENVBD_BLOCKRING BlockRing, + IN PVOID Transaction ); extern VOID BlockRingEnable( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ); extern VOID BlockRingDisable( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ); extern VOID BlockRingDisconnect( - IN PXENVBD_BLOCKRING BlockRing - ); - -extern VOID -BlockRingDebugCallback( - IN PXENVBD_BLOCKRING BlockRing, - IN PXENBUS_DEBUG_INTERFACE Debug + IN PXENVBD_BLOCKRING BlockRing ); -extern VOID +extern ULONG BlockRingPoll( - IN PXENVBD_BLOCKRING BlockRing + IN PXENVBD_BLOCKRING BlockRing ); extern BOOLEAN BlockRingSubmit( - IN PXENVBD_BLOCKRING BlockRing, - IN PXENVBD_REQUEST Request + IN PXENVBD_BLOCKRING BlockRing, + IN PXENVBD_REQUEST Request + ); + +extern VOID +BlockRingKick( + IN PXENVBD_BLOCKRING BlockRing ); #endif // _XENVBD_BLOCKRING_H diff --git a/src/xenvbd/frontend.c b/src/xenvbd/frontend.c deleted file mode 100644 index 691ea3a..0000000 --- a/src/xenvbd/frontend.c +++ /dev/null @@ -1,1769 +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 <ntddk.h> -#include <ntstrsafe.h> - -#include "frontend.h" -#include "registry.h" -#include "driver.h" -#include "adapter.h" -#include "pdoinquiry.h" -#include "srbext.h" -#include "debug.h" -#include "assert.h" -#include "util.h" -#include "names.h" -#include "notifier.h" -#include "blockring.h" -#include "granter.h" -#include "thread.h" -#include <store_interface.h> -#include <suspend_interface.h> - -#include <stdlib.h> - -struct _XENVBD_FRONTEND { - // Frontend - PXENVBD_TARGET Target; - ULONG TargetId; - ULONG DeviceId; - CHAR FrontendPath[sizeof("device/vbd/XXXXXXXX")]; - PCHAR BackendPath; - CHAR TargetPath[sizeof("data/scsi/target/XXXX")]; - USHORT BackendId; - XENVBD_STATE State; - KSPIN_LOCK StateLock; - - XENVBD_CAPS Caps; - XENVBD_FEATURES Features; - XENVBD_DISKINFO DiskInfo; - PVOID Inquiry; - - // Interfaces to XenBus - XENBUS_STORE_INTERFACE StoreInterface; - XENBUS_SUSPEND_INTERFACE SuspendInterface; - - PXENBUS_SUSPEND_CALLBACK SuspendLateCallback; - - // Ring - PXENVBD_NOTIFIER Notifier; - PXENVBD_BLOCKRING BlockRing; - PXENVBD_GRANTER Granter; - - // Backend State Watch - BOOLEAN Active; - PXENVBD_THREAD BackendThread; - PXENBUS_STORE_WATCH BackendWatch; -}; - -#define DOMID_INVALID (0x7FF4U) - -static const PCHAR -__XenvbdStateName( - IN XENVBD_STATE State - ) -{ - switch (State) { - case XENVBD_STATE_INVALID: return "STATE_INVALID"; - case XENVBD_INITIALIZED: return "INITIALIZED"; - case XENVBD_CLOSING: return "CLOSING"; - case XENVBD_CLOSED: return "CLOSED"; - case XENVBD_PREPARED: return "PREPARED"; - case XENVBD_CONNECTED: return "CONNECTED"; - case XENVBD_ENABLED: return "ENABLED"; - default: return "UNKNOWN"; - } -} -//============================================================================= -#define FRONTEND_POOL_TAG 'tnFX' -__checkReturn -__drv_allocatesMem(mem) -__bcount(Size) -static FORCEINLINE PVOID -#pragma warning(suppress: 28195) -__FrontendAlloc( - __in ULONG Size - ) -{ - return __AllocatePoolWithTag(NonPagedPool, Size, FRONTEND_POOL_TAG); -} - -static FORCEINLINE VOID -#pragma warning(suppress: 28197) -__FrontendFree( - __in __drv_freesMem(mem) PVOID Buffer - ) -{ - if (Buffer) - __FreePoolWithTag(Buffer, FRONTEND_POOL_TAG); -} - -//============================================================================= -// Accessors -VOID -FrontendRemoveFeature( - IN PXENVBD_FRONTEND Frontend, - IN UCHAR BlkifOperation - ) -{ - switch (BlkifOperation) { - case BLKIF_OP_FLUSH_DISKCACHE: - Verbose("FLUSH_DISKCACHE\n"); - Frontend->DiskInfo.FlushCache = FALSE; - break; - case BLKIF_OP_WRITE_BARRIER: - Verbose("WRITE_BARRIER\n"); - Frontend->DiskInfo.Barrier = FALSE; - break; - case BLKIF_OP_DISCARD: - Verbose("DISCARD\n"); - Frontend->DiskInfo.Discard = FALSE; - break; - case BLKIF_OP_INDIRECT: - Verbose("INDIRECT\n"); - Frontend->Features.Indirect = 0; - break; - default: - break; - } -} -PXENVBD_CAPS -FrontendGetCaps( - __in PXENVBD_FRONTEND Frontend - ) -{ - return &Frontend->Caps; -} -PXENVBD_FEATURES -FrontendGetFeatures( - __in PXENVBD_FRONTEND Frontend - ) -{ - return &Frontend->Features; -} -PXENVBD_DISKINFO -FrontendGetDiskInfo( - __in PXENVBD_FRONTEND Frontend - ) -{ - return &Frontend->DiskInfo; -} -ULONG -FrontendGetTargetId( - __in PXENVBD_FRONTEND Frontend - ) -{ - return Frontend->TargetId; -} -ULONG -FrontendGetDeviceId( - __in PXENVBD_FRONTEND Frontend - ) -{ - return Frontend->DeviceId; -} -PVOID -FrontendGetInquiry( - __in PXENVBD_FRONTEND Frontend - ) -{ - return Frontend->Inquiry; -} -PXENVBD_TARGET -FrontendGetTarget( - __in PXENVBD_FRONTEND Frontend - ) -{ - return Frontend->Target; -} -PXENVBD_BLOCKRING -FrontendGetBlockRing( - __in PXENVBD_FRONTEND Frontend - ) -{ - return Frontend->BlockRing; -} -PXENVBD_NOTIFIER -FrontendGetNotifier( - __in PXENVBD_FRONTEND Frontend - ) -{ - return Frontend->Notifier; -} -PXENVBD_GRANTER -FrontendGetGranter( - __in PXENVBD_FRONTEND Frontend - ) -{ - return Frontend->Granter; -} - -NTSTATUS -FrontendStoreWriteFrontend( - __in PXENVBD_FRONTEND Frontend, - __in PCHAR Name, - __in PCHAR Value - ) -{ - return XENBUS_STORE(Printf, - &Frontend->StoreInterface, - NULL, - Frontend->FrontendPath, - Name, - Value); -} -NTSTATUS -FrontendStoreReadBackend( - __in PXENVBD_FRONTEND Frontend, - __in PCHAR Name, - __out PCHAR* Value - ) -{ - NTSTATUS Status; - - Status = STATUS_INVALID_PARAMETER; - if (Frontend->BackendPath == NULL) - goto fail1; - - Status = XENBUS_STORE(Read, - &Frontend->StoreInterface, - NULL, - Frontend->BackendPath, - Name, - Value); - if (!NT_SUCCESS(Status)) - goto fail2; - - return STATUS_SUCCESS; - -fail2: -fail1: - return Status; -} -VOID -FrontendStoreFree( - __in PXENVBD_FRONTEND Frontend, - __in PCHAR Value - ) -{ - XENBUS_STORE(Free, - &Frontend->StoreInterface, - Value); -} -__drv_maxIRQL(DISPATCH_LEVEL) -NTSTATUS -FrontendWriteUsage( - __in PXENVBD_FRONTEND Frontend - ) -{ - NTSTATUS Status; - - Status = XENBUS_STORE(Printf, - &Frontend->StoreInterface, - NULL, - Frontend->TargetPath, - "paging", - "%u", - Frontend->Caps.Paging); - if (!NT_SUCCESS(Status)) - goto out; - - Status = XENBUS_STORE(Printf, - &Frontend->StoreInterface, - NULL, - Frontend->TargetPath, - "hibernation", - "%u", - Frontend->Caps.Hibernation); - if (!NT_SUCCESS(Status)) - goto out; - - Status = XENBUS_STORE(Printf, - &Frontend->StoreInterface, - NULL, - Frontend->TargetPath, - "dump", - "%u", - Frontend->Caps.DumpFile); - if (!NT_SUCCESS(Status)) - goto out; - - Verbose("Target[%d] : %s %s %s\n", Frontend->TargetId, - Frontend->Caps.DumpFile ? "DUMP" : "NOT_DUMP", - Frontend->Caps.Hibernation ? "HIBER" : "NOT_HIBER", - Frontend->Caps.Paging ? "PAGE" : "NOT_PAGE"); - -out: - return Status; -} - -//============================================================================= -__drv_requiresIRQL(DISPATCH_LEVEL) -VOID -FrontendNotifyResponses( - __in PXENVBD_FRONTEND Frontend - ) -{ - BlockRingPoll(Frontend->BlockRing); - TargetSubmitRequests(Frontend->Target); -} - -//============================================================================= -__drv_requiresIRQL(DISPATCH_LEVEL) -static NTSTATUS -__UpdateBackendPath( - __in PXENVBD_FRONTEND Frontend - ) -{ - NTSTATUS Status; - PCHAR Value; - ULONG Length; - - Status = XENBUS_STORE(Read, - &Frontend->StoreInterface, - NULL, - Frontend->FrontendPath, - "backend-id", - &Value); - if (NT_SUCCESS(Status)) { - Frontend->BackendId = (USHORT)strtoul(Value, NULL, 10); - XENBUS_STORE(Free, - &Frontend->StoreInterface, - Value); - } else { - Frontend->BackendId = 0; - } - - Status = XENBUS_STORE(Read, - &Frontend->StoreInterface, - NULL, - Frontend->FrontendPath, - "backend", - &Value); - if (NT_SUCCESS(Status)) { - if (Frontend->BackendPath) { - Trace("<< %s\n", Frontend->BackendPath); - __FrontendFree(Frontend->BackendPath); - Frontend->BackendPath = NULL; - } - - Length = (ULONG)strlen(Value); - Frontend->BackendPath = (PCHAR)__FrontendAlloc(Length + 1); - - if (Frontend->BackendPath) { - RtlCopyMemory(Frontend->BackendPath, Value, Length); - Trace(">> %s\n", Frontend->BackendPath); - } - - XENBUS_STORE(Free, - &Frontend->StoreInterface, - Value); - } else { - Warning("Failed to read \'backend\' from \'%s\' (%08x)\n", - Frontend->FrontendPath, Status); - } - - return Status; -} -__drv_maxIRQL(DISPATCH_LEVEL) -static NTSTATUS -__ReadState( - __in PXENVBD_FRONTEND Frontend, - __in_opt PXENBUS_STORE_TRANSACTION Transaction, - __in PCHAR Path, - __out XenbusState* State - ) -{ - NTSTATUS Status; - PCHAR Buffer; - - Status = XENBUS_STORE(Read, - &Frontend->StoreInterface, - Transaction, - Path, - "state", - &Buffer); - if (!NT_SUCCESS(Status)) - goto fail; - - *State = (XenbusState)strtoul(Buffer, NULL, 10); - XENBUS_STORE(Free, - &Frontend->StoreInterface, - Buffer); - - return STATUS_SUCCESS; - -fail: - *State = XenbusStateUnknown; - return Status; -} -__drv_requiresIRQL(DISPATCH_LEVEL) -static NTSTATUS -__WaitState( - __in PXENVBD_FRONTEND Frontend, - __inout XenbusState* State - ) -{ - NTSTATUS Status; - XenbusState OldState = *State; - PXENBUS_STORE_WATCH Watch; - KEVENT Event; - LARGE_INTEGER Timeout; - - LARGE_INTEGER StartTime; - LARGE_INTEGER CurrentTime; - ULONG Count = 0; - - KeInitializeEvent(&Event, NotificationEvent, FALSE); - Timeout.QuadPart = 0; - - ASSERT3P(Frontend->BackendPath, !=, NULL); - Status = XENBUS_STORE(WatchAdd, - &Frontend->StoreInterface, - Frontend->BackendPath, - "state", - &Event, - &Watch); - if (!NT_SUCCESS(Status)) - goto fail1; - - KeQuerySystemTime(&StartTime); - - while (OldState == *State) { - // check event and spin or read -#pragma prefast(suppress:28121) - if (KeWaitForSingleObject(&Event, Executive, KernelMode, - FALSE, &Timeout) == STATUS_TIMEOUT) { - XENBUS_STORE(Poll, - &Frontend->StoreInterface); - - KeQuerySystemTime(&CurrentTime); - if ((CurrentTime.QuadPart - StartTime.QuadPart) > 10000) { - Warning("Target[%d] : %d Waited for %d ms\n", Frontend->TargetId, - Count, (ULONG)((CurrentTime.QuadPart - StartTime.QuadPart) / 10)); - StartTime.QuadPart = CurrentTime.QuadPart; - ++Count; - } - - continue; - } - - Status = __ReadState(Frontend, NULL, Frontend->BackendPath, State); - if (!NT_SUCCESS(Status)) - goto fail2; - } - - XENBUS_STORE(WatchRemove, - &Frontend->StoreInterface, - Watch); - - Trace("Target[%d] : BACKEND_STATE -> %s\n", - Frontend->TargetId, - XenbusStateName(*State)); - - return STATUS_SUCCESS; - -fail2: - Error("Fail2\n"); - - XENBUS_STORE(WatchRemove, - &Frontend->StoreInterface, - Watch); -fail1: - Error("Fail1 (%08x)\n", Status); - - return Status; -} -__drv_requiresIRQL(DISPATCH_LEVEL) -static NTSTATUS -___SetState( - __in PXENVBD_FRONTEND Frontend, - __in XenbusState State - ) -{ - NTSTATUS Status; - - Status = XENBUS_STORE(Printf, - &Frontend->StoreInterface, - NULL, - Frontend->FrontendPath, - "state", - "%u", - State); - if (NT_SUCCESS(Status)) { - Trace("Target[%d] : FRONTEND_STATE -> %s\n", - Frontend->TargetId, - XenbusStateName(State)); - } else { - Error("Fail (%08x)\n", Status); - } - - return Status; -} -__drv_requiresIRQL(DISPATCH_LEVEL) -static FORCEINLINE VOID -__CheckBackendForEject( - __in PXENVBD_FRONTEND Frontend - ) -{ - XenbusState FrontendState; - XenbusState BackendState; - BOOLEAN Online; - ULONG Attempt; - NTSTATUS Status; - - if (Frontend->FrontendPath == NULL) - return; - if (Frontend->BackendPath == NULL) - return; - - // get FrontendState, BackendState and Online - Attempt = 0; - FrontendState = XenbusStateUnknown; - BackendState = XenbusStateUnknown; - Online = TRUE; - for (;;) { - PXENBUS_STORE_TRANSACTION Transaction; - PCHAR Buffer; - - Status = XENBUS_STORE(TransactionStart, - &Frontend->StoreInterface, - &Transaction); - if (!NT_SUCCESS(Status)) - break; - - Status = __ReadState(Frontend, - Transaction, - Frontend->FrontendPath, - &FrontendState); - if (!NT_SUCCESS(Status)) - goto abort; - - Status = __ReadState(Frontend, - Transaction, - Frontend->BackendPath, - &BackendState); - if (!NT_SUCCESS(Status)) - goto abort; - - Status = XENBUS_STORE(Read, - &Frontend->StoreInterface, - Transaction, - Frontend->BackendPath, - "online", - &Buffer); - if (!NT_SUCCESS(Status)) - goto abort; - - Online = (BOOLEAN)strtol(Buffer, NULL, 2); - XENBUS_STORE(Free, - &Frontend->StoreInterface, - Buffer); - - Status = XENBUS_STORE(TransactionEnd, - &Frontend->StoreInterface, - Transaction, - TRUE); - if (Status != STATUS_RETRY || ++Attempt > 10) - break; - - continue; - -abort: - (VOID) XENBUS_STORE(TransactionEnd, - &Frontend->StoreInterface, - Transaction, - FALSE); - break; - } - if (!NT_SUCCESS(Status)) - return; - - // check to see eject required - if (!Online && BackendState == XenbusStateClosing) { - Trace("Target[%d] : BackendState(%s) FrontendState(%s)\n", - Frontend->TargetId, XenbusStateName(BackendState), XenbusStateName(FrontendState)); - - TargetIssueDeviceEject(Frontend->Target, XenbusStateName(BackendState)); - } -} - -static FORCEINLINE BOOLEAN -FrontendReadFeature( - IN PXENVBD_FRONTEND Frontend, - IN PCHAR Name, - IN PBOOLEAN Value - ) -{ - NTSTATUS status; - PCHAR Buffer; - ULONG Override; - BOOLEAN Old = *Value; - - status = XENBUS_STORE(Read, - &Frontend->StoreInterface, - NULL, - Frontend->BackendPath, - Name, - &Buffer); - if (!NT_SUCCESS(status)) - return FALSE; // no value, unchanged - - *Value = !!(strtoul(Buffer, NULL, 10)); - XENBUS_STORE(Free, - &Frontend->StoreInterface, - Buffer); - - // check registry for disable-override - status = RegistryQueryDwordValue(DriverGetParametersKey(), - Name, - &Override); - if (NT_SUCCESS(status)) { - if (Override == 0) - *Value = FALSE; - } - - return Old != *Value; -} - -static FORCEINLINE BOOLEAN -FrontendReadValue32( - IN PXENVBD_FRONTEND Frontend, - IN PCHAR Name, - IN BOOLEAN AllowOverride, - IN PULONG Value - ) -{ - NTSTATUS status; - PCHAR Buffer; - ULONG Override; - ULONG Old = *Value; - - status = XENBUS_STORE(Read, - &Frontend->StoreInterface, - NULL, - Frontend->BackendPath, - Name, - &Buffer); - if (!NT_SUCCESS(status)) - return FALSE; // no value, unchanged - - *Value = strtoul(Buffer, NULL, 10); - XENBUS_STORE(Free, - &Frontend->StoreInterface, - Buffer); - - // check registry for disable-override - if (AllowOverride) { - status = RegistryQueryDwordValue(DriverGetParametersKey(), - Name, - &Override); - if (NT_SUCCESS(status)) { - *Value = Override; - } - } - - return Old != *Value; -} - -static FORCEINLINE BOOLEAN -FrontendReadValue64( - IN PXENVBD_FRONTEND Frontend, - IN PCHAR Name, - IN OUT PULONG64 Value - ) -{ - NTSTATUS status; - PCHAR Buffer; - ULONG64 Old = *Value; - - status = XENBUS_STORE(Read, - &Frontend->StoreInterface, - NULL, - Frontend->BackendPath, - Name, - &Buffer); - if (!NT_SUCCESS(status)) - return FALSE; // no value, unchanged - - *Value = _strtoui64(Buffer, NULL, 10); - XENBUS_STORE(Free, - &Frontend->StoreInterface, - Buffer); - - return Old != *Value; -} - -static FORCEINLINE ULONG -__Size( - __in PXENVBD_DISKINFO Info - ) -{ - ULONG64 MBytes = (Info->SectorSize * Info->SectorCount) >> 20; // / (1024 * 1024); - if (MBytes < 10240) - return (ULONG)MBytes; - return (ULONG)(MBytes >> 10); // / 1024 -} -static FORCEINLINE PCHAR -__Units( - __in PXENVBD_DISKINFO Info - ) -{ - ULONG64 MBytes = (Info->SectorSize * Info->SectorCount) >> 20; // / (1024 * 1024); - if (MBytes < 10240) - return "MB"; - return "GB"; -} - -__drv_requiresIRQL(DISPATCH_LEVEL) -static VOID -__ReadDiskInfo( - __in PXENVBD_FRONTEND Frontend - ) -{ - BOOLEAN Changed = FALSE; - - Changed |= FrontendReadValue32(Frontend, - "info", - FALSE, - &Frontend->DiskInfo.DiskInfo); - Changed |= FrontendReadValue32(Frontend, - "sector-size", - FALSE, - &Frontend->DiskInfo.SectorSize); - Changed |= FrontendReadValue32(Frontend, - "physical-sector-size", - FALSE, - &Frontend->DiskInfo.PhysSectorSize); - Changed |= FrontendReadValue64(Frontend, - "sectors", - &Frontend->DiskInfo.SectorCount); - - if (!Changed) - return; - - Frontend->Caps.SurpriseRemovable = !!(Frontend->DiskInfo.DiskInfo & VDISK_REMOVABLE); - if (Frontend->DiskInfo.DiskInfo & VDISK_READONLY) { - Warning("Target[%d] : DiskInfo contains VDISK_READONLY flag!\n", Frontend->TargetId); - } - if (Frontend->DiskInfo.DiskInfo & VDISK_CDROM) { - Warning("Target[%d] : DiskInfo contains VDISK_CDROM flag!\n", Frontend->TargetId); - } - if (Frontend->DiskInfo.SectorSize == 0) { - Error("Target[%d] : Invalid SectorSize!\n", Frontend->TargetId); - } - if (Frontend->DiskInfo.SectorCount == 0) { - Error("Target[%d] : Invalid SectorCount!\n", Frontend->TargetId); - } - if (Frontend->DiskInfo.PhysSectorSize == 0) { - Frontend->DiskInfo.PhysSectorSize = Frontend->DiskInfo.SectorSize; - } - - // dump actual values - Verbose("Target[%d] : %lld sectors of %d bytes (%d)\n", Frontend->TargetId, - Frontend->DiskInfo.SectorCount, Frontend->DiskInfo.SectorSize, - Frontend->DiskInfo.PhysSectorSize); - Verbose("Target[%d] : %d %s (%08x) %s\n", Frontend->TargetId, - __Size(&Frontend->DiskInfo), __Units(&Frontend->DiskInfo), - Frontend->DiskInfo.DiskInfo, - Frontend->Caps.SurpriseRemovable ? "SURPRISE_REMOVABLE" : ""); -} - -static FORCEINLINE VOID -FrontendReadFeatures( - IN PXENVBD_FRONTEND Frontend - ) -{ - BOOLEAN Changed = FALSE; - - Changed |= FrontendReadFeature(Frontend, - "removable", - &Frontend->Caps.Removable); - Changed |= FrontendReadValue32(Frontend, - "feature-max-indirect-segments", - TRUE, - &Frontend->Features.Indirect); - Changed |= FrontendReadFeature(Frontend, - "feature-persistent", - &Frontend->Features.Persistent); - - if (!Changed) - return; - - Verbose("Target[%d] : Features: %s%s%s\n", - Frontend->TargetId, - Frontend->Features.Persistent ? "PERSISTENT " : "", - Frontend->Features.Indirect ? "INDIRECT " : "", - Frontend->Caps.Removable ? "REMOVABLE" : ""); - if (Frontend->Features.Indirect) { - Verbose("Target[%d] : INDIRECT %x\n", - Frontend->TargetId, - Frontend->Features.Indirect); - } -} - -static FORCEINLINE VOID -FrontendReadDiskInfo( - IN PXENVBD_FRONTEND Frontend - ) -{ - BOOLEAN Changed = FALSE; - BOOLEAN Discard; - BOOLEAN DiscardFeature = FALSE; - BOOLEAN DiscardEnable = TRUE; - - Changed |= FrontendReadFeature(Frontend, - "feature-barrier", - &Frontend->DiskInfo.Barrier); - Changed |= FrontendReadFeature(Frontend, - "feature-flush-cache", - &Frontend->DiskInfo.FlushCache); - - // discard related - FrontendReadFeature(Frontend, - "feature-discard", - &DiscardFeature); - FrontendReadFeature(Frontend, - "discard-enable", - &DiscardEnable); - Discard = DiscardFeature && DiscardEnable; - Changed |= (Discard != Frontend->DiskInfo.Discard); - Frontend->DiskInfo.Discard = Discard; - Changed |= FrontendReadFeature(Frontend, - "discard-secure", - &Frontend->DiskInfo.DiscardSecure); - Changed |= FrontendReadValue32(Frontend, - "discard-alignment", - TRUE, - &Frontend->DiskInfo.DiscardAlignment); - Changed |= FrontendReadValue32(Frontend, - "discard-granularity", - TRUE, - &Frontend->DiskInfo.DiscardGranularity); - - if (!Changed) - return; - - Verbose("Target[%d] : Features: %s%s%s\n", - Frontend->TargetId, - Frontend->DiskInfo.Barrier ? "BARRIER " : "", - Frontend->DiskInfo.FlushCache ? "FLUSH " : "", - Frontend->DiskInfo.Discard ? "DISCARD " : ""); - if (Frontend->DiskInfo.Discard) { - Verbose("Target[%d] : DISCARD %s%x/%x\n", - Frontend->TargetId, - Frontend->DiskInfo.DiscardSecure ? "SECURE " : "", - Frontend->DiskInfo.DiscardAlignment, - Frontend->DiskInfo.DiscardGranularity); - } -} - -//============================================================================= -__drv_requiresIRQL(DISPATCH_LEVEL) -static NTSTATUS -FrontendClose( - __in PXENVBD_FRONTEND Frontend - ) -{ - NTSTATUS Status; - XenbusState BackendState; - - // unwatch backend (null check for initial close operation) - if (Frontend->BackendWatch) - XENBUS_STORE(WatchRemove, - &Frontend->StoreInterface, - Frontend->BackendWatch); - Frontend->BackendWatch = NULL; - - Frontend->BackendId = DOMID_INVALID; - - // get/update backend path - Status = __UpdateBackendPath(Frontend); - if (!NT_SUCCESS(Status)) - goto fail1; - - // Backend : -> !INITIALIZING - BackendState = XenbusStateUnknown; - do { - Status = __WaitState(Frontend, &BackendState); - if (!NT_SUCCESS(Status)) - goto fail2; - } while (BackendState == XenbusStateInitialising); - - // Frontend: -> CLOSING - // Backend : -> CLOSING - while (BackendState != XenbusStateClosing && - BackendState != XenbusStateClosed) { - Status = ___SetState(Frontend, XenbusStateClosing); - if (!NT_SUCCESS(Status)) - goto fail3; - Status = __WaitState(Frontend, &BackendState); - if (!NT_SUCCESS(Status)) - goto fail4; - } - - // Frontend: -> CLOSED - // Backend : -> CLOSED - while (BackendState != XenbusStateClosed) { - Status = ___SetState(Frontend, XenbusStateClosed); - if (!NT_SUCCESS(Status)) - goto fail5; - Status = __WaitState(Frontend, &BackendState); - if (!NT_SUCCESS(Status)) - goto fail6; - } - - return STATUS_SUCCESS; - -fail6: -fail5: -fail4: -fail3: -fail2: -fail1: - return Status; -} -__drv_requiresIRQL(DISPATCH_LEVEL) -static NTSTATUS -FrontendPrepare( - __in PXENVBD_FRONTEND Frontend - ) -{ - NTSTATUS Status; - XenbusState BackendState; - - // get/update backend path - Status = __UpdateBackendPath(Frontend); - if (!NT_SUCCESS(Status)) - goto fail1; - - // watch backend (4 paths needed) - Status = XENBUS_STORE(WatchAdd, - &Frontend->StoreInterface, - NULL, - Frontend->BackendPath, - ThreadGetEvent(Frontend->BackendThread), - &Frontend->BackendWatch); - if (!NT_SUCCESS(Status)) - goto fail2; - - // write targetpath - Status = FrontendWriteUsage(Frontend); - if (!NT_SUCCESS(Status)) - goto fail3; - - Status = XENBUS_STORE(Printf, - &Frontend->StoreInterface, - NULL, - Frontend->TargetPath, - "frontend", - "%s", - Frontend->FrontendPath); - if (!NT_SUCCESS(Status)) - goto fail4; - - Status = XENBUS_STORE(Printf, - &Frontend->StoreInterface, - NULL, - Frontend->TargetPath, - "device", - "%u", - Frontend->DeviceId); - if (!NT_SUCCESS(Status)) - goto fail5; - - // Frontend: -> INITIALIZING - Status = ___SetState(Frontend, XenbusStateInitialising); - if (!NT_SUCCESS(Status)) - goto fail6; - - // Backend : -> INITWAIT - BackendState = XenbusStateUnknown; - do { - Status = __WaitState(Frontend, &BackendState); - if (!NT_SUCCESS(Status)) - goto fail7; - } while (BackendState == XenbusStateClosed || - BackendState == XenbusStateInitialising); - Status = STATUS_UNSUCCESSFUL; - if (BackendState != XenbusStateInitWait) - goto fail8; - - // read inquiry data - if (Frontend->Inquiry == NULL) - PdoReadInquiryData(Frontend, &Frontend->Inquiry); - PdoUpdateInquiryData(Frontend, Frontend->Inquiry); - - // read features and caps (removable, ring-order, ...) - Verbose("Target[%d] : BackendId %d (%s)\n", - Frontend->TargetId, - Frontend->BackendId, - Frontend->BackendPath); - - FrontendReadFeatures(Frontend); - - return STATUS_SUCCESS; - -fail8: - Error("Fail8\n"); -fail7: - Error("Fail7\n"); -fail6: - Error("Fail6\n"); -fail5: - Error("Fail5\n"); -fail4: - Error("Fail4\n"); -fail3: - Error("Fail3\n"); - (VOID) XENBUS_STORE(WatchRemove, - &Frontend->StoreInterface, - Frontend->BackendWatch); - Frontend->BackendWatch = NULL; -fail2: - Error("Fail2\n"); -fail1: - Error("Fail1 (%08x)\n", Status); - return Status; -} -__drv_requiresIRQL(DISPATCH_LEVEL) -static NTSTATUS -FrontendConnect( - __in PXENVBD_FRONTEND Frontend - ) -{ - NTSTATUS Status; - XenbusState BackendState; - - // Alloc Ring, Create Evtchn, Gnttab map - Status = GranterConnect(Frontend->Granter, Frontend->BackendId); - if (!NT_SUCCESS(Status)) - goto fail1; - - Status = BlockRingConnect(Frontend->BlockRing); - if (!NT_SUCCESS(Status)) - goto fail2; - - Status = NotifierConnect(Frontend->Notifier, Frontend->BackendId); - if (!NT_SUCCESS(Status)) - goto fail3; - - // write evtchn/gnttab details in xenstore - for (;;) { - PXENBUS_STORE_TRANSACTION Transaction; - - Status = XENBUS_STORE(TransactionStart, - &Frontend->StoreInterface, - &Transaction); - if (!NT_SUCCESS(Status)) - break; - - Status = NotifierStoreWrite(Frontend->Notifier, Transaction, Frontend->FrontendPath); - if (!NT_SUCCESS(Status)) - goto abort; - - Status = BlockRingStoreWrite(Frontend->BlockRing, Transaction, Frontend->FrontendPath); - if (!NT_SUCCESS(Status)) - goto abort; - - Status = GranterStoreWrite(Frontend->Granter, Transaction, Frontend->FrontendPath); - if (!NT_SUCCESS(Status)) - goto abort; - - Status = XENBUS_STORE(Printf, - &Frontend->StoreInterface, - Transaction, - Frontend->FrontendPath, - "target-id", - "%u", - Frontend->TargetId); - if (!NT_SUCCESS(Status)) - goto abort; - - Status = XENBUS_STORE(Printf, - &Frontend->StoreInterface, - Transaction, - Frontend->FrontendPath, - "feature-surprise-remove", - "%u", - 1); - if (!NT_SUCCESS(Status)) - goto abort; - - Status = XENBUS_STORE(Printf, - &Frontend->StoreInterface, - Transaction, - Frontend->FrontendPath, - "feature-online-resize", - "%u", - 1); - if (!NT_SUCCESS(Status)) - goto abort; - - Status = XENBUS_STORE(TransactionEnd, - &Frontend->StoreInterface, - Transaction, - TRUE); - if (Status == STATUS_RETRY) - continue; - - break; - -abort: - (VOID) XENBUS_STORE(TransactionEnd, - &Frontend->StoreInterface, - Transaction, - FALSE); - break; - } - if (!NT_SUCCESS(Status)) - goto fail4; - - // Frontend: -> INITIALIZED - Status = ___SetState(Frontend, XenbusStateInitialised); - if (!NT_SUCCESS(Status)) - goto fail5; - - // Backend : -> CONNECTED - BackendState = XenbusStateUnknown; - do { - Status = __WaitState(Frontend, &BackendState); - if (!NT_SUCCESS(Status)) - goto fail6; - } while (BackendState == XenbusStateInitWait || - BackendState == XenbusStateInitialising || - BackendState == XenbusStateInitialised); - Status = STATUS_UNSUCCESSFUL; - if (BackendState != XenbusStateConnected) - goto fail7; - - // read disk info - __ReadDiskInfo(Frontend); - FrontendReadDiskInfo(Frontend); - - // blkback doesnt write features before InitWait, blkback writes features before Connected! - FrontendReadFeatures(Frontend); - - // Frontend: -> CONNECTED - Status = ___SetState(Frontend, XenbusStateConnected); - if (!NT_SUCCESS(Status)) - goto fail8; - - return STATUS_SUCCESS; - -fail8: - Error("Fail8\n"); -fail7: - Error("Fail7\n"); -fail6: - Error("Fail6\n"); -fail5: - Error("Fail5\n"); -fail4: - Error("Fail4\n"); - NotifierDisconnect(Frontend->Notifier); -fail3: - Error("Fail3\n"); - BlockRingDisconnect(Frontend->BlockRing); -fail2: - Error("Fail2\n"); - GranterDisconnect(Frontend->Granter); -fail1: - Error("Fail1 (%08x)\n", Status); - return Status; -} -__drv_requiresIRQL(DISPATCH_LEVEL) -static FORCEINLINE VOID -FrontendDisconnect( - __in PXENVBD_FRONTEND Frontend - ) -{ - NotifierDisconnect(Frontend->Notifier); - BlockRingDisconnect(Frontend->BlockRing); - GranterDisconnect(Frontend->Granter); -} -__drv_requiresIRQL(DISPATCH_LEVEL) -static FORCEINLINE VOID -FrontendEnable( - __in PXENVBD_FRONTEND Frontend - ) -{ - Frontend->Caps.Connected = TRUE; - KeMemoryBarrier(); - - GranterEnable(Frontend->Granter); - BlockRingEnable(Frontend->BlockRing); - NotifierEnable(Frontend->Notifier); -} -__drv_requiresIRQL(DISPATCH_LEVEL) -static FORCEINLINE VOID -FrontendDisable( - __in PXENVBD_FRONTEND Frontend - ) -{ - Frontend->Caps.Connected = FALSE; - - NotifierDisable(Frontend->Notifier); - BlockRingDisable(Frontend->BlockRing); - GranterDisable(Frontend->Granter); -} - -//============================================================================= -// Init/Term -static DECLSPEC_NOINLINE NTSTATUS -__FrontendSetState( - __in PXENVBD_FRONTEND Frontend, - __in XENVBD_STATE State - ) -{ - NTSTATUS Status; - const ULONG TargetId = Frontend->TargetId; - BOOLEAN Failed = FALSE; - - Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); - Verbose("Target[%d] : %s ----> %s\n", - TargetId, - __XenvbdStateName(Frontend->State), - __XenvbdStateName(State)); - ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL); - - while (!Failed && Frontend->State != State) { - switch (Frontend->State) { - case XENVBD_INITIALIZED: - switch (State) { - case XENVBD_CLOSING: - case XENVBD_CLOSED: - case XENVBD_PREPARED: - case XENVBD_CONNECTED: - case XENVBD_ENABLED: - Status = FrontendClose(Frontend); - if (NT_SUCCESS(Status)) { - Frontend->State = XENVBD_CLOSED; - } else { - Failed = TRUE; - } - break; - default: - Failed = TRUE; - break; - } - break; - - case XENVBD_CLOSED: - switch (State) { - case XENVBD_INITIALIZED: - // ONLY Closed->Initialized is valid, which can occur with a very early resume from suspend - // i.e. VM was suspended before the Initianized->Closed transition, and each resume needs - // the Close transition to properly close the frontend and backend devices. - Frontend->State = XENVBD_INITIALIZED; - break; - case XENVBD_PREPARED: - case XENVBD_CONNECTED: - case XENVBD_ENABLED: - Status = FrontendPrepare(Frontend); - if (NT_SUCCESS(Status)) { - Frontend->State = XENVBD_PREPARED; - } else { - Status = FrontendClose(Frontend); - if (NT_SUCCESS(Status)) - Frontend->State = XENVBD_CLOSED; - else - Frontend->State = XENVBD_STATE_INVALID; - Failed = TRUE; - } - break; - default: - Failed = TRUE; - break; - } - break; - - case XENVBD_PREPARED: - switch (State) { - case XENVBD_CONNECTED: - case XENVBD_ENABLED: - Status = FrontendConnect(Frontend); - if (NT_SUCCESS(Status)) { - Frontend->State = XENVBD_CONNECTED; - } else { - Status = FrontendClose(Frontend); - if (NT_SUCCESS(Status)) - Frontend->State = XENVBD_CLOSED; - else - Frontend->State = XENVBD_STATE_INVALID; - Failed = TRUE; - } - break; - case XENVBD_CLOSING: - case XENVBD_CLOSED: - Status = FrontendClose(Frontend); - if (NT_SUCCESS(Status)) { - Frontend->State = XENVBD_CLOSED; - } else { - Frontend->State = XENVBD_STATE_INVALID; - Failed = TRUE; - } - break; - default: - Failed = TRUE; - break; - } - break; - - case XENVBD_CONNECTED: - switch (State) { - case XENVBD_ENABLED: - FrontendEnable(Frontend); - Frontend->State = XENVBD_ENABLED; - break; - case XENVBD_CLOSING: - case XENVBD_CLOSED: - case XENVBD_PREPARED: - Status = FrontendClose(Frontend); - Frontend->State = XENVBD_CLOSING; - break; - default: - Failed = TRUE; - break; - } - break; - - case XENVBD_CLOSING: - switch (State) { - case XENVBD_INITIALIZED: - case XENVBD_CLOSED: - case XENVBD_PREPARED: - case XENVBD_CONNECTED: - case XENVBD_ENABLED: - FrontendDisconnect(Frontend); - Frontend->State = XENVBD_CLOSED; - break; - default: - Failed = TRUE; - break; - } - break; - - case XENVBD_ENABLED: - switch (State) { - case XENVBD_CLOSING: - case XENVBD_CLOSED: - case XENVBD_PREPARED: - case XENVBD_CONNECTED: - FrontendDisable(Frontend); - Frontend->State = XENVBD_CONNECTED; - break; - default: - Failed = TRUE; - break; - } - break; - - default: - Failed = TRUE; - break; - } - Verbose("Target[%d] : in state %s\n", TargetId, __XenvbdStateName(Frontend->State)); - } - Trace("Target[%d] @ (%d) <===== (%s)\n", TargetId, KeGetCurrentIrql(), Failed ? "FAILED" : "SUCCEEDED"); - return Failed ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS; -} - -__drv_requiresIRQL(DISPATCH_LEVEL) -static DECLSPEC_NOINLINE VOID -FrontendSuspendLateCallback( - __in PVOID Argument - ) -{ - NTSTATUS Status; - XENVBD_STATE State; - PXENVBD_FRONTEND Frontend = (PXENVBD_FRONTEND)Argument; - - Verbose("Target[%d] : ===> from %s\n", Frontend->TargetId, __XenvbdStateName(Frontend->State)); - State = Frontend->State; - - TargetPreResume(Frontend->Target); - - // dont acquire state lock - called at DISPATCH on 1 vCPU with interrupts enabled - Status = __FrontendSetState(Frontend, XENVBD_CLOSED); - if (!NT_SUCCESS(Status)) { - Error("Target[%d] : SetState CLOSED (%08x)\n", Frontend->TargetId, Status); - ASSERT(FALSE); - } - - // dont acquire state lock - called at DISPATCH on 1 vCPU with interrupts enabled - Status = __FrontendSetState(Frontend, State); - if (!NT_SUCCESS(Status)) { - Error("Target[%d] : SetState %s (%08x)\n", Frontend->TargetId, __XenvbdStateName(State), Status); - ASSERT(FALSE); - } - - TargetPostResume(Frontend->Target); - NotifierTrigger(Frontend->Notifier); - - Verbose("Target[%d] : <=== restored %s\n", Frontend->TargetId, __XenvbdStateName(Frontend->State)); -} - -__checkReturn -__drv_maxIRQL(DISPATCH_LEVEL) -NTSTATUS -FrontendD3ToD0( - __in PXENVBD_FRONTEND Frontend - ) -{ - PXENVBD_ADAPTER Adapter = TargetGetAdapter(Frontend->Target); - NTSTATUS Status; - KIRQL Irql; - - KeAcquireSpinLock(&Frontend->StateLock, &Irql); - - // acquire interfaces - AdapterGetStoreInterface(Adapter, &Frontend->StoreInterface); - AdapterGetSuspendInterface(Adapter, &Frontend->SuspendInterface); - - Status = XENBUS_STORE(Acquire, &Frontend->StoreInterface); - if (!NT_SUCCESS(Status)) - goto fail1; - - Status = XENBUS_SUSPEND(Acquire, &Frontend->SuspendInterface); - if (!NT_SUCCESS(Status)) - goto fail2; - - // register suspend callback - ASSERT3P(Frontend->SuspendLateCallback, ==, NULL); - Status = XENBUS_SUSPEND(Register, - &Frontend->SuspendInterface, - SUSPEND_CALLBACK_LATE, - FrontendSuspendLateCallback, - Frontend, - &Frontend->SuspendLateCallback); - if (!NT_SUCCESS(Status)) - goto fail3; - - // update state - Frontend->Active = TRUE; - - KeReleaseSpinLock(&Frontend->StateLock, Irql); - return STATUS_SUCCESS; - -fail3: - Error("Fail3\n"); - - XENBUS_SUSPEND(Release, &Frontend->SuspendInterface); - RtlZeroMemory(&Frontend->SuspendInterface, sizeof(XENBUS_SUSPEND_INTERFACE)); - -fail2: - Error("Fail2\n"); - - XENBUS_STORE(Release, &Frontend->StoreInterface); - RtlZeroMemory(&Frontend->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); - -fail1: - Error("Fail1 (%08x)\n", Status); - - KeReleaseSpinLock(&Frontend->StateLock, Irql); - return Status; -} - -__drv_maxIRQL(DISPATCH_LEVEL) -VOID -FrontendD0ToD3( - __in PXENVBD_FRONTEND Frontend - ) -{ - KIRQL Irql; - - KeAcquireSpinLock(&Frontend->StateLock, &Irql); - - // update state - Frontend->Active = FALSE; - - // deregister suspend callback - if (Frontend->SuspendLateCallback != NULL) { - XENBUS_SUSPEND(Deregister, - &Frontend->SuspendInterface, - Frontend->SuspendLateCallback); - Frontend->SuspendLateCallback = NULL; - } - // Free backend path before dropping store interface - if (Frontend->BackendPath) { - __FrontendFree(Frontend->BackendPath); - Frontend->BackendPath = NULL; - } - - // release interfaces - XENBUS_SUSPEND(Release, &Frontend->SuspendInterface); - RtlZeroMemory(&Frontend->SuspendInterface, sizeof(XENBUS_SUSPEND_INTERFACE)); - - XENBUS_STORE(Release, &Frontend->StoreInterface); - RtlZeroMemory(&Frontend->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); - - KeReleaseSpinLock(&Frontend->StateLock, Irql); -} - -__checkReturn -NTSTATUS -FrontendSetState( - __in PXENVBD_FRONTEND Frontend, - __in XENVBD_STATE State - ) -{ - NTSTATUS Status; - KIRQL Irql; - - KeAcquireSpinLock(&Frontend->StateLock, &Irql); - - Status = __FrontendSetState(Frontend, State); - - KeReleaseSpinLock(&Frontend->StateLock, Irql); - return Status; -} - -__checkReturn -static DECLSPEC_NOINLINE NTSTATUS -FrontendBackend( - __in PXENVBD_THREAD Thread, - __in PVOID Context - ) -{ - PXENVBD_FRONTEND Frontend = Context; - - for (;;) { - KIRQL Irql; - - if (!ThreadWait(Thread)) - break; - - KeAcquireSpinLock(&Frontend->StateLock, &Irql); - // Only attempt this if Active, Active is set/cleared on D3->D0/D0->D3 - if (Frontend->Active) { - __ReadDiskInfo(Frontend); - __CheckBackendForEject(Frontend); - } - KeReleaseSpinLock(&Frontend->StateLock, Irql); - } - - return STATUS_SUCCESS; - -} - -NTSTATUS -FrontendCreate( - IN PXENVBD_TARGET Target, - IN PCHAR DeviceId, - IN ULONG TargetId, - OUT PXENVBD_FRONTEND* _Frontend - ) -{ - NTSTATUS status; - PXENVBD_FRONTEND Frontend; - - Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); - - Frontend = __FrontendAlloc(sizeof(XENVBD_FRONTEND)); - - status = STATUS_NO_MEMORY; - if (Frontend == NULL) - goto fail1; - - // populate members - Frontend->Target = Target; - Frontend->TargetId = TargetId; - Frontend->DeviceId = strtoul(DeviceId, NULL, 10); - Frontend->State = XENVBD_INITIALIZED; - Frontend->DiskInfo.SectorSize = 512; // default sector size - Frontend->BackendId = DOMID_INVALID; - - status = RtlStringCbPrintfA(Frontend->FrontendPath, - sizeof(Frontend->FrontendPath), - "device/vbd/%u", - Frontend->DeviceId); - if (!NT_SUCCESS(status)) - goto fail2; - - status = RtlStringCbPrintfA(Frontend->TargetPath, - sizeof(Frontend->TargetPath), - "data/scsi/target/%u", - TargetId); - if (!NT_SUCCESS(status)) - goto fail3; - - status = NotifierCreate(Frontend, &Frontend->Notifier); - if (!NT_SUCCESS(status)) - goto fail4; - - status = BlockRingCreate(Frontend, Frontend->DeviceId, &Frontend->BlockRing); - if (!NT_SUCCESS(status)) - goto fail5; - - status = GranterCreate(Frontend, &Frontend->Granter); - if (!NT_SUCCESS(status)) - goto fail6; - - status = ThreadCreate(FrontendBackend, Frontend, &Frontend->BackendThread); - if (!NT_SUCCESS(status)) - goto fail7; - - // kernel objects - KeInitializeSpinLock(&Frontend->StateLock); - - Trace("Target[%d] @ (%d) <===== (STATUS_SUCCESS)\n", Frontend->TargetId, KeGetCurrentIrql()); - *_Frontend = Frontend; - return STATUS_SUCCESS; - -fail7: - Error("fail7\n"); - GranterDestroy(Frontend->Granter); - Frontend->Granter = NULL; -fail6: - Error("fail6\n"); - BlockRingDestroy(Frontend->BlockRing); - Frontend->BlockRing = NULL; -fail5: - Error("fail5\n"); - NotifierDestroy(Frontend->Notifier); - Frontend->Notifier = NULL; -fail4: - Error("fail4\n"); -fail3: - Error("fail3\n"); -fail2: - Error("Fail2\n"); - __FrontendFree(Frontend); -fail1: - Error("Fail1 (%08x)\n", status); - *_Frontend = NULL; - return status; -} - -VOID -FrontendDestroy( - __in PXENVBD_FRONTEND Frontend - ) -{ - const ULONG TargetId = Frontend->TargetId; - - Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); - - PdoFreeInquiryData(Frontend->Inquiry); - Frontend->Inquiry = NULL; - - ThreadAlert(Frontend->BackendThread); - ThreadJoin(Frontend->BackendThread); - Frontend->BackendThread = NULL; - - GranterDestroy(Frontend->Granter); - Frontend->Granter = NULL; - - BlockRingDestroy(Frontend->BlockRing); - Frontend->BlockRing = NULL; - - NotifierDestroy(Frontend->Notifier); - Frontend->Notifier = NULL; - - ASSERT3P(Frontend->BackendPath, ==, NULL); - ASSERT3P(Frontend->Inquiry, ==, NULL); - ASSERT3P(Frontend->SuspendLateCallback, ==, NULL); - ASSERT3P(Frontend->BackendWatch, ==, NULL); - - __FrontendFree(Frontend); - Trace("Target[%d] @ (%d) <=====\n", TargetId, KeGetCurrentIrql()); -} - -//============================================================================= -// Debug -VOID -FrontendDebugCallback( - __in PXENVBD_FRONTEND Frontend, - __in PXENBUS_DEBUG_INTERFACE Debug - ) -{ - XENBUS_DEBUG(Printf, Debug, - "FRONTEND: TargetId=%d DeviceId=%d BackendId=%d\n", - Frontend->TargetId, - Frontend->DeviceId, - Frontend->BackendId); - XENBUS_DEBUG(Printf, Debug, - "FRONTEND: FrontendPath %s\n", - Frontend->FrontendPath); - XENBUS_DEBUG(Printf, Debug, - "FRONTEND: BackendPath %s\n", - Frontend->BackendPath ? Frontend->BackendPath : "NULL"); - XENBUS_DEBUG(Printf, Debug, - "FRONTEND: TargetPath %s\n", - Frontend->TargetPath); - XENBUS_DEBUG(Printf, Debug, - "FRONTEND: State : %s\n", - __XenvbdStateName(Frontend->State)); - - XENBUS_DEBUG(Printf, Debug, - "FRONTEND: Caps : %s%s%s%s%s%s\n", - Frontend->Caps.Connected ? "CONNECTED " : "", - Frontend->Caps.Removable ? "REMOVABLE " : "", - Frontend->Caps.SurpriseRemovable ? "SURPRISE " : "", - Frontend->Caps.Paging ? "PAGING " : "", - Frontend->Caps.Hibernation ? "HIBER " : "", - Frontend->Caps.DumpFile ? "DUMP " : ""); - - XENBUS_DEBUG(Printf, Debug, - "FRONTEND: Features: %s%s%s%s%s\n", - Frontend->Features.Persistent ? "PERSISTENT " : "", - Frontend->Features.Indirect > 0 ? "INDIRECT " : "", - Frontend->DiskInfo.Barrier ? "BARRIER " : "", - Frontend->DiskInfo.FlushCache ? "FLUSH " : "", - Frontend->DiskInfo.Discard ? "DISCARD " : ""); - - if (Frontend->Features.Indirect > 0) { - XENBUS_DEBUG(Printf, Debug, - "FRONTEND: INDIRECT %x\n", - Frontend->Features.Indirect); - } - if (Frontend->DiskInfo.Discard) { - XENBUS_DEBUG(Printf, Debug, - "FRONTEND: DISCARD %s%x/%x\n", - Frontend->DiskInfo.DiscardSecure ? "SECURE " : "", - Frontend->DiskInfo.DiscardAlignment, - Frontend->DiskInfo.DiscardGranularity); - } - - XENBUS_DEBUG(Printf, Debug, - "FRONTEND: DiskInfo: %llu @ %u (%u) %08x\n", - Frontend->DiskInfo.SectorCount, - Frontend->DiskInfo.SectorSize, - Frontend->DiskInfo.PhysSectorSize, - Frontend->DiskInfo.DiskInfo); - - GranterDebugCallback(Frontend->Granter, Debug); - BlockRingDebugCallback(Frontend->BlockRing, Debug); - NotifierDebugCallback(Frontend->Notifier, Debug); -} - diff --git a/src/xenvbd/frontend.h b/src/xenvbd/frontend.h deleted file mode 100644 index f466ef8..0000000 --- a/src/xenvbd/frontend.h +++ /dev/null @@ -1,198 +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_FRONTEND_H -#define _XENVBD_FRONTEND_H - -#include "target.h" -#include <debug_interface.h> - -typedef enum _XENVBD_STATE { - XENVBD_STATE_INVALID, - XENVBD_INITIALIZED, // -> { CLOSED } - XENVBD_CLOSING, // -> { CLOSED } - XENVBD_CLOSED, // -> { PREPARED } - XENVBD_PREPARED, // -> { CLOSING, CONNECTED } - XENVBD_CONNECTED, // -> { ENABLED, CLOSING } - XENVBD_ENABLED // -> { CLOSING } -} XENVBD_STATE, *PXENVBD_STATE; - -typedef struct _XENVBD_CAPS { - BOOLEAN Connected; - BOOLEAN Removable; - BOOLEAN SurpriseRemovable; - BOOLEAN Paging; - BOOLEAN Hibernation; - BOOLEAN DumpFile; -} XENVBD_CAPS, *PXENVBD_CAPS; - -typedef struct _XENVBD_FEATURES { - ULONG Indirect; - BOOLEAN Persistent; -} XENVBD_FEATURES, *PXENVBD_FEATURES; - -typedef struct _XENVBD_DISKINFO { - ULONG64 SectorCount; - ULONG SectorSize; - ULONG PhysSectorSize; - ULONG DiskInfo; - BOOLEAN Barrier; - BOOLEAN FlushCache; - BOOLEAN Discard; - BOOLEAN DiscardSecure; - ULONG DiscardAlignment; - ULONG DiscardGranularity; -} XENVBD_DISKINFO, *PXENVBD_DISKINFO; - -typedef struct _XENVBD_FRONTEND XENVBD_FRONTEND, *PXENVBD_FRONTEND; - -// Accessors -extern VOID -FrontendRemoveFeature( - IN PXENVBD_FRONTEND Frontend, - IN UCHAR BlkifOperation - ); -extern PXENVBD_CAPS -FrontendGetCaps( - __in PXENVBD_FRONTEND Frontend - ); -extern PXENVBD_FEATURES -FrontendGetFeatures( - __in PXENVBD_FRONTEND Frontend - ); -extern PXENVBD_DISKINFO -FrontendGetDiskInfo( - __in PXENVBD_FRONTEND Frontend - ); -extern ULONG -FrontendGetTargetId( - __in PXENVBD_FRONTEND Frontend - ); -extern ULONG -FrontendGetDeviceId( - __in PXENVBD_FRONTEND Frontend - ); -extern PVOID -FrontendGetInquiry( - __in PXENVBD_FRONTEND Frontend - ); -extern PXENVBD_TARGET -FrontendGetTarget( - __in PXENVBD_FRONTEND Frontend - ); -#include "blockring.h" -extern PXENVBD_BLOCKRING -FrontendGetBlockRing( - __in PXENVBD_FRONTEND Frontend - ); -#include "notifier.h" -extern PXENVBD_NOTIFIER -FrontendGetNotifier( - __in PXENVBD_FRONTEND Frontend - ); -#include "granter.h" -extern PXENVBD_GRANTER -FrontendGetGranter( - __in PXENVBD_FRONTEND Frontend - ); - -extern NTSTATUS -FrontendStoreWriteFrontend( - __in PXENVBD_FRONTEND Frontend, - __in PCHAR Name, - __in PCHAR Value - ); -extern NTSTATUS -FrontendStoreReadBackend( - __in PXENVBD_FRONTEND Frontend, - __in PCHAR Name, - __out PCHAR* Value - ); -extern VOID -FrontendStoreFree( - __in PXENVBD_FRONTEND Frontend, - __in PCHAR Value - ); -__drv_maxIRQL(DISPATCH_LEVEL) -extern NTSTATUS -FrontendWriteUsage( - __in PXENVBD_FRONTEND Frontend - ); - -// Ring -__drv_requiresIRQL(DISPATCH_LEVEL) -extern VOID -FrontendNotifyResponses( - __in PXENVBD_FRONTEND Frontend - ); - -// Init/Term -__checkReturn -__drv_maxIRQL(DISPATCH_LEVEL) -extern NTSTATUS -FrontendD3ToD0( - __in PXENVBD_FRONTEND Frontend - ); - -__drv_maxIRQL(DISPATCH_LEVEL) -extern VOID -FrontendD0ToD3( - __in PXENVBD_FRONTEND Frontend - ); - -__checkReturn -extern NTSTATUS -FrontendSetState( - __in PXENVBD_FRONTEND Frontend, - __in XENVBD_STATE State - ); - -extern NTSTATUS -FrontendCreate( - IN PXENVBD_TARGET Target, - IN PCHAR DeviceId, - IN ULONG TargetId, - OUT PXENVBD_FRONTEND* _Frontend - ); - -extern VOID -FrontendDestroy( - __in PXENVBD_FRONTEND Frontend - ); - -// Debug -extern VOID -FrontendDebugCallback( - __in PXENVBD_FRONTEND Frontend, - __in PXENBUS_DEBUG_INTERFACE Debug - ); - -#endif // _XENVBD_FRONTEND_H diff --git a/src/xenvbd/granter.c b/src/xenvbd/granter.c index d61b8b2..22147f3 100644 --- a/src/xenvbd/granter.c +++ b/src/xenvbd/granter.c @@ -32,50 +32,62 @@ #include <ntddk.h> #include <ntstrsafe.h> -#include "frontend.h" +#include <gnttab_interface.h> +#include <debug_interface.h> + +#include "granter.h" #include "target.h" #include "adapter.h" + #include "util.h" #include "debug.h" -#include "thread.h" -#include <gnttab_interface.h> +#include "assert.h" struct _XENVBD_GRANTER { - PXENVBD_FRONTEND Frontend; - BOOLEAN Connected; - BOOLEAN Enabled; + PXENVBD_TARGET Target; + BOOLEAN Connected; + BOOLEAN Enabled; + + XENBUS_DEBUG_INTERFACE DebugInterface; + XENBUS_GNTTAB_INTERFACE GnttabInterface; - XENBUS_GNTTAB_INTERFACE GnttabInterface; - PXENBUS_GNTTAB_CACHE Cache; - KSPIN_LOCK Lock; + PXENBUS_DEBUG_CALLBACK DebugCallback; - USHORT BackendDomain; - LONG Current; - LONG Maximum; + PXENBUS_GNTTAB_CACHE Cache; + KSPIN_LOCK Lock; + + LONG Current; + LONG Maximum; }; -#define GRANTER_POOL_TAG 'tnGX' +#define GRANTER_POOL_TAG 'tnGX' static FORCEINLINE PVOID __GranterAllocate( - IN ULONG Length + IN ULONG Size ) { - return __AllocatePoolWithTag(NonPagedPool, Length, GRANTER_POOL_TAG); + PVOID Buffer; + Buffer = ExAllocatePoolWithTag(NonPagedPool, + Size, + GRANTER_POOL_TAG); + if (Buffer) + RtlZeroMemory(Buffer, Size); + return Buffer; } static FORCEINLINE VOID __GranterFree( - IN PVOID Buffer + IN PVOID Buffer ) { if (Buffer) - __FreePoolWithTag(Buffer, GRANTER_POOL_TAG); + ExFreePoolWithTag(Buffer, GRANTER_POOL_TAG); } NTSTATUS GranterCreate( - IN PXENVBD_FRONTEND Frontend, - OUT PXENVBD_GRANTER* Granter + IN PXENVBD_TARGET Target, + OUT PXENVBD_GRANTER* Granter ) { NTSTATUS status; @@ -85,7 +97,7 @@ GranterCreate( if (*Granter == NULL) goto fail1; - (*Granter)->Frontend = Frontend; + (*Granter)->Target = Target; KeInitializeSpinLock(&(*Granter)->Lock); return STATUS_SUCCESS; @@ -96,10 +108,10 @@ fail1: VOID GranterDestroy( - IN PXENVBD_GRANTER Granter + IN PXENVBD_GRANTER Granter ) { - Granter->Frontend = NULL; + Granter->Target = NULL; RtlZeroMemory(&Granter->Lock, sizeof(KSPIN_LOCK)); ASSERT(IsZeroMemory(Granter, sizeof(XENVBD_GRANTER))); @@ -134,34 +146,54 @@ GranterReleaseLock( KeReleaseSpinLockFromDpcLevel(&Granter->Lock); } -#define MAXNAMELEN 32 +static DECLSPEC_NOINLINE VOID +GranterDebugCallback( + IN PVOID Context, + IN BOOLEAN Crashing + ) +{ + PXENVBD_GRANTER Granter = Context; + + UNREFERENCED_PARAMETER(Crashing); + + XENBUS_DEBUG(Printf, + &Granter->DebugInterface, + "%u / %u Grants\n", + Granter->Current, + Granter->Maximum); + Granter->Maximum = Granter->Current; +} NTSTATUS GranterConnect( - IN PXENVBD_GRANTER Granter, - IN USHORT BackendDomain + IN PXENVBD_GRANTER Granter ) { - PXENVBD_ADAPTER Adapter = TargetGetAdapter(FrontendGetTarget(Granter->Frontend)); - CHAR Name[MAXNAMELEN]; - NTSTATUS status; + PXENVBD_ADAPTER Adapter; + CHAR Name[sizeof("xenvbd_XXXX_gnttab")]; + NTSTATUS status; ASSERT(Granter->Connected == FALSE); + Adapter = TargetGetAdapter(Granter->Target); + AdapterGetGnttabInterface(Adapter, &Granter->GnttabInterface); + AdapterGetDebugInterface(Adapter, &Granter->DebugInterface); status = XENBUS_GNTTAB(Acquire, &Granter->GnttabInterface); if (!NT_SUCCESS(status)) goto fail1; - Granter->BackendDomain = BackendDomain; + status = XENBUS_DEBUG(Acquire, &Granter->DebugInterface); + if (!NT_SUCCESS(status)) + goto fail2; status = RtlStringCbPrintfA(Name, - sizeof (Name), - "disk_%u", - FrontendGetTargetId(Granter->Frontend)); + sizeof(Name), + "xenvbd_%u_gnttab", + TargetGetTargetId(Granter->Target)); if (!NT_SUCCESS(status)) - goto fail2; + goto fail3; status = XENBUS_GNTTAB(CreateCache, &Granter->GnttabInterface, @@ -172,37 +204,56 @@ GranterConnect( Granter, &Granter->Cache); if (!NT_SUCCESS(status)) - goto fail3; + goto fail4; + + status = XENBUS_DEBUG(Register, + &Granter->DebugInterface, + __MODULE__, + GranterDebugCallback, + Granter, + &Granter->DebugCallback); + if (!NT_SUCCESS(status)) + goto fail5; Granter->Connected = TRUE; return STATUS_SUCCESS; +fail5: + Error("fail5\n"); + XENBUS_GNTTAB(DestroyCache, + &Granter->GnttabInterface, + Granter->Cache); + Granter->Cache = NULL; +fail4: + Error("fail4\n"); fail3: + Error("fail3\n"); + XENBUS_DEBUG(Release, &Granter->DebugInterface); + RtlZeroMemory(&Granter->DebugInterface, sizeof(XENBUS_DEBUG_INTERFACE)); fail2: - Granter->BackendDomain = 0; + Error("fail2\n"); XENBUS_GNTTAB(Release, &Granter->GnttabInterface); RtlZeroMemory(&Granter->GnttabInterface, sizeof(XENBUS_GNTTAB_INTERFACE)); fail1: + Error("fail1 %08x\n", status); return status; } NTSTATUS GranterStoreWrite( - IN PXENVBD_GRANTER Granter, - IN PXENBUS_STORE_TRANSACTION Transaction, - IN PCHAR FrontendPath + IN PXENVBD_GRANTER Granter, + IN PVOID Transaction ) { UNREFERENCED_PARAMETER(Granter); UNREFERENCED_PARAMETER(Transaction); - UNREFERENCED_PARAMETER(FrontendPath); return STATUS_SUCCESS; } VOID GranterEnable( - IN PXENVBD_GRANTER Granter + IN PXENVBD_GRANTER Granter ) { ASSERT(Granter->Enabled == FALSE); @@ -212,7 +263,7 @@ GranterEnable( VOID GranterDisable( - IN PXENVBD_GRANTER Granter + IN PXENVBD_GRANTER Granter ) { ASSERT(Granter->Enabled == TRUE); @@ -222,43 +273,33 @@ GranterDisable( VOID GranterDisconnect( - IN PXENVBD_GRANTER Granter + IN PXENVBD_GRANTER Granter ) { ASSERT(Granter->Connected == TRUE); - ASSERT3S(Granter->Current, ==, 0); + Granter->Current = 0; Granter->Maximum = 0; + XENBUS_DEBUG(Deregister, + &Granter->DebugInterface, + Granter->DebugCallback); + Granter->DebugCallback = NULL; + XENBUS_GNTTAB(DestroyCache, &Granter->GnttabInterface, Granter->Cache); Granter->Cache = NULL; + XENBUS_DEBUG(Release, &Granter->DebugInterface); + RtlZeroMemory(&Granter->DebugInterface, sizeof(XENBUS_DEBUG_INTERFACE)); + XENBUS_GNTTAB(Release, &Granter->GnttabInterface); RtlZeroMemory(&Granter->GnttabInterface, sizeof(XENBUS_GNTTAB_INTERFACE)); - Granter->BackendDomain = 0; Granter->Connected = FALSE; } -VOID -GranterDebugCallback( - IN PXENVBD_GRANTER Granter, - IN PXENBUS_DEBUG_INTERFACE Debug - ) -{ - XENBUS_DEBUG(Printf, Debug, - "GRANTER: %s %s\n", - Granter->Connected ? "CONNECTED" : "DISCONNECTED", - Granter->Enabled ? "ENABLED" : "DISABLED"); - XENBUS_DEBUG(Printf, Debug, - "GRANTER: %d / %d\n", - Granter->Current, - Granter->Maximum); - Granter->Maximum = Granter->Current; -} - NTSTATUS GranterGet( IN PXENVBD_GRANTER Granter, @@ -279,7 +320,7 @@ GranterGet( &Granter->GnttabInterface, Granter->Cache, FALSE, - Granter->BackendDomain, + TargetGetBackendId(Granter->Target), Pfn, ReadOnly, &Entry); @@ -294,7 +335,9 @@ GranterGet( return STATUS_SUCCESS; fail2: + Error("fail2\n"); fail1: + Error("fail1 %08x\n", status); return status; } diff --git a/src/xenvbd/granter.h b/src/xenvbd/granter.h index de7701c..da17698 100644 --- a/src/xenvbd/granter.h +++ b/src/xenvbd/granter.h @@ -32,75 +32,67 @@ #ifndef _XENVBD_GRANTER_H #define _XENVBD_GRANTER_H +#include <ntddk.h> + typedef struct _XENVBD_GRANTER XENVBD_GRANTER, *PXENVBD_GRANTER; -#include <debug_interface.h> -#include <store_interface.h> -#include "frontend.h" +#include "target.h" extern NTSTATUS GranterCreate( - IN PXENVBD_FRONTEND Frontend, - OUT PXENVBD_GRANTER* Granter + IN PXENVBD_TARGET Target, + OUT PXENVBD_GRANTER* Granter ); extern VOID GranterDestroy( - IN PXENVBD_GRANTER Granter + IN PXENVBD_GRANTER Granter ); extern NTSTATUS GranterConnect( - IN PXENVBD_GRANTER Granter, - IN USHORT BackendDomain + IN PXENVBD_GRANTER Granter ); extern NTSTATUS GranterStoreWrite( - IN PXENVBD_GRANTER Granter, - IN PXENBUS_STORE_TRANSACTION Transaction, - IN PCHAR FrontendPath + IN PXENVBD_GRANTER Granter, + IN PVOID Transaction ); extern VOID GranterEnable( - IN PXENVBD_GRANTER Granter + IN PXENVBD_GRANTER Granter ); extern VOID GranterDisable( - IN PXENVBD_GRANTER Granter + IN PXENVBD_GRANTER Granter ); extern VOID GranterDisconnect( - IN PXENVBD_GRANTER Granter - ); - -extern VOID -GranterDebugCallback( - IN PXENVBD_GRANTER Granter, - IN PXENBUS_DEBUG_INTERFACE Debug + IN PXENVBD_GRANTER Granter ); extern NTSTATUS GranterGet( - IN PXENVBD_GRANTER Granter, - IN PFN_NUMBER Pfn, - IN BOOLEAN ReadOnly, - OUT PVOID *Handle + IN PXENVBD_GRANTER Granter, + IN PFN_NUMBER Pfn, + IN BOOLEAN ReadOnly, + OUT PVOID *Handle ); extern VOID GranterPut( - IN PXENVBD_GRANTER Granter, - IN PVOID Handle + IN PXENVBD_GRANTER Granter, + IN PVOID Handle ); extern ULONG GranterReference( - IN PXENVBD_GRANTER Granter, - IN PVOID Handle + IN PXENVBD_GRANTER Granter, + IN PVOID Handle ); #endif // _XENVBD_GRANTER_H diff --git a/src/xenvbd/notifier.c b/src/xenvbd/notifier.c deleted file mode 100644 index 1e0c057..0000000 --- a/src/xenvbd/notifier.c +++ /dev/null @@ -1,334 +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 "notifier.h" -#include "frontend.h" -#include "target.h" -#include "adapter.h" -#include "util.h" -#include "debug.h" -#include <evtchn_interface.h> - -struct _XENVBD_NOTIFIER { - PXENVBD_FRONTEND Frontend; - BOOLEAN Connected; - BOOLEAN Enabled; - - XENBUS_STORE_INTERFACE StoreInterface; - XENBUS_EVTCHN_INTERFACE EvtchnInterface; - - PXENBUS_EVTCHN_CHANNEL Channel; - ULONG Port; - ULONG NumInts; - ULONG NumDpcs; - KDPC Dpc; -}; - -#define NOTIFIER_POOL_TAG 'yfNX' - -static FORCEINLINE PVOID -__NotifierAllocate( - IN ULONG Length - ) -{ - return __AllocatePoolWithTag(NonPagedPool, Length, NOTIFIER_POOL_TAG); -} - -static FORCEINLINE VOID -__NotifierFree( - IN PVOID Buffer - ) -{ - if (Buffer) - __FreePoolWithTag(Buffer, NOTIFIER_POOL_TAG); -} - -KSERVICE_ROUTINE NotifierInterrupt; - -BOOLEAN -NotifierInterrupt( - __in PKINTERRUPT Interrupt, - _In_opt_ PVOID Context - ) -{ - PXENVBD_NOTIFIER Notifier = Context; - - UNREFERENCED_PARAMETER(Interrupt); - - ASSERT(Notifier != NULL); - - ++Notifier->NumInts; - if (Notifier->Connected) { - if (KeInsertQueueDpc(&Notifier->Dpc, NULL, NULL)) { - ++Notifier->NumDpcs; - } - } - - return TRUE; -} - -KDEFERRED_ROUTINE NotifierDpc; - -VOID -NotifierDpc( - __in PKDPC Dpc, - __in_opt PVOID Context, - __in_opt PVOID Arg1, - __in_opt PVOID Arg2 - ) -{ - PXENVBD_NOTIFIER Notifier = Context; - - UNREFERENCED_PARAMETER(Dpc); - UNREFERENCED_PARAMETER(Arg1); - UNREFERENCED_PARAMETER(Arg2); - - ASSERT(Notifier != NULL); - - if (!Notifier->Connected) - return; - - FrontendNotifyResponses(Notifier->Frontend); - - XENBUS_EVTCHN(Unmask, - &Notifier->EvtchnInterface, - Notifier->Channel, - FALSE); -} - -NTSTATUS -NotifierCreate( - IN PXENVBD_FRONTEND Frontend, - OUT PXENVBD_NOTIFIER* Notifier - ) -{ - *Notifier = __NotifierAllocate(sizeof(XENVBD_NOTIFIER)); - if (*Notifier == NULL) - goto fail1; - - (*Notifier)->Frontend = Frontend; - KeInitializeDpc(&(*Notifier)->Dpc, NotifierDpc, *Notifier); - - return STATUS_SUCCESS; - -fail1: - return STATUS_NO_MEMORY; -} - -VOID -NotifierDestroy( - IN PXENVBD_NOTIFIER Notifier - ) -{ - Notifier->Frontend = NULL; - RtlZeroMemory(&Notifier->Dpc, sizeof(KDPC)); - - ASSERT(IsZeroMemory(Notifier, sizeof(XENVBD_NOTIFIER))); - - __NotifierFree(Notifier); -} - -NTSTATUS -NotifierConnect( - IN PXENVBD_NOTIFIER Notifier, - IN USHORT BackendDomain - ) -{ - PXENVBD_ADAPTER Adapter = TargetGetAdapter(FrontendGetTarget(Notifier->Frontend)); - NTSTATUS status; - - ASSERT(Notifier->Connected == FALSE); - - AdapterGetStoreInterface(Adapter, &Notifier->StoreInterface); - AdapterGetEvtchnInterface(Adapter, &Notifier->EvtchnInterface); - - status = XENBUS_STORE(Acquire, &Notifier->StoreInterface); - if (!NT_SUCCESS(status)) - goto fail1; - - status = XENBUS_EVTCHN(Acquire, &Notifier->EvtchnInterface); - if (!NT_SUCCESS(status)) - goto fail2; - - Notifier->Channel = XENBUS_EVTCHN(Open, - &Notifier->EvtchnInterface, - XENBUS_EVTCHN_TYPE_UNBOUND, - NotifierInterrupt, - Notifier, - BackendDomain, - TRUE); - - status = STATUS_NO_MEMORY; - if (Notifier->Channel == NULL) - goto fail3; - - Notifier->Port = XENBUS_EVTCHN(GetPort, - &Notifier->EvtchnInterface, - Notifier->Channel); - - XENBUS_EVTCHN(Unmask, - &Notifier->EvtchnInterface, - Notifier->Channel, - FALSE); - - Notifier->Connected = TRUE; - return STATUS_SUCCESS; - -fail3: - XENBUS_EVTCHN(Release, &Notifier->EvtchnInterface); - RtlZeroMemory(&Notifier->EvtchnInterface, sizeof(XENBUS_EVTCHN_INTERFACE)); - -fail2: - XENBUS_STORE(Release, &Notifier->StoreInterface); - RtlZeroMemory(&Notifier->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); - -fail1: - return status; -} - -NTSTATUS -NotifierStoreWrite( - IN PXENVBD_NOTIFIER Notifier, - IN PXENBUS_STORE_TRANSACTION Transaction, - IN PCHAR FrontendPath - ) -{ - return XENBUS_STORE(Printf, - &Notifier->StoreInterface, - Transaction, - FrontendPath, - "event-channel", - "%u", - Notifier->Port); -} - -VOID -NotifierEnable( - IN PXENVBD_NOTIFIER Notifier - ) -{ - ASSERT(Notifier->Enabled == FALSE); - - XENBUS_EVTCHN(Trigger, - &Notifier->EvtchnInterface, - Notifier->Channel); - - Notifier->Enabled = TRUE; -} - -VOID -NotifierDisable( - IN PXENVBD_NOTIFIER Notifier - ) -{ - ASSERT(Notifier->Enabled == TRUE); - - Notifier->Enabled = FALSE; -} - -VOID -NotifierDisconnect( - IN PXENVBD_NOTIFIER Notifier - ) -{ - ASSERT(Notifier->Connected == TRUE); - - XENBUS_EVTCHN(Close, - &Notifier->EvtchnInterface, - Notifier->Channel); - Notifier->Channel = NULL; - Notifier->Port = 0; - - XENBUS_EVTCHN(Release, &Notifier->EvtchnInterface); - RtlZeroMemory(&Notifier->EvtchnInterface, sizeof(XENBUS_EVTCHN_INTERFACE)); - - XENBUS_STORE(Release, &Notifier->StoreInterface); - RtlZeroMemory(&Notifier->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); - - Notifier->NumInts = Notifier->NumDpcs = 0; - - Notifier->Connected = FALSE; -} - -VOID -NotifierDebugCallback( - IN PXENVBD_NOTIFIER Notifier, - IN PXENBUS_DEBUG_INTERFACE Debug - ) -{ - XENBUS_DEBUG(Printf, Debug, - "NOTIFIER: Int / DPC : %d / %d\n", - Notifier->NumInts, Notifier->NumDpcs); - - if (Notifier->Channel) { - XENBUS_DEBUG(Printf, Debug, - "NOTIFIER: Channel : %p (%d)\n", - Notifier->Channel, Notifier->Port); - } - - Notifier->NumInts = 0; - Notifier->NumDpcs = 0; -} - -VOID -NotifierKick( - IN PXENVBD_NOTIFIER Notifier - ) -{ - if (Notifier->Enabled) { - if (KeInsertQueueDpc(&Notifier->Dpc, NULL, NULL)) { - ++Notifier->NumDpcs; - } - } -} - -VOID -NotifierTrigger( - IN PXENVBD_NOTIFIER Notifier - ) -{ - if (Notifier->Enabled) - XENBUS_EVTCHN(Trigger, - &Notifier->EvtchnInterface, - Notifier->Channel); -} - -VOID -NotifierSend( - IN PXENVBD_NOTIFIER Notifier - ) -{ - if (Notifier->Enabled) - XENBUS_EVTCHN(Send, - &Notifier->EvtchnInterface, - Notifier->Channel); -} - diff --git a/src/xenvbd/notifier.h b/src/xenvbd/notifier.h deleted file mode 100644 index 4cf35e7..0000000 --- a/src/xenvbd/notifier.h +++ /dev/null @@ -1,101 +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_NOTIFIER_H -#define _XENVBD_NOTIFIER_H - -typedef struct _XENVBD_NOTIFIER XENVBD_NOTIFIER, *PXENVBD_NOTIFIER; - -#include "frontend.h" -#include <debug_interface.h> -#include <store_interface.h> - -extern NTSTATUS -NotifierCreate( - IN PXENVBD_FRONTEND Frontend, - OUT PXENVBD_NOTIFIER* Notifier - ); - -extern VOID -NotifierDestroy( - IN PXENVBD_NOTIFIER Notifier - ); - -extern NTSTATUS -NotifierConnect( - IN PXENVBD_NOTIFIER Notifier, - IN USHORT BackendDomain - ); - -extern NTSTATUS -NotifierStoreWrite( - IN PXENVBD_NOTIFIER Notifier, - IN PXENBUS_STORE_TRANSACTION Transaction, - IN PCHAR FrontendPath - ); - -extern VOID -NotifierEnable( - IN PXENVBD_NOTIFIER Notifier - ); - -extern VOID -NotifierDisable( - IN PXENVBD_NOTIFIER Notifier - ); - -extern VOID -NotifierDisconnect( - IN PXENVBD_NOTIFIER Notifier - ); - -extern VOID -NotifierDebugCallback( - IN PXENVBD_NOTIFIER Notifier, - IN PXENBUS_DEBUG_INTERFACE Debug - ); - -extern VOID -NotifierKick( - IN PXENVBD_NOTIFIER Notifier - ); - -extern VOID -NotifierTrigger( - IN PXENVBD_NOTIFIER Notifier - ); - -extern VOID -NotifierSend( - IN PXENVBD_NOTIFIER Notifier - ); - -#endif // _XENVBD_NOTIFIER_H diff --git a/src/xenvbd/pdoinquiry.c b/src/xenvbd/pdoinquiry.c deleted file mode 100644 index 2608fbf..0000000 --- a/src/xenvbd/pdoinquiry.c +++ /dev/null @@ -1,530 +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 "pdoinquiry.h" -#include "driver.h" -#include "debug.h" -#include "assert.h" -#include "util.h" -#include <xencdb.h> -#include <xenvbd-ntstrsafe.h> -#include <stdlib.h> - -// "00000000-0000-0000-0000-000000000000" -#define GUID_LENGTH 36 - -// 00 00 00 00 00 00 00 00 "XENSRC 00000000" -#define PAGE83_MIN_SIZE (4 + 4 + 16) - -// 00 00 00 00 + GUID_LENGTH -#define VDI_ID_LENGTH (4 + GUID_LENGTH) - -#define INQUIRY_POOL_TAG 'qnIX' - -typedef struct _XENVBD_PAGE { - PCHAR Data; - ULONG Length; -} XENVBD_PAGE, *PXENVBD_PAGE; - -typedef struct _XENVBD_INQUIRY { - XENVBD_PAGE Page80; - XENVBD_PAGE Page83; - CHAR VdiUuid[GUID_LENGTH + 1]; -} XENVBD_INQUIRY, *PXENVBD_INQUIRY; - -static FORCEINLINE ULONG -__Min3( - __in ULONG A, - __in ULONG B, - __in ULONG C - ) -{ - return A < B ? __min(A, C) : __min(B, C); -} - -__checkReturn -__drv_allocatesMem(mem) -__bcount(Size) -static FORCEINLINE PVOID -#pragma warning(suppress: 28195) -__InquiryAlloc( - __in SIZE_T Size - ) -{ - return __AllocatePoolWithTag(NonPagedPool, Size, INQUIRY_POOL_TAG); -} - -static FORCEINLINE VOID -#pragma warning(suppress: 28197) -__InquiryFree( - __in __drv_freesMem(mem) PVOID Buffer - ) -{ - if (Buffer != NULL) - __FreePoolWithTag(Buffer, INQUIRY_POOL_TAG); -} - -static FORCEINLINE UCHAR -__DecodeChar( - __in CHAR Char - ) -{ - if (Char >= 'A' && Char <= 'Z') return Char - 'A'; - if (Char >= 'a' && Char <= 'z') return Char - 'a' + 26; - if (Char >= '0' && Char <= '9') return Char - '0' + 52; - if (Char == '+') return 62; - if (Char == '/') return 63; - if (Char == '=') return 0; - return 0xFF; -} -static DECLSPEC_NOINLINE UCHAR -__Decode( - __in PUCHAR Dest, - __in PCHAR Src, - __in ULONG RemainingChars - ) -{ - UCHAR Values[4]; - - if (RemainingChars < 4) - return 0xFF; - - // take 4 Src chars -> 1, 2, or 3 Dest bytes - Values[0] = __DecodeChar(Src[0]); - Values[1] = __DecodeChar(Src[1]); - Values[2] = __DecodeChar(Src[2]); - Values[3] = __DecodeChar(Src[3]); - - // sanity checks - if ((Src[0] == '=' || Src[1] == '=') || - (Src[2] == '=' && Src[3] != '=')) - return 0xFF; - if (Values[0] == 0xFF || Values[1] == 0xFF || - Values[2] == 0xFF || Values[3] == 0xFF) - return 0xFF; - - // convert - Dest[0] = (Values[1] >> 4) | (Values[0] << 2); - if (Src[2] == '=') return 2; - Dest[1] = (Values[2] >> 2) | (Values[1] << 4); - if (Src[3] == '=') return 1; - Dest[2] = (Values[3] ) | (Values[2] << 6); - return 0; -} -__checkReturn -static NTSTATUS -__DecodeBase64( - __in PCHAR Base64, - __in ULONG Base64Length, - __out PVOID *_Buffer, - __out PULONG BufferLength - ) -{ - // convert Base64(4chars) into Buffer(3bytes) - PUCHAR Buffer; - ULONG NumBlocks; - ULONG i; - UCHAR Pad = 0; - - NumBlocks = Base64Length / 4; - - Buffer = (PUCHAR)__InquiryAlloc(NumBlocks * 3); - if (Buffer == NULL) { - Error("__InquiryAlloc (STATUS_INSUFFICIENT_RESOURCES)\n"); - goto fail1; - } - - for (i = 0; i < NumBlocks; ++i) { - if (Pad) goto invalid_base64; - Pad = __Decode(Buffer + (i * 3), Base64 + (i * 4), Base64Length - (i * 4)); - if (Pad > 2) goto invalid_base64; - } - - *BufferLength = (NumBlocks * 3) - Pad; - *_Buffer = Buffer; - return STATUS_SUCCESS; - -invalid_base64: - Error("Invalid BASE64 encoding\n"); - __InquiryFree((PVOID)Buffer); - return STATUS_UNSUCCESSFUL; - -fail1: - return STATUS_INSUFFICIENT_RESOURCES; -} -static DECLSPEC_NOINLINE BOOLEAN -__ReadPage( - __in PXENVBD_FRONTEND Frontend, - __in PXENVBD_PAGE Page, - __in PCHAR Path - ) -{ - NTSTATUS Status; - PCHAR Value; - - Status = FrontendStoreReadBackend(Frontend, Path, &Value); - if (!NT_SUCCESS(Status)) - goto fail1; - - Status = __DecodeBase64(Value, (ULONG)strlen(Value), (PVOID*)&Page->Data, &Page->Length); - if (!NT_SUCCESS(Status)) - goto fail2; - - FrontendStoreFree(Frontend, Value); - return TRUE; - -fail2: - FrontendStoreFree(Frontend, Value); -fail1: - Page->Data = NULL; - Page->Length = 0; - return FALSE; -} - -static FORCEINLINE BOOLEAN -__HandlePageStd( - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PINQUIRYDATA Data = (PINQUIRYDATA)Srb->DataBuffer; - ULONG Length = Srb->DataTransferLength; - - if (Length < INQUIRYDATABUFFERSIZE) - return FALSE; - - Data->DeviceType = DIRECT_ACCESS_DEVICE; - Data->DeviceTypeQualifier = DEVICE_CONNECTED; - Data->Versions = 4; - Data->ResponseDataFormat = 2; - Data->AdditionalLength = INQUIRYDATABUFFERSIZE - 4; - Data->CommandQueue = 1; - RtlCopyMemory(Data->VendorId, "XENSRC ", 8); - RtlCopyMemory(Data->ProductId, "PVDISK ", 16); - RtlCopyMemory(Data->ProductRevisionLevel, "2.0 ", 4); - - Srb->DataTransferLength = INQUIRYDATABUFFERSIZE; - return TRUE; -} -static FORCEINLINE BOOLEAN -__HandlePage00( - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PCHAR Data = (PCHAR)Srb->DataBuffer; - ULONG Length = Srb->DataTransferLength; - - if (Length < 7) - return FALSE; - RtlZeroMemory(Data, Length); - - // 00 00 00 NumPages+1 00 [Page [...]] - Data[3] = 3; - Data[4] = 0x00; - Data[5] = 0x80; - Data[6] = 0x83; - Srb->DataTransferLength = 7; - - return TRUE; -} -static FORCEINLINE BOOLEAN -__HandlePage80( - __in ULONG TargetId, - __in PXENVBD_INQUIRY Inquiry, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PCHAR Data = (PCHAR)Srb->DataBuffer; - ULONG Length = Srb->DataTransferLength; - - RtlZeroMemory(Data, Length); - if (Inquiry == NULL || - Inquiry->Page80.Data == NULL || - Inquiry->Page80.Length == 0) { - // generate the serial number page - PVPD_SERIAL_NUMBER_PAGE Serial; - if (Length < sizeof(VPD_SERIAL_NUMBER_PAGE) + 4) - return FALSE; - - Serial = (PVPD_SERIAL_NUMBER_PAGE)Data; - Serial->PageCode = 0x80; - Serial->PageLength = 4; - (VOID) RtlStringCchPrintfA((PCHAR)Serial->SerialNumber, 5, "%04u", TargetId); - - Verbose("Target[%u] : INQUIRY Using Fake Page80 Data\n", TargetId); - - Srb->DataTransferLength = sizeof(VPD_SERIAL_NUMBER_PAGE) + 4; - // VPD_SERIAL_NUMBER_PAGE includes 1 char already - } else { - if (Length < Inquiry->Page80.Length) - return FALSE; - - RtlCopyMemory(Data, Inquiry->Page80.Data, Inquiry->Page80.Length); - Srb->DataTransferLength = Inquiry->Page80.Length; - } - - // if possible, append additional data - //if (Inquiry && Length >= Srb->DataTransferLength + ADDITIONAL_LENGTH) { - // Srb->DataTransferLength += ADDITIONAL_LENGTH; - //} - return TRUE; -} -static FORCEINLINE BOOLEAN -__HandlePage83( - __in ULONG TargetId, - __in PXENVBD_INQUIRY Inquiry, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PCHAR Data = (PCHAR)Srb->DataBuffer; - ULONG Length = Srb->DataTransferLength; - - RtlZeroMemory(Data, Length); - if (Inquiry == NULL || - Inquiry->Page83.Data == NULL || - Inquiry->Page83.Length == 0) { - // generate the id page data - PVPD_IDENTIFICATION_DESCRIPTOR Id; - CHAR Buffer[17]; - - if (Length < PAGE83_MIN_SIZE) - return FALSE; - - Data[1] = 0x83; - Data[3] = 16; - - Id = (PVPD_IDENTIFICATION_DESCRIPTOR)(Data + 4); - Id->CodeSet = VpdCodeSetAscii; - Id->IdentifierType = VpdIdentifierTypeVendorId; - Id->IdentifierLength = 16; - (VOID)RtlStringCchPrintfA(Buffer, 17, "XENSRC %08u", TargetId); - RtlCopyMemory((PCHAR)Id->Identifier, Buffer, 16); - - Verbose("Target[%u] : INQUIRY Using Fake Page83 Data\n", TargetId); - - Srb->DataTransferLength = PAGE83_MIN_SIZE; - } else { - if (Length < Inquiry->Page83.Length) - return FALSE; - - RtlCopyMemory(Data, Inquiry->Page83.Data, Inquiry->Page83.Length); - Srb->DataTransferLength = Inquiry->Page83.Length; - } - - // if possible, append vdi-uuid as VendorSpecific - if (Inquiry && Length >= Srb->DataTransferLength + VDI_ID_LENGTH) { - PVPD_IDENTIFICATION_DESCRIPTOR Id; - - // update internal size - *(Data + 3) += VDI_ID_LENGTH; - - // copy new data - Id = (PVPD_IDENTIFICATION_DESCRIPTOR)(Data + Srb->DataTransferLength); - Id->CodeSet = VpdCodeSetAscii; - Id->IdentifierType = VpdIdentifierTypeVendorSpecific; - Id->IdentifierLength = GUID_LENGTH; - RtlCopyMemory(Id->Identifier, Inquiry->VdiUuid, GUID_LENGTH); - - Srb->DataTransferLength += VDI_ID_LENGTH; - } - return TRUE; -} - -#define MAX_BUFFER 64 - -static FORCEINLINE VOID -__TracePage80( - __in ULONG TargetId, - __in PXENVBD_INQUIRY Inquiry - ) -{ - ULONG Length; - CHAR Buffer[MAX_BUFFER+1]; - - Length = __Min3(Inquiry->Page80.Data[3], MAX_BUFFER, Inquiry->Page80.Length - 4); - RtlCopyMemory(Buffer, Inquiry->Page80.Data + 4, Length); - Buffer[Length] = 0; - Verbose("Target[%u] : SerialNumber = \"%s\"\n", TargetId, Buffer); -} -static FORCEINLINE VOID -__TracePage83( - __in ULONG TargetId, - __in PXENVBD_INQUIRY Inquiry - ) -{ - ULONG Length; - ULONG Index; - CHAR Buffer[MAX_BUFFER+1]; - - for (Index = 4; Index < Inquiry->Page83.Length; ) { - PVPD_IDENTIFICATION_DESCRIPTOR Identifier = (PVPD_IDENTIFICATION_DESCRIPTOR)&Inquiry->Page83.Data[Index]; - - switch (Identifier->CodeSet) { - case VpdCodeSetAscii: - Length = __Min3(Identifier->IdentifierLength, MAX_BUFFER, Inquiry->Page83.Length - Index - 4); - RtlCopyMemory(Buffer, Identifier->Identifier, Length); - Buffer[Length] = 0; - Verbose("Target[%u] : Identifier (ASCII, Type %02x, \"%s\")\n", - TargetId, Identifier->IdentifierType, Buffer); - break; - - default: - Verbose("Target[%u] : Identifier (CodeSet %02x, Type %02x, Length %02x)\n", - TargetId, Identifier->CodeSet, Identifier->IdentifierType, Identifier->IdentifierLength); - break; - } - - Index += (4 + Identifier->IdentifierLength); - } -} - -VOID -#pragma warning(suppress: 28195) -PdoReadInquiryData( - __in PXENVBD_FRONTEND Frontend, - __out __drv_allocatesMem(mem) PVOID* _Inquiry - ) -{ - PXENVBD_INQUIRY Inquiry; - const CHAR GuidNull[] = "00000000-0000-0000-0000-000000000000"; - const ULONG TargetId = FrontendGetTargetId(Frontend); - - *_Inquiry = NULL; - Inquiry = (PXENVBD_INQUIRY)__InquiryAlloc(sizeof(XENVBD_INQUIRY)); - if (Inquiry == NULL) { - Error("Target[%d] : Memory allocation getting INQUIRY data (%d bytes failed)\n", - TargetId, sizeof(XENVBD_INQUIRY)); - return; - } - - // initialize VDI-UUID - RtlCopyMemory(Inquiry->VdiUuid, GuidNull, GUID_LENGTH); - Inquiry->VdiUuid[GUID_LENGTH] = 0; - - // read page80 - if (!__ReadPage(Frontend, &Inquiry->Page80, "sm-data/scsi/0x12/0x80")) { - Warning("Target[%d] : Failed to get Page80 data\n", TargetId); - } else { - __TracePage80(TargetId, Inquiry); - } - - // read page83 - if (!__ReadPage(Frontend, &Inquiry->Page83, "sm-data/scsi/0x12/0x83")) { - Warning("Target[%d] : Failed to get Page83 data\n", TargetId); - } else { - __TracePage83(TargetId, Inquiry); - } - - *_Inquiry = Inquiry; -} - -VOID -PdoFreeInquiryData( - __in __drv_freesMem(mem) PVOID _Inquiry - ) -{ - PXENVBD_INQUIRY Inquiry = (PXENVBD_INQUIRY)_Inquiry; - - if (_Inquiry == NULL) - return; - - __InquiryFree((PVOID)Inquiry->Page80.Data); - __InquiryFree((PVOID)Inquiry->Page83.Data); - __InquiryFree((PVOID)Inquiry); -} - -VOID -PdoUpdateInquiryData( - __in PXENVBD_FRONTEND Frontend, - __in PVOID _Inquiry - ) -{ - PXENVBD_INQUIRY Inquiry = (PXENVBD_INQUIRY)_Inquiry; - NTSTATUS Status; - PCHAR Value; - ULONG Length; - const CHAR GuidNull[] = "00000000-0000-0000-0000-000000000000"; - - if (_Inquiry == NULL) - return; - - RtlCopyMemory(Inquiry->VdiUuid, GuidNull, GUID_LENGTH); - Inquiry->VdiUuid[GUID_LENGTH] = 0; - - Status = FrontendStoreReadBackend(Frontend, "sm-data/vdi-uuid", &Value); - if (NT_SUCCESS(Status)) { - Length = (ULONG)strlen(Value); - - if (Length == GUID_LENGTH) { - RtlCopyMemory(Inquiry->VdiUuid, Value, Length); - Inquiry->VdiUuid[GUID_LENGTH] = 0; - } - - FrontendStoreFree(Frontend, Value); - } - - Verbose("Target[%u] : VDI-UUID = {%s}\n", FrontendGetTargetId(Frontend), Inquiry->VdiUuid); -} - -VOID -PdoInquiry( - __in ULONG TargetId, - __in PVOID Inquiry, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - BOOLEAN Success; - const UCHAR Evpd = Cdb_EVPD(Srb); - const UCHAR PageCode = Cdb_PageCode(Srb); - - Trace("Target[%d] : INQUIRY %02x%s\n", TargetId, PageCode, Evpd ? " EVPD" : ""); - if (Evpd) { - switch (PageCode) { - case 0x00: Success = __HandlePage00(Srb); break; - case 0x80: Success = __HandlePage80(TargetId, (PXENVBD_INQUIRY)Inquiry, Srb); break; - case 0x83: Success = __HandlePage83(TargetId, (PXENVBD_INQUIRY)Inquiry, Srb); break; - default: Success = FALSE; break; - } - } else { - switch (PageCode) { - case 0x00: Success = __HandlePageStd(Srb); break; - default: Success = FALSE; break; - } - } - - if (Success) { - Srb->ScsiStatus = 0; /* SUCCESS */ - Srb->SrbStatus = SRB_STATUS_SUCCESS; - } else { - Error("Target[%d] : INQUIRY failed %02x%s\n", TargetId, PageCode, Evpd ? " EVPD" : ""); - Srb->ScsiStatus = 0x02; /* CHECK_CONDITION */ - Srb->SrbStatus = SRB_STATUS_ERROR; - } -} diff --git a/src/xenvbd/pdoinquiry.h b/src/xenvbd/pdoinquiry.h deleted file mode 100644 index a8cb155..0000000 --- a/src/xenvbd/pdoinquiry.h +++ /dev/null @@ -1,64 +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_INQUIRY_H -#define _XENVBD_PDO_INQUIRY_H - -#include <ntddk.h> -#include <xenvbd-storport.h> -#include "frontend.h" - -extern VOID -PdoReadInquiryData( - __in PXENVBD_FRONTEND Frontend, - __out __drv_allocatesMem(mem) PVOID* _Inquiry - ); - -extern VOID -PdoFreeInquiryData( - __in __drv_freesMem(mem) PVOID Inquiry - ); - -extern VOID -PdoUpdateInquiryData( - __in PXENVBD_FRONTEND Frontend, - __in PVOID _Inquiry - ); - -extern VOID -PdoInquiry( - __in ULONG TargetId, - __in PVOID Inquiry, - __in PSCSI_REQUEST_BLOCK Srb - ); - -#endif // _XENVBD_PDO_INQUIRY_H - diff --git a/src/xenvbd/queue.c b/src/xenvbd/queue.c deleted file mode 100644 index fc70459..0000000 --- a/src/xenvbd/queue.c +++ /dev/null @@ -1,139 +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 "queue.h" -#include "debug.h" -#include "assert.h" - -VOID -QueueInit( - __in PXENVBD_QUEUE Queue - ) -{ - RtlZeroMemory(Queue, sizeof(XENVBD_QUEUE)); - KeInitializeSpinLock(&Queue->Lock); - InitializeListHead(&Queue->List); -} - -ULONG -QueueCount( - __in PXENVBD_QUEUE Queue - ) -{ - return Queue->Current; -} - -__checkReturn -PLIST_ENTRY -QueuePop( - __in PXENVBD_QUEUE Queue - ) -{ - KIRQL Irql; - PLIST_ENTRY Entry = NULL; - - KeAcquireSpinLock(&Queue->Lock, &Irql); - - if (!IsListEmpty(&Queue->List)) { - Entry = RemoveHeadList(&Queue->List); - ASSERT3P(Entry, !=, &Queue->List); - --Queue->Current; - } - - KeReleaseSpinLock(&Queue->Lock, Irql); - - return Entry; -} - -VOID -QueueUnPop( - __in PXENVBD_QUEUE Queue, - __in PLIST_ENTRY Entry - ) -{ - KIRQL Irql; - - KeAcquireSpinLock(&Queue->Lock, &Irql); - - InsertHeadList(&Queue->List, Entry); - if (++Queue->Current > Queue->Maximum) - Queue->Maximum = Queue->Current; - - KeReleaseSpinLock(&Queue->Lock, Irql); -} - -VOID -QueueAppend( - __in PXENVBD_QUEUE Queue, - __in PLIST_ENTRY Entry - ) -{ - KIRQL Irql; - - KeAcquireSpinLock(&Queue->Lock, &Irql); - - InsertTailList(&Queue->List, Entry); - if (++Queue->Current > Queue->Maximum) - Queue->Maximum = Queue->Current; - - KeReleaseSpinLock(&Queue->Lock, Irql); -} - -VOID -QueueRemove( - __in PXENVBD_QUEUE Queue, - __in PLIST_ENTRY Entry - ) -{ - KIRQL Irql; - - KeAcquireSpinLock(&Queue->Lock, &Irql); - - RemoveEntryList(Entry); - --Queue->Current; - - KeReleaseSpinLock(&Queue->Lock, Irql); -} - -VOID -QueueDebugCallback( - __in PXENVBD_QUEUE Queue, - __in __nullterminated const CHAR* Name, - __in PXENBUS_DEBUG_INTERFACE Debug - ) -{ - XENBUS_DEBUG(Printf, Debug, - "QUEUE: %s : %u / %u\n", - Name, Queue->Current, Queue->Maximum); - - Queue->Maximum = Queue->Current; -} - diff --git a/src/xenvbd/queue.h b/src/xenvbd/queue.h deleted file mode 100644 index 0434198..0000000 --- a/src/xenvbd/queue.h +++ /dev/null @@ -1,86 +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_QUEUE_H -#define _XENVBD_QUEUE_H - -#include <ntddk.h> -#include <debug_interface.h> - -typedef struct _XENVBD_QUEUE { - KSPIN_LOCK Lock; - LIST_ENTRY List; - ULONG Current; - ULONG Maximum; -} XENVBD_QUEUE, *PXENVBD_QUEUE; - -extern VOID -QueueInit( - __in PXENVBD_QUEUE Queue - ); - -extern ULONG -QueueCount( - __in PXENVBD_QUEUE Queue - ); - -__checkReturn -extern PLIST_ENTRY -QueuePop( - __in PXENVBD_QUEUE Queue - ); - -extern VOID -QueueUnPop( - __in PXENVBD_QUEUE Queue, - __in PLIST_ENTRY Entry - ); - -extern VOID -QueueAppend( - __in PXENVBD_QUEUE Queue, - __in PLIST_ENTRY Entry - ); - -extern VOID -QueueRemove( - __in PXENVBD_QUEUE Queue, - __in PLIST_ENTRY Entry - ); - -extern VOID -QueueDebugCallback( - __in PXENVBD_QUEUE Queue, - __in __nullterminated const CHAR* Name, - __in PXENBUS_DEBUG_INTERFACE Debug - ); - -#endif // _XENVBD_QUEUE_H diff --git a/src/xenvbd/srbext.h b/src/xenvbd/srbext.h index 51b5e77..2e79de8 100644 --- a/src/xenvbd/srbext.h +++ b/src/xenvbd/srbext.h @@ -37,6 +37,27 @@ #include <xen.h> #include "assert.h" +typedef struct _XENVBD_SRBEXT { + PSCSI_REQUEST_BLOCK Srb; + LIST_ENTRY ListEntry; + LONG RequestCount; +} XENVBD_SRBEXT, *PXENVBD_SRBEXT; + +typedef struct _XENVBD_REQUEST { + PXENVBD_SRBEXT SrbExt; + LIST_ENTRY ListEntry; + ULONG64 Id; // = (ULONG64)(ULONG_PTR)this + + UCHAR Operation; // BLKIF_OP_{READ/WRITE/BARRIER/DISCARD} + UCHAR Flags; // BLKIF_OP_DISCARD only + USHORT NrSegments; // BLKIF_OP_{READ/WRITE} only, 0-11 (direct) or 11-4096 (indirect) + LIST_ENTRY Segments; // BLKIF_OP_{READ/WRITE} only + + ULONG64 FirstSector; + ULONG64 NrSectors; // BLKIF_OP_DISCARD only + LIST_ENTRY Indirects; // BLKIF_OP_{READ/WRITE} with NrSegments > 11 only +} XENVBD_REQUEST, *PXENVBD_REQUEST; + #pragma pack(push, 1) typedef struct _BLKIF_SEGMENT { ULONG GrantRef; @@ -46,19 +67,18 @@ typedef struct _BLKIF_SEGMENT { } BLKIF_SEGMENT, *PBLKIF_SEGMENT; #pragma pack(pop) -#define XENVBD_MAX_SEGMENTS_PER_PAGE (PAGE_SIZE / sizeof(BLKIF_SEGMENT)) +#define XENVBD_MAX_SEGMENTS_PER_PAGE (PAGE_SIZE / sizeof(BLKIF_SEGMENT)) +#define XENVBD_MAX_SEGMENTS_PER_INDIRECT (XENVBD_MAX_SEGMENTS_PER_PAGE * 2) // limited Indirecting -// Internal indirect context typedef struct _XENVBD_INDIRECT { - LIST_ENTRY Entry; + LIST_ENTRY ListEntry; PBLKIF_SEGMENT Page; PVOID Grant; PMDL Mdl; } XENVBD_INDIRECT, *PXENVBD_INDIRECT; -// Internal segment context typedef struct _XENVBD_SEGMENT { - LIST_ENTRY Entry; + LIST_ENTRY ListEntry; PVOID Grant; UCHAR FirstSector; UCHAR LastSector; @@ -69,27 +89,4 @@ typedef struct _XENVBD_SEGMENT { PFN_NUMBER Pfn[2]; } XENVBD_SEGMENT, *PXENVBD_SEGMENT; -// Internal request context -typedef struct _XENVBD_REQUEST { - PSCSI_REQUEST_BLOCK Srb; - LIST_ENTRY Entry; - ULONG Id; - - UCHAR Operation; // BLKIF_OP_{READ/WRITE/BARRIER/DISCARD} - UCHAR Flags; // BLKIF_OP_DISCARD only - USHORT NrSegments; // BLKIF_OP_{READ/WRITE} only, 0-11 (direct) or 11-4096 (indirect) - LIST_ENTRY Segments; // BLKIF_OP_{READ/WRITE} only - - ULONG64 FirstSector; - ULONG64 NrSectors; // BLKIF_OP_DISCARD only - LIST_ENTRY Indirects; // BLKIF_OP_{READ/WRITE} with NrSegments > 11 only -} XENVBD_REQUEST, *PXENVBD_REQUEST; - -// SRBExtension - context for SRBs -typedef struct _XENVBD_SRBEXT { - PSCSI_REQUEST_BLOCK Srb; - LIST_ENTRY ListEntry; - LONG RequestCount; -} XENVBD_SRBEXT, *PXENVBD_SRBEXT; - #endif // _XENVBD_SRBEXT_H diff --git a/src/xenvbd/target.c b/src/xenvbd/target.c index c939738..5b14a73 100644 --- a/src/xenvbd/target.c +++ b/src/xenvbd/target.c @@ -37,25 +37,91 @@ #include <xencdb.h> #include <names.h> #include <store_interface.h> -#include <evtchn_interface.h> -#include <gnttab_interface.h> #include <debug_interface.h> #include <suspend_interface.h> #include "target.h" #include "driver.h" #include "adapter.h" -#include "frontend.h" -#include "queue.h" +#include "thread.h" #include "srbext.h" #include "buffer.h" -#include "pdoinquiry.h" +#include "granter.h" +#include "blockring.h" #include "util.h" #include "debug.h" #include "assert.h" -#define XENVBD_MAX_QUEUE_DEPTH (254) +#define TARGET_POOL_TAG 'raTX' +#define REQUEST_POOL_TAG 'qeRX' +#define SEGMENT_POOL_TAG 'geSX' +#define INDIRECT_POOL_TAG 'dnIX' +#define XENVBD_MAX_QUEUE_DEPTH (254) + +typedef enum _XENVBD_STATE { + XENVBD_STATE_INVALID, + XENVBD_INITIALIZED, // -> { CLOSED } + XENVBD_CLOSING, // -> { CLOSED } + XENVBD_CLOSED, // -> { PREPARED } + XENVBD_PREPARED, // -> { CLOSING, CONNECTED } + XENVBD_CONNECTED, // -> { ENABLED, CLOSING } + XENVBD_ENABLED // -> { CLOSING } +} XENVBD_STATE; + +struct _XENVBD_TARGET { + PXENVBD_ADAPTER Adapter; + PDEVICE_OBJECT DeviceObject; + DEVICE_PNP_STATE PrevPnpState; + DEVICE_PNP_STATE DevicePnpState; + DEVICE_POWER_STATE DevicePowerState; + XENVBD_STATE State; + KSPIN_LOCK StateLock; + KSPIN_LOCK QueueLock; + BOOLEAN Missing; + PXENVBD_GRANTER Granter; + PXENVBD_BLOCKRING BlockRing; + + ULONG DeviceId; + ULONG TargetId; + PCHAR Path; + PCHAR TargetPath; + PCHAR BackendPath; + USHORT BackendId; + + BOOLEAN DeviceUsage[4]; + ULONG64 SectorCount; + ULONG SectorSize; + ULONG PhysicalSectorSize; + ULONG DiskInfo; + BOOLEAN Removable; + BOOLEAN FeatureBarrier; + BOOLEAN FeatureFlush; + BOOLEAN FeatureDiscard; + BOOLEAN DiscardSecure; + ULONG DiscardAlignment; + ULONG DiscardGranularity; + ULONG FeatureIndirect; + + XENBUS_DEBUG_INTERFACE DebugInterface; + XENBUS_SUSPEND_INTERFACE SuspendInterface; + XENBUS_STORE_INTERFACE StoreInterface; + + PXENBUS_DEBUG_CALLBACK DebugCallback; + PXENBUS_SUSPEND_CALLBACK SuspendCallback; + + PXENVBD_THREAD BackendThread; + PXENBUS_STORE_WATCH BackendWatch; + + LIST_ENTRY Fresh; + LIST_ENTRY Prepared; + LIST_ENTRY Submitted; + LIST_ENTRY Shutdown; + + NPAGED_LOOKASIDE_LIST RequestList; + NPAGED_LOOKASIDE_LIST SegmentList; + NPAGED_LOOKASIDE_LIST IndirectList; +}; typedef struct _XENVBD_SG_LIST { // SGList from SRB @@ -69,182 +135,129 @@ typedef struct _XENVBD_SG_LIST { ULONG Length; } XENVBD_SG_LIST, *PXENVBD_SG_LIST; -#define TARGET_SIGNATURE 'odpX' +static FORCEINLINE VOID +SGListInit( + IN OUT PXENVBD_SG_LIST SGList, + IN PVOID Adapter, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + RtlZeroMemory(SGList, sizeof(XENVBD_SG_LIST)); + SGList->SGList = StorPortGetScatterGatherList(Adapter, Srb); +} -typedef struct _XENVBD_LOOKASIDE { - KEVENT Empty; - LONG Used; - LONG Max; - ULONG Failed; - ULONG Size; - NPAGED_LOOKASIDE_LIST List; -} XENVBD_LOOKASIDE, *PXENVBD_LOOKASIDE; +static FORCEINLINE VOID +SGListGet( + IN OUT PXENVBD_SG_LIST SGList + ) +{ + PSTOR_SCATTER_GATHER_ELEMENT SGElement; + ULONG Offset; -struct _XENVBD_TARGET { - ULONG Signature; - PXENVBD_ADAPTER Adapter; - PDEVICE_OBJECT DeviceObject; - DEVICE_PNP_STATE DevicePnpState; - DEVICE_PNP_STATE PrevPnpState; - DEVICE_POWER_STATE DevicePowerState; - KSPIN_LOCK Lock; + ASSERT3U(SGList->Index, <, SGList->SGList->NumberOfElements); - // Frontend (Ring, includes XenBus interfaces) - PXENVBD_FRONTEND Frontend; + SGElement = &SGList->SGList->List[SGList->Index]; - // State - LONG Paused; + SGList->PhysAddr.QuadPart = SGElement->PhysicalAddress.QuadPart + SGList->Offset; + Offset = (ULONG)(SGList->PhysAddr.QuadPart & (PAGE_SIZE - 1)); + SGList->PhysLen = __min(PAGE_SIZE - Offset - SGList->Length, + SGElement->Length - SGList->Offset); - // 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; -}; + ASSERT3U(SGList->PhysLen, <=, PAGE_SIZE); + ASSERT3U(SGList->Offset, <, SGElement->Length); -//============================================================================= -#define TARGET_POOL_TAG 'odPX' -#define REQUEST_POOL_TAG 'qeRX' -#define SEGMENT_POOL_TAG 'geSX' -#define INDIRECT_POOL_TAG 'dnIX' + 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; + } +} -__checkReturn -__drv_allocatesMem(mem) -__bcount(Size) -static FORCEINLINE PVOID -#pragma warning(suppress: 28195) -__TargetAlloc( - __in ULONG Size +static FORCEINLINE BOOLEAN +SGListNext( + IN OUT PXENVBD_SG_LIST SGList, + IN ULONG AlignmentMask ) { - return __AllocatePoolWithTag(NonPagedPool, Size, TARGET_POOL_TAG); + SGList->Length = 0; + SGListGet(SGList); // get next PhysAddr and PhysLen + return !((SGList->PhysAddr.QuadPart & AlignmentMask) || (SGList->PhysLen & AlignmentMask)); } -static FORCEINLINE VOID -#pragma warning(suppress: 28197) -__TargetFree( - __in __drv_freesMem(mem) PVOID Buffer +static FORCEINLINE PFN_NUMBER +SGListPfn( + IN PXENVBD_SG_LIST SGList ) { - if (Buffer) - __FreePoolWithTag(Buffer, TARGET_POOL_TAG); + return (PFN_NUMBER)(SGList->PhysAddr.QuadPart >> PAGE_SHIFT); } -//============================================================================= -// Lookasides -static FORCEINLINE VOID -__LookasideInit( - IN OUT PXENVBD_LOOKASIDE Lookaside, - IN ULONG Size, - IN ULONG Tag +static FORCEINLINE ULONG +SGListOffset( + IN PXENVBD_SG_LIST SGList ) { - RtlZeroMemory(Lookaside, sizeof(XENVBD_LOOKASIDE)); - Lookaside->Size = Size; - KeInitializeEvent(&Lookaside->Empty, SynchronizationEvent, TRUE); - ExInitializeNPagedLookasideList(&Lookaside->List, NULL, NULL, 0, - Size, Tag, 0); + return (ULONG)(SGList->PhysAddr.QuadPart & (PAGE_SIZE - 1)); } -static FORCEINLINE VOID -__LookasideTerm( - IN PXENVBD_LOOKASIDE Lookaside +static FORCEINLINE ULONG +SGListLength( + IN PXENVBD_SG_LIST SGList ) { - ASSERT3U(Lookaside->Used, ==, 0); - ExDeleteNPagedLookasideList(&Lookaside->List); - RtlZeroMemory(Lookaside, sizeof(XENVBD_LOOKASIDE)); + return SGList->PhysLen; } static FORCEINLINE PVOID -__LookasideAlloc( - IN PXENVBD_LOOKASIDE Lookaside +__TargetAllocate( + IN ULONG Size ) { - 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); - + PVOID Buffer; + Buffer = ExAllocatePoolWithTag(NonPagedPool, + Size, + TARGET_POOL_TAG); + if (Buffer) + RtlZeroMemory(Buffer, Size); return Buffer; } static FORCEINLINE VOID -__LookasideFree( - IN PXENVBD_LOOKASIDE Lookaside, - IN PVOID Buffer +__TargetFree( + IN PVOID Buffer ) { - LONG Result; + if (Buffer) + ExFreePoolWithTag(Buffer, TARGET_POOL_TAG); +} - ExFreeToNPagedLookasideList(&Lookaside->List, Buffer); - Result = InterlockedDecrement(&Lookaside->Used); - ASSERT3S(Result, >=, 0); - - if (Result == 0) { - KeSetEvent(&Lookaside->Empty, IO_NO_INCREMENT, FALSE); - } +#define TARGET_GET_PROPERTY(_name, _type) \ +_type \ +TargetGet ## _name ## ( \ + IN PXENVBD_TARGET Target \ + ) \ +{ \ + return Target-> ## _name ## ; \ } -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); +TARGET_GET_PROPERTY(DeviceId, ULONG) +TARGET_GET_PROPERTY(TargetId, ULONG) +TARGET_GET_PROPERTY(DeviceObject, PDEVICE_OBJECT) +TARGET_GET_PROPERTY(Missing, BOOLEAN) +TARGET_GET_PROPERTY(DevicePnpState, DEVICE_PNP_STATE) +TARGET_GET_PROPERTY(Adapter, PXENVBD_ADAPTER) +TARGET_GET_PROPERTY(Granter, PXENVBD_GRANTER) +TARGET_GET_PROPERTY(Path, PCHAR) +TARGET_GET_PROPERTY(BackendPath, PCHAR) +TARGET_GET_PROPERTY(BackendId, USHORT) +TARGET_GET_PROPERTY(Removable, BOOLEAN) - Lookaside->Max = Lookaside->Used; - Lookaside->Failed = 0; -} +#undef TARGET_GET_PROPERTY -//============================================================================= -// Debug static FORCEINLINE PCHAR -__PnpStateName( - __in DEVICE_PNP_STATE State +DevicePnpStateName( + IN DEVICE_PNP_STATE State ) { switch (State) { @@ -258,294 +271,81 @@ __PnpStateName( 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: 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; + default: return "<UNKNOWN>"; } - 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 +static FORCEINLINE VOID +TargetRestoreDevicePnpState( + IN PXENVBD_TARGET Target ) { - KIRQL Irql; - const CHAR* Reason; - - KeAcquireSpinLock(&Target->Lock, &Irql); - Reason = Target->Reason; - KeReleaseSpinLock(&Target->Lock, Irql); - - return Reason; + Verbose("[%u] %s --> %s\n", + Target->TargetId, + DevicePnpStateName(Target->DevicePnpState), + DevicePnpStateName(Target->PrevPnpState)); + Target->DevicePnpState = Target->PrevPnpState; } -FORCEINLINE VOID +VOID TargetSetDevicePnpState( - __in PXENVBD_TARGET Target, - __in DEVICE_PNP_STATE State + 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; - + Verbose("[%u] %s --> %s\n", + Target->TargetId, + DevicePnpStateName(Target->DevicePnpState), + DevicePnpStateName(State)); 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; - } -} - -//============================================================================= -// Query Methods -FORCEINLINE ULONG -TargetGetTargetId( - __in PXENVBD_TARGET Target - ) -{ - ASSERT3P(Target, !=, NULL); - return FrontendGetTargetId(Target->Frontend); -} - -ULONG -TargetGetDeviceId( - __in PXENVBD_TARGET Target - ) -{ - ASSERT3P(Target, !=, NULL); - return FrontendGetDeviceId(Target->Frontend); -} - -__checkReturn -FORCEINLINE PDEVICE_OBJECT -TargetGetDeviceObject( - __in PXENVBD_TARGET Target - ) -{ - ASSERT3P(Target, !=, NULL); - return Target->DeviceObject; -} - -FORCEINLINE VOID +VOID TargetSetDeviceObject( - __in PXENVBD_TARGET Target, - __in PDEVICE_OBJECT DeviceObject + IN PXENVBD_TARGET Target, + IN PDEVICE_OBJECT DeviceObject ) { - Verbose("Target[%d] : Setting DeviceObject = 0x%p\n", TargetGetTargetId(Target), DeviceObject); - - ASSERT3P(Target->DeviceObject, ==, NULL); + Verbose("[%u] DevObj = 0x%p\n", + Target->TargetId, + DeviceObject); 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 +VOID +TargetSetMissing( + IN PXENVBD_TARGET Target, + IN const CHAR* Reason ) { - return FrontendGetDiskInfo(Target->Frontend)->SectorSize; + Verbose("[%u] Missing: %s\n", Target->TargetId, Reason); + Target->Missing = TRUE; } -//============================================================================= static PXENVBD_INDIRECT TargetGetIndirect( - IN PXENVBD_TARGET Target + IN PXENVBD_TARGET Target ) { PXENVBD_INDIRECT Indirect; NTSTATUS status; - PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); - Indirect = __LookasideAlloc(&Target->IndirectList); + Indirect = ExAllocateFromNPagedLookasideList(&Target->IndirectList); if (Indirect == NULL) goto fail1; RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); + InitializeListHead(&Indirect->ListEntry); Indirect->Mdl = __AllocatePage(); if (Indirect->Mdl == NULL) goto fail2; Indirect->Page = MmGetSystemAddressForMdlSafe(Indirect->Mdl, NormalPagePriority); + ASSERT(Indirect->Page != NULL); - status = GranterGet(Granter, + status = GranterGet(Target->Granter, MmGetMdlPfnArray(Indirect->Mdl)[0], TRUE, &Indirect->Grant); @@ -557,40 +357,43 @@ TargetGetIndirect( fail3: __FreePage(Indirect->Mdl); fail2: - __LookasideFree(&Target->IndirectList, Indirect); + RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); + ExFreeToNPagedLookasideList(&Target->IndirectList, Indirect); fail1: return NULL; } static VOID TargetPutIndirect( - IN PXENVBD_TARGET Target, - IN PXENVBD_INDIRECT Indirect + IN PXENVBD_TARGET Target, + IN PXENVBD_INDIRECT Indirect ) { - PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); - if (Indirect->Grant) - GranterPut(Granter, Indirect->Grant); + GranterPut(Target->Granter, Indirect->Grant); + if (Indirect->Page) __FreePage(Indirect->Mdl); RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); - __LookasideFree(&Target->IndirectList, Indirect); + ExFreeToNPagedLookasideList(&Target->IndirectList, Indirect); } static PXENVBD_SEGMENT TargetGetSegment( - IN PXENVBD_TARGET Target + IN PXENVBD_TARGET Target ) { - PXENVBD_SEGMENT Segment; + PXENVBD_SEGMENT Segment; - Segment = __LookasideAlloc(&Target->SegmentList); + Segment = ExAllocateFromNPagedLookasideList(&Target->SegmentList); if (Segment == NULL) goto fail1; RtlZeroMemory(Segment, sizeof(XENVBD_SEGMENT)); + + InitializeListHead(&Segment->ListEntry); + return Segment; fail1: @@ -599,38 +402,38 @@ fail1: static VOID TargetPutSegment( - IN PXENVBD_TARGET Target, - IN PXENVBD_SEGMENT Segment + IN PXENVBD_TARGET Target, + IN PXENVBD_SEGMENT Segment ) { - PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); - if (Segment->Grant) - GranterPut(Granter, Segment->Grant); + GranterPut(Target->Granter, Segment->Grant); + + if (Segment->Buffer) + MmUnmapLockedPages(Segment->Buffer, &Segment->Mdl); if (Segment->BufferId) BufferPut(Segment->BufferId); - if (Segment->Buffer) - MmUnmapLockedPages(Segment->Buffer, &Segment->Mdl); - RtlZeroMemory(Segment, sizeof(XENVBD_SEGMENT)); - __LookasideFree(&Target->SegmentList, Segment); + ExFreeToNPagedLookasideList(&Target->SegmentList, Segment); } static PXENVBD_REQUEST TargetGetRequest( - IN PXENVBD_TARGET Target + IN PXENVBD_TARGET Target ) { - PXENVBD_REQUEST Request; + PXENVBD_REQUEST Request; - Request = __LookasideAlloc(&Target->RequestList); + Request = ExAllocateFromNPagedLookasideList(&Target->RequestList); if (Request == NULL) goto fail1; RtlZeroMemory(Request, sizeof(XENVBD_REQUEST)); - Request->Id = (ULONG)InterlockedIncrement((PLONG)&Target->NextTag); + Request->Id = (ULONG64)(ULONG_PTR)Request; + + InitializeListHead(&Request->ListEntry); InitializeListHead(&Request->Segments); InitializeListHead(&Request->Indirects); @@ -642,1694 +445,2398 @@ fail1: static VOID TargetPutRequest( - IN PXENVBD_TARGET Target, - IN PXENVBD_REQUEST Request + IN PXENVBD_TARGET Target, + IN PXENVBD_REQUEST Request ) { - PLIST_ENTRY Entry; - for (;;) { - PXENVBD_SEGMENT Segment; + PLIST_ENTRY ListEntry; + PXENVBD_INDIRECT Indirect; - Entry = RemoveHeadList(&Request->Segments); - if (Entry == &Request->Segments) + ListEntry = RemoveHeadList(&Request->Indirects); + if (ListEntry == &Request->Indirects) break; - Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); - TargetPutSegment(Target, Segment); - } + Indirect = CONTAINING_RECORD(ListEntry, XENVBD_INDIRECT, ListEntry); + TargetPutIndirect(Target, Indirect); + } for (;;) { - PXENVBD_INDIRECT Indirect; + PLIST_ENTRY ListEntry; + PXENVBD_SEGMENT Segment; - Entry = RemoveHeadList(&Request->Indirects); - if (Entry == &Request->Indirects) + ListEntry = RemoveHeadList(&Request->Segments); + if (ListEntry == &Request->Segments) break; - Indirect = CONTAINING_RECORD(Entry, XENVBD_INDIRECT, Entry); - TargetPutIndirect(Target, Indirect); + + Segment = CONTAINING_RECORD(ListEntry, XENVBD_SEGMENT, ListEntry); + TargetPutSegment(Target, Segment); } RtlZeroMemory(Request, sizeof(XENVBD_REQUEST)); - __LookasideFree(&Target->RequestList, Request); + ExFreeToNPagedLookasideList(&Target->RequestList, Request); } -static FORCEINLINE PXENVBD_REQUEST -TargetRequestFromTag( - IN PXENVBD_TARGET Target, - IN ULONG Tag +static FORCEINLINE BOOLEAN +BufferMap( + IN PXENVBD_SEGMENT Segment, + IN PXENVBD_SG_LIST SGList, + IN ULONG Length ) { - 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; - } + // map PhysAddr to 1 or 2 pages and lock for VirtAddr +#pragma warning(push) +#pragma warning(disable:28145) + Segment->Mdl.Next = NULL; + Segment->Mdl.Size = (SHORT)(sizeof(MDL) + sizeof(PFN_NUMBER)); + Segment->Mdl.MdlFlags = MDL_PAGES_LOCKED; + Segment->Mdl.Process = NULL; + Segment->Mdl.MappedSystemVa = NULL; + Segment->Mdl.StartVa = NULL; + Segment->Mdl.ByteCount = SGListLength(SGList); + Segment->Mdl.ByteOffset = SGListOffset(SGList); + Segment->Pfn[0] = SGListPfn(SGList); + + if (Segment->Mdl.ByteCount < Length) { + // need part of next page + SGListGet(SGList); + Segment->Mdl.Size += sizeof(PFN_NUMBER); + Segment->Mdl.ByteCount = Segment->Mdl.ByteCount + SGListLength(SGList); + Segment->Pfn[1] = SGListPfn(SGList); } +#pragma warning(pop) - KeReleaseSpinLock(&Queue->Lock, Irql); - Warning("Target[%d] : Tag %x not found in submitted list (%u items)\n", - TargetGetTargetId(Target), Tag, QueueCount(Queue)); - return NULL; -} + ASSERT3U(Segment->Mdl.ByteCount, <=, PAGE_SIZE); + ASSERT3U(Segment->Mdl.ByteCount, ==, Length); + + Segment->Length = min(Segment->Mdl.ByteCount, PAGE_SIZE); + Segment->Buffer = MmMapLockedPagesSpecifyCache(&Segment->Mdl, + KernelMode, + MmCached, + NULL, + FALSE, + NormalPagePriority); + if (Segment->Buffer == NULL) + goto fail; -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; - } -} + ASSERT3P(MmGetMdlPfnArray(&Segment->Mdl)[0], ==, Segment->Pfn[0]); + // if only 1 Pfn is used, this triggers an array-out-of-bounds condition! + //ASSERT3P(MmGetMdlPfnArray(&Segment->Mdl)[1], ==, Segment->Pfn[1]); + + return TRUE; -static FORCEINLINE ULONG -__SectorsPerPage( - __in ULONG SectorSize - ) -{ - ASSERT3U(SectorSize, !=, 0); - return PAGE_SIZE / SectorSize; +fail: + return FALSE; } -static FORCEINLINE VOID -__Operation( - __in UCHAR CdbOp, - __out PUCHAR RingOp, - __out PBOOLEAN ReadOnly +static BOOLEAN +TargetPrepareRW( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt, + IN UCHAR Operation ) { - 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); - } -} + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + ULONG64 SectorStart = Cdb_LogicalBlock(Srb); + ULONG SectorsLeft = Cdb_TransferBlock(Srb); + LIST_ENTRY List; + XENVBD_SG_LIST SGList; + KIRQL Irql; + const ULONG SectorSize = Target->SectorSize; + const ULONG SectorMask = SectorSize - 1; + const ULONG SectorsPerPage = PAGE_SIZE / SectorSize; -static FORCEINLINE ULONG -__Offset( - __in STOR_PHYSICAL_ADDRESS PhysAddr - ) -{ - return (ULONG)(PhysAddr.QuadPart & (PAGE_SIZE - 1)); -} + InitializeListHead(&List); + SGListInit(&SGList, TargetGetAdapter(Target), Srb); -static FORCEINLINE PFN_NUMBER -__Phys2Pfn( - __in STOR_PHYSICAL_ADDRESS PhysAddr - ) -{ - return (PFN_NUMBER)(PhysAddr.QuadPart >> PAGE_SHIFT); -} + // validate SectorStart, SectorsLeft fits in this target (prevent read/write beyond extents) -static FORCEINLINE PFN_NUMBER -__Virt2Pfn( - __in PVOID VirtAddr - ) -{ - return (PFN_NUMBER)(MmGetPhysicalAddress(VirtAddr).QuadPart >> PAGE_SHIFT); -} + while (SectorsLeft > 0) { + PXENVBD_REQUEST Request; + ULONG Index; + ULONG MaxSegments; -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; + MaxSegments = Target->FeatureIndirect; + MaxSegments = min(MaxSegments, XENVBD_MAX_SEGMENTS_PER_INDIRECT); // limit to sensible value + MaxSegments = max(MaxSegments, BLKIF_MAX_SEGMENTS_PER_REQUEST); // ensure at least 11 + ASSERT3U(MaxSegments, >=, BLKIF_MAX_SEGMENTS_PER_REQUEST); + ASSERT3U(MaxSegments, <=, XENVBD_MAX_SEGMENTS_PER_INDIRECT); - return HighPagePriority; -} - -static FORCEINLINE VOID -SGListGet( - IN OUT PXENVBD_SG_LIST SGList - ) -{ - PSTOR_SCATTER_GATHER_ELEMENT SGElement; - - ASSERT3U(SGList->Index, <, SGList->SGList->NumberOfElements); + Request = TargetGetRequest(Target); + if (Request == NULL) + goto fail1; + InsertTailList(&List, &Request->ListEntry); + InterlockedIncrement(&SrbExt->RequestCount); + + Request->SrbExt = SrbExt; + Request->Operation = Operation; + Request->FirstSector = SectorStart; + + // build segments + for (Index = 0; Index < MaxSegments; ++Index) { + PXENVBD_SEGMENT Segment; + ULONG SectorsNow; + PFN_NUMBER Pfn; + NTSTATUS status; + + if (SectorsLeft == 0) + break; + + Segment = TargetGetSegment(Target); + if (Segment == NULL) + goto fail2; + InsertTailList(&Request->Segments, &Segment->ListEntry); + ++Request->NrSegments; + + if (SGListNext(&SGList, SectorMask)) { + ASSERT((SGListOffset(&SGList) & SectorMask) == 0); + + Segment->FirstSector = (UCHAR)(SGListOffset(&SGList) / SectorSize); + SectorsNow = min(SectorsLeft, SectorsPerPage - Segment->FirstSector); + Segment->LastSector = (UCHAR)(Segment->FirstSector + SectorsNow - 1); + + Pfn = SGListPfn(&SGList); + } else { + ASSERT((SGListOffset(&SGList) & SectorMask) != 0); + + Segment->FirstSector = (UCHAR)0; + SectorsNow = min(SectorsLeft, SectorsPerPage); + Segment->LastSector = (UCHAR)(SectorsNow - 1); + + if (!BufferMap(Segment, &SGList, SectorsNow * SectorSize)) + goto fail3; + + if (!BufferGet(Segment, &Segment->BufferId, &Pfn)) + goto fail4; + + if (Operation == BLKIF_OP_WRITE) { + BufferCopyIn(Segment->BufferId, + Segment->Buffer, + Segment->Length); + } + } + + status = GranterGet(Target->Granter, + Pfn, + Operation == BLKIF_OP_WRITE, + &Segment->Grant); + if (!NT_SUCCESS(status)) + goto fail5; + + SectorStart += SectorsNow; + SectorsLeft -= SectorsNow; + } - SGElement = &SGList->SGList->List[SGList->Index]; + // build indirects + if (MaxSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { + // round up + ULONG NumInd = (Request->NrSegments + XENVBD_MAX_SEGMENTS_PER_PAGE - 1) / + XENVBD_MAX_SEGMENTS_PER_PAGE; - SGList->PhysAddr.QuadPart = SGElement->PhysicalAddress.QuadPart + SGList->Offset; - SGList->PhysLen = __min(PAGE_SIZE - __Offset(SGList->PhysAddr) - SGList->Length, SGElement->Length - SGList->Offset); + ASSERT(NumInd <= BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST); + while (NumInd--) { + PXENVBD_INDIRECT Indirect; - ASSERT3U(SGList->PhysLen, <=, PAGE_SIZE); - ASSERT3U(SGList->Offset, <, SGElement->Length); + Indirect = TargetGetIndirect(Target); + if (Indirect == NULL) + goto fail6; - 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; + InsertTailList(&Request->Indirects, &Indirect->ListEntry); + } + } } -} - -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; + Srb->SrbStatus = SRB_STATUS_PENDING; - // 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) + KeAcquireSpinLock(&Target->QueueLock, &Irql); + for (;;) { + PLIST_ENTRY ListEntry; + PXENVBD_REQUEST Request; - 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; + ListEntry = RemoveHeadList(&List); + if (ListEntry == &List) + break; + Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); + InsertTailList(&Target->Prepared, &Request->ListEntry); } + KeReleaseSpinLock(&Target->QueueLock, Irql); - ASSERT3P(MmGetMdlPfnArray(Mdl)[0], ==, Segment->Pfn[0]); - ASSERT3P(MmGetMdlPfnArray(Mdl)[1], ==, Segment->Pfn[1]); - return TRUE; -fail: +fail6: +fail5: +fail4: +fail3: +fail2: +fail1: + Srb->SrbStatus = SRB_STATUS_ERROR; + for (;;) { + PLIST_ENTRY ListEntry; + PXENVBD_REQUEST Request; + + ListEntry = RemoveHeadList(&List); + if (ListEntry == &List) + break; + Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); + TargetPutRequest(Target, Request); + } return FALSE; } -static FORCEINLINE VOID -RequestCopyOutput( - __in PXENVBD_REQUEST Request +static BOOLEAN +TargetPrepareUnmap( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt ) { - PLIST_ENTRY Entry; - - if (Request->Operation != BLKIF_OP_READ) - return; + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PUNMAP_LIST_HEADER Unmap = Srb->DataBuffer; + ULONG Count; + ULONG Index; + LIST_ENTRY List; + KIRQL Irql; - for (Entry = Request->Segments.Flink; - Entry != &Request->Segments; - Entry = Entry->Flink) { - PXENVBD_SEGMENT Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); + InitializeListHead(&List); + Count = _byteswap_ushort(*(PUSHORT)Unmap->BlockDescrDataLength) / + sizeof(UNMAP_BLOCK_DESCRIPTOR); - if (Segment->BufferId) - BufferCopyOut(Segment->BufferId, Segment->Buffer, Segment->Length); - } -} + for (Index = 0; Index < Count; ++Index) { + PUNMAP_BLOCK_DESCRIPTOR Descr = &Unmap->Descriptors[Index]; + PXENVBD_REQUEST Request; -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; + Request = TargetGetRequest(Target); + if (Request == NULL) goto fail1; - } - - // get a buffer - if (!BufferGet(Segment, &Segment->BufferId, &Pfn)) { - ++Target->FailedBounces; - goto fail2; - } + InsertTailList(&List, &Request->ListEntry); + InterlockedIncrement(&SrbExt->RequestCount); - // copy contents in - if (ReadOnly) { // Operation == BLKIF_OP_WRITE - BufferCopyIn(Segment->BufferId, Segment->Buffer, Segment->Length); - } + Request->SrbExt = SrbExt; + Request->Operation = BLKIF_OP_DISCARD; + Request->FirstSector = _byteswap_uint64(*(PULONG64)Descr->StartingLba); + Request->NrSectors = _byteswap_ulong(*(PULONG)Descr->LbaCount); + Request->Flags = 0; } - // Grant segment's page - Status = GranterGet(Granter, Pfn, ReadOnly, &Segment->Grant); - if (!NT_SUCCESS(Status)) { - ++Target->FailedGrants; - goto fail3; + Srb->SrbStatus = SRB_STATUS_PENDING; + + KeAcquireSpinLock(&Target->QueueLock, &Irql); + for (;;) { + PLIST_ENTRY ListEntry; + PXENVBD_REQUEST Request; + + ListEntry = RemoveHeadList(&List); + if (ListEntry == &List) + break; + Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); + InsertTailList(&Target->Prepared, &Request->ListEntry); } + KeReleaseSpinLock(&Target->QueueLock, Irql); return TRUE; -fail3: -fail2: -fail1: +fail1: + Srb->SrbStatus = SRB_STATUS_ERROR; + for (;;) { + PLIST_ENTRY ListEntry; + PXENVBD_REQUEST Request; + + ListEntry = RemoveHeadList(&List); + if (ListEntry == &List) + break; + Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); + TargetPutRequest(Target, Request); + } 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 +TargetPrepareSync( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt, + IN UCHAR Operation ) { - UCHAR Operation; - BOOLEAN ReadOnly; - ULONG Index; - __Operation(Cdb_OperationEx(Request->Srb), &Operation, &ReadOnly); + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PXENVBD_REQUEST Request; + KIRQL Irql; - 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; + Srb->SrbStatus = SRB_STATUS_ERROR; + Request = TargetGetRequest(Target); + if (Request == NULL) + return FALSE; + InterlockedIncrement(&SrbExt->RequestCount); - InsertTailList(&Request->Segments, &Segment->Entry); - ++Request->NrSegments; + Request->SrbExt = SrbExt; + Request->Operation = Operation; + Request->FirstSector = Cdb_LogicalBlock(Srb); - if (!PrepareSegment(Target, - Segment, - SGList, - ReadOnly, - SectorsLeft, - &SectorsNow)) - goto fail2; + Srb->SrbStatus = SRB_STATUS_PENDING; - *SectorsDone += SectorsNow; - SectorsLeft -= SectorsNow; - } - ASSERT3U(Request->NrSegments, >, 0); - ASSERT3U(Request->NrSegments, <=, MaxSegments); + KeAcquireSpinLock(&Target->QueueLock, &Irql); + InsertTailList(&Target->Prepared, &Request->ListEntry); + KeReleaseSpinLock(&Target->QueueLock, Irql); return TRUE; - -fail2: -fail1: - return FALSE; } static BOOLEAN -PrepareBlkifIndirect( - IN PXENVBD_TARGET Target, - IN PXENVBD_REQUEST Request +TargetPrepareRequest( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt ) { - ULONG Index; - ULONG NrSegments = 0; + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + UCHAR Operation; - for (Index = 0; - Index < BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST && - NrSegments < Request->NrSegments; - ++Index) { - PXENVBD_INDIRECT Indirect; + Operation = Cdb_OperationEx(SrbExt->Srb); + switch (Operation) { + case SCSIOP_READ: + return TargetPrepareRW(Target, SrbExt, BLKIF_OP_READ); - Indirect = TargetGetIndirect(Target); - if (Indirect == NULL) - goto fail1; - InsertTailList(&Request->Indirects, &Indirect->Entry); + case SCSIOP_WRITE: + return TargetPrepareRW(Target, SrbExt, BLKIF_OP_WRITE); - NrSegments += XENVBD_MAX_SEGMENTS_PER_PAGE; - } + case SCSIOP_UNMAP: + return TargetPrepareUnmap(Target, SrbExt); - return TRUE; + case SCSIOP_SYNCHRONIZE_CACHE: + if (Target->FeatureFlush) + return TargetPrepareSync(Target, SrbExt, BLKIF_OP_FLUSH_DISKCACHE); + if (Target->FeatureBarrier) + return TargetPrepareSync(Target, SrbExt, BLKIF_OP_WRITE_BARRIER); + + // nothing supported - shouldnt really get here, but just complete if it did + Warning("[%u] FLUSH & BARRIER not supported, SCSIOP_SYNCHRONIZE_CACHE got to Prepare\n", + Target->TargetId); + Srb->SrbStatus = SRB_STATUS_SUCCESS; + AdapterCompleteSrb(Target->Adapter, SrbExt); + return TRUE; -fail1: + default: + ASSERT(FALSE); + break; + } return FALSE; } -static FORCEINLINE ULONG -UseIndirect( - IN PXENVBD_TARGET Target, - IN ULONG SectorsLeft - ) +static FORCEINLINE BOOLEAN +TargetPrepareFresh( + IN PXENVBD_TARGET Target + ) { - const ULONG SectorsPerPage = __SectorsPerPage(TargetSectorSize(Target)); - const ULONG MaxIndirectSegs = FrontendGetFeatures(Target->Frontend)->Indirect; + PXENVBD_SRBEXT SrbExt; + PLIST_ENTRY ListEntry; + KIRQL Irql; + + KeAcquireSpinLock(&Target->QueueLock, &Irql); + ListEntry = RemoveHeadList(&Target->Fresh); + if (ListEntry == &Target->Fresh) { + KeReleaseSpinLock(&Target->QueueLock, Irql); + return FALSE; + } + KeReleaseSpinLock(&Target->QueueLock, Irql); + + SrbExt = CONTAINING_RECORD(ListEntry, XENVBD_SRBEXT, ListEntry); - if (MaxIndirectSegs <= BLKIF_MAX_SEGMENTS_PER_REQUEST) - return BLKIF_MAX_SEGMENTS_PER_REQUEST; // not supported + if (TargetPrepareRequest(Target, SrbExt)) + return TRUE; - if (SectorsLeft < BLKIF_MAX_SEGMENTS_PER_REQUEST * SectorsPerPage) - return BLKIF_MAX_SEGMENTS_PER_REQUEST; // first into a single BLKIF_OP_{READ/WRITE} + KeAcquireSpinLock(&Target->QueueLock, &Irql); + InsertHeadList(&Target->Fresh, ListEntry); + KeReleaseSpinLock(&Target->QueueLock, Irql); - return MaxIndirectSegs; + return FALSE; } -static FORCEINLINE ULONG -TargetQueueRequestList( - IN PXENVBD_TARGET Target, - IN PLIST_ENTRY List +static FORCEINLINE BOOLEAN +TargetSubmitPrepared( + IN PXENVBD_TARGET Target ) { - ULONG Count = 0; for (;;) { + PLIST_ENTRY ListEntry; PXENVBD_REQUEST Request; - PLIST_ENTRY Entry; + KIRQL Irql; - Entry = RemoveHeadList(List); - if (Entry == List) + KeAcquireSpinLock(&Target->QueueLock, &Irql); + ListEntry = RemoveHeadList(&Target->Prepared); + if (ListEntry == &Target->Prepared) { + KeReleaseSpinLock(&Target->QueueLock, Irql); break; + } + Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); + + InsertTailList(&Target->Submitted, ListEntry); + KeReleaseSpinLock(&Target->QueueLock, Irql); - ++Count; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - __TargetIncBlkifOpCount(Target, Request); - QueueAppend(&Target->PreparedReqs, &Request->Entry); + if (BlockRingSubmit(Target->BlockRing, Request)) + continue; + + KeAcquireSpinLock(&Target->QueueLock, &Irql); + RemoveEntryList(&Request->ListEntry); + InsertHeadList(&Target->Prepared, &Request->ListEntry); + KeReleaseSpinLock(&Target->QueueLock, Irql); + + return FALSE; } - return Count; + + return TRUE; } static FORCEINLINE VOID -TargetCancelRequestList( - IN PXENVBD_TARGET Target, - IN PLIST_ENTRY List +TargetCompleteShutdown( + IN PXENVBD_TARGET Target ) { + if (IsListEmpty(&Target->Shutdown)) + return; + if (!IsListEmpty(&Target->Fresh)) + return; + if (!IsListEmpty(&Target->Prepared)) + return; + if (!IsListEmpty(&Target->Shutdown)) + return; + for (;;) { - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry; + PLIST_ENTRY ListEntry; + PXENVBD_SRBEXT SrbExt; + KIRQL Irql; - Entry = RemoveHeadList(List); - if (Entry == List) + KeAcquireSpinLock(&Target->QueueLock, &Irql); + ListEntry = RemoveHeadList(&Target->Shutdown); + if (ListEntry == &Target->Shutdown) { + KeReleaseSpinLock(&Target->QueueLock, Irql); break; + } + KeReleaseSpinLock(&Target->QueueLock, Irql); - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - TargetPutRequest(Target, Request); + SrbExt = CONTAINING_RECORD(ListEntry, XENVBD_SRBEXT, ListEntry); + SrbExt->Srb->SrbStatus = SRB_STATUS_SUCCESS; + AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt); } } -__checkReturn -static BOOLEAN -PrepareReadWrite( - __in PXENVBD_TARGET Target, - __in PSCSI_REQUEST_BLOCK Srb +VOID +TargetSubmitRequests( + IN PXENVBD_TARGET Target ) { - PXENVBD_SRBEXT SrbExt = Srb->SrbExtension; - ULONG64 SectorStart = Cdb_LogicalBlock(Srb); - ULONG SectorsLeft = Cdb_TransferBlock(Srb); - LIST_ENTRY List; - XENVBD_SG_LIST SGList; - ULONG DebugCount; + 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; - Srb->SrbStatus = SRB_STATUS_PENDING; + // 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; + } - InitializeListHead(&List); - SrbExt->RequestCount = 0; + // if no requests/SRBs outstanding, complete any shutdown SRBs + TargetCompleteShutdown(Target); +} + +static FORCEINLINE VOID +TargetDisableFeature( + IN PXENVBD_TARGET Target, + IN UCHAR Operation + ) +{ + switch (Operation) { + case BLKIF_OP_WRITE_BARRIER: + Target->FeatureBarrier = FALSE; + break; + case BLKIF_OP_FLUSH_DISKCACHE: + Target->FeatureFlush = FALSE; + break; + case BLKIF_OP_DISCARD: + Target->FeatureDiscard = FALSE; + break; + default: + break; + } +} - RtlZeroMemory(&SGList, sizeof(SGList)); - SGList.SGList = StorPortGetScatterGatherList(TargetGetAdapter(Target), Srb); +VOID +TargetCompleteResponse( + IN PXENVBD_TARGET Target, + IN ULONG64 Id, + IN SHORT Status + ) +{ + PLIST_ENTRY ListEntry; + PXENVBD_REQUEST Request; + PXENVBD_SRBEXT SrbExt; + PSCSI_REQUEST_BLOCK Srb; + KIRQL Irql; - while (SectorsLeft > 0) { - ULONG MaxSegments; - ULONG SectorsDone = 0; - PXENVBD_REQUEST Request; + KeAcquireSpinLock(&Target->QueueLock, &Irql); + Request = NULL; + for (ListEntry = Target->Submitted.Flink; + ListEntry != &Target->Submitted; + ListEntry = ListEntry->Flink) { + Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); - Request = TargetGetRequest(Target); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->Entry); - InterlockedIncrement(&SrbExt->RequestCount); - - Request->Srb = Srb; - MaxSegments = UseIndirect(Target, SectorsLeft); - - if (!PrepareBlkifReadWrite(Target, - Request, - &SGList, - MaxSegments, - SectorStart, - SectorsLeft, - &SectorsDone)) - goto fail2; + if (Request->Id == Id) { + RemoveEntryList(&Request->ListEntry); - if (MaxSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { - if (!PrepareBlkifIndirect(Target, Request)) - goto fail3; + ASSERT3P(Request, ==, (PVOID)(ULONG_PTR)Id); + break; } - SectorsLeft -= SectorsDone; - SectorStart += SectorsDone; + Request = NULL; } + KeReleaseSpinLock(&Target->QueueLock, Irql); - DebugCount = TargetQueueRequestList(Target, &List); - if (DebugCount != (ULONG)SrbExt->RequestCount) { - Trace("[%u] %d != %u\n", TargetGetTargetId(Target), SrbExt->RequestCount, DebugCount); - } - return TRUE; + ASSERT3P(Request, !=, NULL); + SrbExt = Request->SrbExt; + ASSERT3P(SrbExt, !=, NULL); + Srb = SrbExt->Srb; + ASSERT3P(Srb, !=, NULL); -fail3: -fail2: -fail1: - TargetCancelRequestList(Target, &List); - SrbExt->RequestCount = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; + switch (Status) { + case BLKIF_RSP_OKAY: + if (Request->Operation == BLKIF_OP_READ) { + for (ListEntry = Request->Segments.Flink; + ListEntry != &Request->Segments; + ListEntry = ListEntry->Flink) { + PXENVBD_SEGMENT Segment = CONTAINING_RECORD(ListEntry, XENVBD_SEGMENT, ListEntry); + + if (Segment->BufferId) { + ASSERT(Segment->Buffer); + ASSERT(Segment->Length); + BufferCopyOut(Segment->BufferId, + Segment->Buffer, + Segment->Length); + } + } + } + break; + case BLKIF_RSP_EOPNOTSUPP: + TargetDisableFeature(Target, Request->Operation); + break; + case BLKIF_RSP_ERROR: + default: + Srb->SrbStatus = SRB_STATUS_ERROR; + break; + } + + TargetPutRequest(Target, Request); + + if (InterlockedDecrement(&SrbExt->RequestCount) != 0) + return; + + if (Srb->SrbStatus == SRB_STATUS_PENDING) + Srb->SrbStatus = SRB_STATUS_SUCCESS; + + AdapterCompleteSrb(Target->Adapter, SrbExt); } -__checkReturn -static BOOLEAN -PrepareSyncCache( - __in PXENVBD_TARGET Target, - __in PSCSI_REQUEST_BLOCK Srb +VOID +TargetReset( + IN PXENVBD_TARGET Target ) { - PXENVBD_SRBEXT SrbExt = Srb->SrbExtension; - PXENVBD_REQUEST Request; - LIST_ENTRY List; - UCHAR Operation; - ULONG DebugCount; + ULONG Outstanding; - Srb->SrbStatus = SRB_STATUS_PENDING; - - if (FrontendGetDiskInfo(Target->Frontend)->FlushCache) - Operation = BLKIF_OP_FLUSH_DISKCACHE; - else - Operation = BLKIF_OP_WRITE_BARRIER; + Verbose("[%u] =====>\n", Target->TargetId); - InitializeListHead(&List); - SrbExt->RequestCount = 0; + ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL); - Request = TargetGetRequest(Target); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->Entry); - InterlockedIncrement(&SrbExt->RequestCount); + Trace("polling...\n"); + Outstanding = BlockRingPoll(Target->BlockRing); + Trace("%u requests outstanding\n", Outstanding); - Request->Srb = Srb; - Request->Operation = Operation; - Request->FirstSector = Cdb_LogicalBlock(Srb); + Verbose("[%u] <=====\n", Target->TargetId); +} - DebugCount = TargetQueueRequestList(Target, &List); - if (DebugCount != (ULONG)SrbExt->RequestCount) { - Trace("[%u] %d != %u\n", TargetGetTargetId(Target), SrbExt->RequestCount, DebugCount); - } - return TRUE; +VOID +TargetFlush( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + KIRQL Irql; -fail1: - TargetCancelRequestList(Target, &List); - SrbExt->RequestCount = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; + SrbExt->Srb->SrbStatus = SRB_STATUS_PENDING; + + KeAcquireSpinLock(&Target->QueueLock, &Irql); + InsertTailList(&Target->Shutdown, &SrbExt->ListEntry); + KeReleaseSpinLock(&Target->QueueLock, Irql); + + BlockRingKick(Target->BlockRing); } -__checkReturn -static BOOLEAN -PrepareUnmap( - __in PXENVBD_TARGET Target, - __in PSCSI_REQUEST_BLOCK Srb +VOID +TargetShutdown( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt ) { - PXENVBD_SRBEXT SrbExt = Srb->SrbExtension; - PUNMAP_LIST_HEADER Unmap = Srb->DataBuffer; - ULONG Count = _byteswap_ushort(*(PUSHORT)Unmap->BlockDescrDataLength) / sizeof(UNMAP_BLOCK_DESCRIPTOR); - ULONG Index; - LIST_ENTRY List; - ULONG DebugCount; + KIRQL Irql; + + SrbExt->Srb->SrbStatus = SRB_STATUS_PENDING; + + KeAcquireSpinLock(&Target->QueueLock, &Irql); + InsertTailList(&Target->Shutdown, &SrbExt->ListEntry); + KeReleaseSpinLock(&Target->QueueLock, Irql); + + BlockRingKick(Target->BlockRing); +} + +VOID +TargetPrepareSrb( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + + UNREFERENCED_PARAMETER(Target); Srb->SrbStatus = SRB_STATUS_PENDING; +} - InitializeListHead(&List); - SrbExt->RequestCount = 0; +static FORCEINLINE VOID +TargetQueueSrb( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + KIRQL Irql; - for (Index = 0; Index < Count; ++Index) { - PUNMAP_BLOCK_DESCRIPTOR Descr = &Unmap->Descriptors[Index]; - PXENVBD_REQUEST Request; + SrbExt->Srb->SrbStatus = SRB_STATUS_PENDING; - Request = TargetGetRequest(Target); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->Entry); - InterlockedIncrement(&SrbExt->RequestCount); + KeAcquireSpinLock(&Target->QueueLock, &Irql); + InsertTailList(&Target->Fresh, &SrbExt->ListEntry); + KeReleaseSpinLock(&Target->QueueLock, Irql); - 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; - } + BlockRingKick(Target->BlockRing); +} - DebugCount = TargetQueueRequestList(Target, &List); - if (DebugCount != (ULONG)SrbExt->RequestCount) { - Trace("[%u] %d != %u\n", TargetGetTargetId(Target), SrbExt->RequestCount, DebugCount); - } - return TRUE; +static FORCEINLINE VOID +TargetInquiryStd( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PINQUIRYDATA Data = Srb->DataBuffer; + + UNREFERENCED_PARAMETER(Target); -fail1: - TargetCancelRequestList(Target, &List); - SrbExt->RequestCount = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + if (Srb->DataTransferLength < sizeof(INQUIRYDATA)) + return; + + RtlZeroMemory(Data, Srb->DataTransferLength); + Data->DeviceType = DIRECT_ACCESS_DEVICE; + Data->DeviceTypeQualifier = DEVICE_CONNECTED; + Data->Versions = 4; + Data->ResponseDataFormat = 2; + Data->AdditionalLength = INQUIRYDATABUFFERSIZE - 4; + Data->CommandQueue = 1; + RtlCopyMemory(Data->VendorId, "XENSRC ", 8); + RtlCopyMemory(Data->ProductId, "PVDISK ", 16); + RtlCopyMemory(Data->ProductRevisionLevel, "3.0 ", 4); + + Srb->DataTransferLength = sizeof(INQUIRYDATA); + Srb->SrbStatus = SRB_STATUS_SUCCESS; +} + +static FORCEINLINE VOID +TargetInquiry00( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PUCHAR Data = Srb->DataBuffer; + + UNREFERENCED_PARAMETER(Target); + + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + if (Srb->DataTransferLength < 7) + return; + + RtlZeroMemory(Data, Srb->DataTransferLength); + Data[3] = 3; + Data[5] = 0x80; + Data[6] = 0x83; + + Srb->DataTransferLength = 7; + Srb->SrbStatus = SRB_STATUS_SUCCESS; } -//============================================================================= -// Queue-Related static FORCEINLINE VOID -__TargetPauseDataPath( - __in PXENVBD_TARGET Target, - __in BOOLEAN Timeout +TargetInquiry80( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt ) { - KIRQL Irql; - ULONG Requests; - ULONG Count = 0; - PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend); - PXENVBD_BLOCKRING BlockRing = FrontendGetBlockRing(Target->Frontend); + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PVPD_SERIAL_NUMBER_PAGE Data = Srb->DataBuffer; + + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + if (Srb->DataTransferLength < sizeof(VPD_SERIAL_NUMBER_PAGE) + 4) + return; - KeAcquireSpinLock(&Target->Lock, &Irql); - ++Target->Paused; - KeReleaseSpinLock(&Target->Lock, Irql); + RtlZeroMemory(Data, Srb->DataTransferLength); + Data->PageCode = 0x80; + Data->PageLength = 4; + RtlStringCchPrintfA((PCHAR)Data->SerialNumber, 4, "%04u", Target->TargetId); - Requests = QueueCount(&Target->SubmittedReqs); - KeMemoryBarrier(); + Srb->DataTransferLength = sizeof(VPD_SERIAL_NUMBER_PAGE) + 4; + Srb->SrbStatus = SRB_STATUS_SUCCESS; +} - Verbose("Target[%d] : Waiting for %d Submitted requests\n", TargetGetTargetId(Target), Requests); +static FORCEINLINE VOID +TargetInquiry83( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PVPD_IDENTIFICATION_PAGE Data = Srb->DataBuffer; + PVPD_IDENTIFICATION_DESCRIPTOR Descr; - // 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; + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + if (Srb->DataTransferLength < sizeof(VPD_IDENTIFICATION_PAGE) - 1 + + sizeof(VPD_IDENTIFICATION_DESCRIPTOR) + 16) + return; + + RtlZeroMemory(Data, Srb->DataTransferLength); + Data->PageCode = 0x83; + Data->PageLength = sizeof(VPD_IDENTIFICATION_DESCRIPTOR) + 16; + + Descr = (PVPD_IDENTIFICATION_DESCRIPTOR)Data->Descriptors; + Descr->CodeSet = VpdCodeSetAscii; + Descr->IdentifierType = VpdIdentifierTypeVendorId; + Descr->IdentifierLength = 16; + RtlStringCbPrintfA((PCHAR)Descr->Identifier, + 16, + "XEN:%u:%u", + Target->DeviceId, + Target->TargetId); + + Srb->DataTransferLength = sizeof(VPD_IDENTIFICATION_PAGE) - 1 + + sizeof(VPD_IDENTIFICATION_DESCRIPTOR) + 16; + Srb->SrbStatus = SRB_STATUS_SUCCESS; +} + +static FORCEINLINE VOID +TargetInquiry( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + if (Cdb_EVPD(SrbExt->Srb)) { + switch (Cdb_PageCode(SrbExt->Srb)) { + case 0x00: TargetInquiry00(Target, SrbExt); break; + case 0x80: TargetInquiry80(Target, SrbExt); break; + case 0x83: TargetInquiry83(Target, SrbExt); break; + default: SrbExt->Srb->SrbStatus = SRB_STATUS_ERROR; break; + } + } else { + switch (Cdb_PageCode(SrbExt->Srb)) { + case 0x00: TargetInquiryStd(Target, SrbExt); break; + default: SrbExt->Srb->SrbStatus = SRB_STATUS_ERROR; break; + } } +} + +static FORCEINLINE VOID +TargetModeSense( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PMODE_PARAMETER_HEADER Header; + ULONG Offset; + UCHAR PageCode; - Verbose("Target[%d] : %u/%u Submitted requests left (%u iterrations)\n", - TargetGetTargetId(Target), QueueCount(&Target->SubmittedReqs), Requests, Count); + UNREFERENCED_PARAMETER(Target); - // Abort Fresh SRBs - for (;;) { - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY ListEntry = QueuePop(&Target->FreshSrbs); - if (ListEntry == NULL) - break; - SrbExt = CONTAINING_RECORD(ListEntry, XENVBD_SRBEXT, ListEntry); + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + if (Srb->DataTransferLength < sizeof(MODE_PARAMETER_HEADER)) + return; + RtlZeroMemory(Srb->DataBuffer, Srb->DataTransferLength); - 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); + Header = Srb->DataBuffer; + Header->ModeDataLength = sizeof(MODE_PARAMETER_HEADER) - 1; + + Offset = sizeof(MODE_PARAMETER_HEADER); + PageCode = Cdb_PageCode(Srb); + if (Cdb_Dbd(Srb) == 0 && + Srb->DataTransferLength >= Offset + sizeof(MODE_PARAMETER_BLOCK)) { + PMODE_PARAMETER_BLOCK Block = (PMODE_PARAMETER_BLOCK)((PUCHAR)Header + Offset); + + // Block is ZEROed + UNREFERENCED_PARAMETER(Block); + + Header->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); + Header->ModeDataLength += sizeof(MODE_PARAMETER_BLOCK); + Offset += sizeof(MODE_PARAMETER_BLOCK); } - // 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 = Request->Srb->SrbExtension; + if ((PageCode == MODE_PAGE_CACHING || PageCode == MODE_SENSE_RETURN_ALL) && + Srb->DataTransferLength >= Offset + sizeof(MODE_CACHING_PAGE)) { + PMODE_CACHING_PAGE Caching = (PMODE_CACHING_PAGE)((PUCHAR)Header + Offset); - Verbose("Target[%d] : PreparedReq 0x%p -> FAILED\n", TargetGetTargetId(Target), Request); + Caching->PageCode = MODE_PAGE_CACHING; + Caching->PageLength = sizeof(MODE_CACHING_PAGE); + // Caching is ZEROed - SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; - TargetPutRequest(Target, Request); + Header->ModeDataLength += sizeof(MODE_CACHING_PAGE); + Offset += sizeof(MODE_CACHING_PAGE); + } - if (InterlockedDecrement(&SrbExt->RequestCount) == 0) { - SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED - AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt); - } + if ((PageCode == MODE_PAGE_FAULT_REPORTING || PageCode == MODE_SENSE_RETURN_ALL) && + Srb->DataTransferLength >= Offset + sizeof(MODE_CACHING_PAGE)) { + PMODE_INFO_EXCEPTIONS Info = (PMODE_INFO_EXCEPTIONS)((PUCHAR)Header + Offset); + + Info->PageCode = MODE_PAGE_FAULT_REPORTING; + Info->PageLength = sizeof(MODE_INFO_EXCEPTIONS); + Info->Dexcpt = 1; + // Info is ZEROed + + Header->ModeDataLength += sizeof(MODE_CACHING_PAGE); + Offset += sizeof(MODE_CACHING_PAGE); } + + Srb->DataTransferLength = Offset; + Srb->SrbStatus = SRB_STATUS_SUCCESS; } static FORCEINLINE VOID -__TargetUnpauseDataPath( - __in PXENVBD_TARGET Target +TargetRequestSense( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt ) { - KIRQL Irql; + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PSENSE_DATA Sense = Srb->DataBuffer; - KeAcquireSpinLock(&Target->Lock, &Irql); - --Target->Paused; - KeReleaseSpinLock(&Target->Lock, Irql); + UNREFERENCED_PARAMETER(Target); + + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + if (Srb->DataTransferLength < sizeof(SENSE_DATA)) + return; + RtlZeroMemory(Srb->DataBuffer, Srb->DataTransferLength); + + Sense->ErrorCode = 0x70; + Sense->Valid = 1; + Sense->SenseKey = SCSI_SENSE_NO_SENSE; + Sense->AdditionalSenseCode = SCSI_ADSENSE_NO_SENSE; + + Srb->DataTransferLength = sizeof(SENSE_DATA); + Srb->SrbStatus = SRB_STATUS_SUCCESS; +} + +static FORCEINLINE VOID +TargetReportLuns( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + ULONG Length; + ULONG Offset; + ULONG AllocLength = Cdb_AllocationLength(Srb); + PUCHAR Buffer = Srb->DataBuffer; + + UNREFERENCED_PARAMETER(Target); + + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + if (Srb->DataTransferLength < 8) + return; + RtlZeroMemory(Srb->DataBuffer, Srb->DataTransferLength); + + 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 FORCEINLINE VOID +TargetReadCapacity( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PREAD_CAPACITY_DATA Capacity = Srb->DataBuffer; + ULONG64 SectorCount = Target->SectorCount; + ULONG SectorSize = Target->SectorSize; + ULONG LastBlock; + + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + if (Srb->DataTransferLength < sizeof(READ_CAPACITY_DATA)) + return; + RtlZeroMemory(Srb->DataBuffer, Srb->DataTransferLength); + + Srb->SrbStatus = SRB_STATUS_ERROR; + if (Cdb_PMI(Srb) == 0 && Cdb_LogicalBlock(Srb) != 0) + return; + + if (SectorCount == (ULONG)SectorCount) + LastBlock = (ULONG)SectorCount - 1; + else + LastBlock = ~0ul; + + Capacity->LogicalBlockAddress = _byteswap_ulong(LastBlock); + Capacity->BytesPerBlock = _byteswap_ulong(SectorSize); + + Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA); + Srb->SrbStatus = SRB_STATUS_SUCCESS; +} + +static FORCEINLINE VOID +TargetReadCapacity16( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PREAD_CAPACITY16_DATA Capacity = Srb->DataBuffer; + ULONG64 SectorCount = Target->SectorCount; + ULONG SectorSize = Target->SectorSize; + ULONG LogPerPhysExp; + + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + if (Srb->DataTransferLength < sizeof(READ_CAPACITY16_DATA)) + return; + RtlZeroMemory(Srb->DataBuffer, Srb->DataTransferLength); + + Srb->SrbStatus = SRB_STATUS_ERROR; + if (Cdb_PMI(Srb) == 0 && Cdb_LogicalBlock(Srb) != 0) + return; + + if (Target->PhysicalSectorSize == 0) + LogPerPhysExp = 0; + else if (!_BitScanReverse(&LogPerPhysExp, Target->PhysicalSectorSize / SectorSize)) + LogPerPhysExp = 0; + + Capacity->LogicalBlockAddress.QuadPart = _byteswap_uint64(SectorCount - 1); + Capacity->BytesPerBlock = _byteswap_ulong(SectorSize); + Capacity->LogicalPerPhysicalExponent = (UCHAR)LogPerPhysExp; + + Srb->DataTransferLength = sizeof(READ_CAPACITY16_DATA); + Srb->SrbStatus = SRB_STATUS_SUCCESS; } static FORCEINLINE BOOLEAN -TargetPrepareFresh( - IN PXENVBD_TARGET Target +TargetCheckSectors( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt ) { - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY ListEntry; + ULONG64 StartSector = Cdb_LogicalBlock(SrbExt->Srb); + ULONG SectorCount = Cdb_TransferBlock(SrbExt->Srb); - ListEntry = QueuePop(&Target->FreshSrbs); - if (ListEntry == NULL) - return FALSE; // fresh queue is empty + // prevent read/write beyond the end of the disk + if (StartSector >= Target->SectorCount) + return FALSE; + if (StartSector + SectorCount >= Target->SectorCount) + return FALSE; + return TRUE; +} - SrbExt = CONTAINING_RECORD(ListEntry, XENVBD_SRBEXT, ListEntry); +VOID +TargetStartSrb( + IN PXENVBD_TARGET Target, + IN PXENVBD_SRBEXT SrbExt + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + UCHAR Operation; - switch (Cdb_OperationEx(SrbExt->Srb)) { + Operation = Cdb_OperationEx(Srb); + switch (Operation) { case SCSIOP_READ: case SCSIOP_WRITE: - if (PrepareReadWrite(Target, SrbExt->Srb)) - return TRUE; // prepared this SRB + if (!TargetCheckSectors(Target, SrbExt)) + Srb->SrbStatus = SRB_STATUS_ERROR; + else + TargetQueueSrb(Target, SrbExt); break; + + case SCSIOP_UNMAP: + if (Target->FeatureDiscard) + TargetQueueSrb(Target, SrbExt); + else + Srb->SrbStatus = SRB_STATUS_SUCCESS; + break; + case SCSIOP_SYNCHRONIZE_CACHE: - if (PrepareSyncCache(Target, SrbExt->Srb)) - return TRUE; // prepared this SRB + if (Target->FeatureBarrier || Target->FeatureFlush) + TargetQueueSrb(Target, SrbExt); + else + Srb->SrbStatus = SRB_STATUS_SUCCESS; break; - case SCSIOP_UNMAP: - if (PrepareUnmap(Target, SrbExt->Srb)) - return TRUE; // prepared this SRB + + case SCSIOP_INQUIRY: + TargetInquiry(Target, SrbExt); + break; + case SCSIOP_MODE_SENSE: + TargetModeSense(Target, SrbExt); + break; + case SCSIOP_REQUEST_SENSE: + TargetRequestSense(Target, SrbExt); + break; + case SCSIOP_REPORT_LUNS: + TargetReportLuns(Target, SrbExt); + break; + case SCSIOP_READ_CAPACITY: + TargetReadCapacity(Target, SrbExt); break; + case SCSIOP_READ_CAPACITY16: + TargetReadCapacity16(Target, SrbExt); + 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: + case SCSIOP_START_STOP_UNIT: + Srb->SrbStatus = SRB_STATUS_SUCCESS; + break; + default: - ASSERT(FALSE); + Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; break; } - QueueUnPop(&Target->FreshSrbs, &SrbExt->ListEntry); - - return FALSE; // prepare failed } -static FORCEINLINE BOOLEAN -TargetSubmitPrepared( - __in PXENVBD_TARGET Target +static VOID +TargetStoreReadDiskInfo( + 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; + PCHAR Buffer; + NTSTATUS status; + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "info", + &Buffer); + if (NT_SUCCESS(status)) { + Target->DiskInfo = strtoul(Buffer, NULL, 10); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "sectors", + &Buffer); + if (NT_SUCCESS(status)) { + Target->SectorCount = _strtoui64(Buffer, NULL, 10); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "sector-size", + &Buffer); + if (NT_SUCCESS(status)) { + Target->SectorSize = strtoul(Buffer, NULL, 10); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "physical-sector-size", + &Buffer); + if (NT_SUCCESS(status)) { + Target->PhysicalSectorSize = strtoul(Buffer, NULL, 10); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } else { + Target->PhysicalSectorSize = Target->SectorSize; } +} - for (;;) { - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry; +static VOID +TargetStoreReadFeatures( + IN PXENVBD_TARGET Target + ) +{ + PCHAR Buffer; + NTSTATUS status; - Entry = QueuePop(&Target->PreparedReqs); - if (Entry == NULL) - break; + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "removable", + &Buffer); + if (NT_SUCCESS(status)) { + Target->Removable = (BOOLEAN)strtoul(Buffer, NULL, 2); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "feature-barrier", + &Buffer); + if (NT_SUCCESS(status)) { + Target->FeatureBarrier = (BOOLEAN)strtoul(Buffer, NULL, 2); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "feature-flush-cache", + &Buffer); + if (NT_SUCCESS(status)) { + Target->FeatureFlush = (BOOLEAN)strtoul(Buffer, NULL, 2); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "feature-discard", + &Buffer); + if (NT_SUCCESS(status)) { + Target->FeatureDiscard = (BOOLEAN)strtoul(Buffer, NULL, 2); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "discard-enable", + &Buffer); + if (NT_SUCCESS(status)) { + BOOLEAN Enabled = (BOOLEAN)strtoul(Buffer, NULL, 2); + if (!Enabled) + Target->FeatureDiscard = FALSE; + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "discard-secure", + &Buffer); + if (NT_SUCCESS(status)) { + Target->DiscardSecure = (BOOLEAN)strtoul(Buffer, NULL, 2); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "discard-alignment", + &Buffer); + if (NT_SUCCESS(status)) { + Target->DiscardAlignment = strtoul(Buffer, NULL, 10); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "discard-secure", + &Buffer); + if (NT_SUCCESS(status)) { + Target->DiscardGranularity = strtoul(Buffer, NULL, 10); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "feature-max-indirect-segments", + &Buffer); + if (NT_SUCCESS(status)) { + Target->FeatureIndirect = strtoul(Buffer, NULL, 10); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } +} + +static NTSTATUS +TargetStoreWrite( + IN PXENVBD_TARGET Target, + IN PXENBUS_STORE_TRANSACTION Transaction + ) +{ + NTSTATUS status; + + status = XENBUS_STORE(Printf, + &Target->StoreInterface, + Transaction, + Target->Path, + "target-id", + "%u", + Target->TargetId); + if (!NT_SUCCESS(status)) + return status; + + status = XENBUS_STORE(Printf, + &Target->StoreInterface, + Transaction, + Target->Path, + "feature-surprise-remove", + "%u", + TRUE); + if (!NT_SUCCESS(status)) + return status; + + status = XENBUS_STORE(Printf, + &Target->StoreInterface, + Transaction, + Target->Path, + "feature-online-resize", + "%u", + TRUE); + if (!NT_SUCCESS(status)) + return status; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + return STATUS_SUCCESS; +} - QueueAppend(&Target->SubmittedReqs, &Request->Entry); - KeMemoryBarrier(); +static NTSTATUS +TargetWriteTargetPath( + IN PXENVBD_TARGET Target + ) +{ + NTSTATUS status; - if (BlockRingSubmit(BlockRing, Request)) - continue; + status = XENBUS_STORE(Printf, + &Target->StoreInterface, + NULL, + Target->TargetPath, + "frontend", + "%s", + Target->Path); + if (!NT_SUCCESS(status)) + goto fail1; - QueueRemove(&Target->SubmittedReqs, &Request->Entry); - QueueUnPop(&Target->PreparedReqs, &Request->Entry); - return FALSE; // ring full - } + status = XENBUS_STORE(Printf, + &Target->StoreInterface, + NULL, + Target->TargetPath, + "device", + "%u", + Target->DeviceId); + if (!NT_SUCCESS(status)) + goto fail2; - return TRUE; + return STATUS_SUCCESS; + +fail2: + Error("fail2\n"); +fail1: + Error("fail1 %08x\n", status); + return status; } -static FORCEINLINE VOID -TargetCompleteShutdown( - __in PXENVBD_TARGET Target +static VOID +TargetWaitForBackendStateChange( + IN PXENVBD_TARGET Target, + OUT XenbusState* State ) { - if (QueueCount(&Target->ShutdownSrbs) == 0) - return; + KEVENT Event; + PXENBUS_STORE_WATCH Watch; + LARGE_INTEGER Start; + ULONGLONG TimeDelta; + LARGE_INTEGER Timeout; + XenbusState Old = *State; + NTSTATUS status; - if (QueueCount(&Target->FreshSrbs) || - QueueCount(&Target->PreparedReqs) || - QueueCount(&Target->SubmittedReqs)) - return; + KeInitializeEvent(&Event, NotificationEvent, FALSE); - for (;;) { - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY ListEntry = QueuePop(&Target->ShutdownSrbs); - if (ListEntry == NULL) - break; - SrbExt = CONTAINING_RECORD(ListEntry, XENVBD_SRBEXT, ListEntry); - SrbExt->Srb->SrbStatus = SRB_STATUS_SUCCESS; - AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt); + status = XENBUS_STORE(WatchAdd, + &Target->StoreInterface, + Target->BackendPath, + "state", + &Event, + &Watch); + if (!NT_SUCCESS(status)) + Watch = NULL; + + KeQuerySystemTime(&Start); + TimeDelta = 0; + + Timeout.QuadPart = 0; + + while (*State == Old && TimeDelta < 120000) { + PCHAR Buffer; + LARGE_INTEGER Now; + + if (Watch != NULL) { + ULONG Attempt = 0; + + while (++Attempt < 1000) { + status = KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + &Timeout); + if (status != STATUS_TIMEOUT) + break; + + // We are waiting for a watch event at DISPATCH_LEVEL so + // it is our responsibility to poll the store ring. + XENBUS_STORE(Poll, + &Target->StoreInterface); + + KeStallExecutionProcessor(1000); // 1ms + } + + KeClearEvent(&Event); + } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "state", + &Buffer); + if (!NT_SUCCESS(status)) { + *State = XenbusStateUnknown; + } else { + *State = (XenbusState)strtol(Buffer, NULL, 10); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } + + KeQuerySystemTime(&Now); + + TimeDelta = (Now.QuadPart - Start.QuadPart) / 10000ull; } + + if (Watch != NULL) + (VOID) XENBUS_STORE(WatchRemove, + &Target->StoreInterface, + Watch); } -static FORCEINLINE PCHAR -BlkifOperationName( - IN UCHAR Operation +static NTSTATUS +TargetUpdatePath( + IN PXENVBD_TARGET Target ) { - 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 "<unknown>"; + ULONG Length; + PCHAR Buffer; + NTSTATUS status; + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->Path, + "backend-id", + &Buffer); + if (NT_SUCCESS(status)) { + Target->BackendId = (USHORT)strtoul(Buffer, NULL, 10); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } else { + Target->BackendId = 0; } + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->Path, + "backend", + &Buffer); + if (!NT_SUCCESS(status)) + goto fail1; + + __TargetFree(Target->BackendPath); + Target->BackendPath = NULL; + + Length = (ULONG)strlen(Buffer); + + status = STATUS_NO_MEMORY; + Target->BackendPath = __TargetAllocate(Length + 1); + if (Target->BackendPath == NULL) + goto fail2; + + RtlCopyMemory(Target->BackendPath, Buffer, Length); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + + return STATUS_SUCCESS; + +fail2: + Error("fail2\n"); + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); +fail1: + Error("fail1 %08x\n", status); + return status; + } -VOID -TargetSubmitRequests( - __in PXENVBD_TARGET Target +static NTSTATUS +TargetClose( + 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; + XenbusState State; + NTSTATUS status; - // 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; - } + Trace("[%u] ----->\n", Target->TargetId); - // if no requests/SRBs outstanding, complete any shutdown SRBs - TargetCompleteShutdown(Target); + if (Target->BackendWatch) + XENBUS_STORE(WatchRemove, + &Target->StoreInterface, + Target->BackendWatch); + Target->BackendWatch = NULL; + + status = TargetUpdatePath(Target); + if (!NT_SUCCESS(status)) + goto fail1; + + State = XenbusStateUnknown; + do { + TargetWaitForBackendStateChange(Target, &State); + + status = STATUS_UNSUCCESSFUL; + if (State == XenbusStateUnknown) + goto fail2; + } while (State == XenbusStateInitialising); + + while (State != XenbusStateClosing && + State != XenbusStateClosed) { + status = XENBUS_STORE(Printf, + &Target->StoreInterface, + NULL, + Target->Path, + "state", + "%u", + (ULONG)XenbusStateClosing); + if (!NT_SUCCESS(status)) + goto fail3; + + TargetWaitForBackendStateChange(Target, &State); + + status = STATUS_UNSUCCESSFUL; + if (State == XenbusStateUnknown) + goto fail4; + } + + while (State != XenbusStateClosed) { + status = XENBUS_STORE(Printf, + &Target->StoreInterface, + NULL, + Target->Path, + "state", + "%u", + (ULONG)XenbusStateClosed); + if (!NT_SUCCESS(status)) + goto fail3; + + TargetWaitForBackendStateChange(Target, &State); + + status = STATUS_UNSUCCESSFUL; + if (State == XenbusStateUnknown) + goto fail4; + } + + Trace("[%u] <-----\n", Target->TargetId); + return STATUS_SUCCESS; + +fail4: + Error("fail4\n"); +fail3: + Error("fail3\n"); +fail2: + Error("fail2\n"); +fail1: + Error("fail1 %08x\n", status); + return status; } -VOID -TargetCompleteResponse( - __in PXENVBD_TARGET Target, - __in ULONG Tag, - __in SHORT Status +static NTSTATUS +TargetPrepare( + IN PXENVBD_TARGET Target ) { - PXENVBD_REQUEST Request; - PSCSI_REQUEST_BLOCK Srb; - PXENVBD_SRBEXT SrbExt; + XenbusState State; + NTSTATUS status; - Request = TargetRequestFromTag(Target, Tag); - if (Request == NULL) - return; + Trace("[%u] ----->\n", Target->TargetId); + + status = TargetUpdatePath(Target); + if (!NT_SUCCESS(status)) + goto fail1; + + status = XENBUS_STORE(WatchAdd, + &Target->StoreInterface, + NULL, + Target->BackendPath, + ThreadGetEvent(Target->BackendThread), + &Target->BackendWatch); + if (!NT_SUCCESS(status)) + goto fail2; - Srb = Request->Srb; - SrbExt = Srb->SrbExtension; - ASSERT3P(SrbExt, !=, NULL); + status = TargetWriteTargetPath(Target); + if (!NT_SUCCESS(status)) + goto fail3; - switch (Status) { - case BLKIF_RSP_OKAY: - RequestCopyOutput(Request); - break; + status = XENBUS_STORE(Printf, + &Target->StoreInterface, + NULL, + Target->Path, + "state", + "%u", + (ULONG)XenbusStateInitialising); + if (!NT_SUCCESS(status)) + goto fail4; - 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; + State = XenbusStateUnknown; + do { + TargetWaitForBackendStateChange(Target, &State); - 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; - } + status = STATUS_UNSUCCESSFUL; + if (State == XenbusStateUnknown) + goto fail5; + } while (State == XenbusStateClosed || + State == XenbusStateInitialising); - TargetPutRequest(Target, Request); + status = STATUS_UNSUCCESSFUL; + if (State != XenbusStateInitWait) + goto fail6; - // complete srb - if (InterlockedDecrement(&SrbExt->RequestCount) == 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 - } + Trace("[%u] <-----\n", Target->TargetId); + return STATUS_SUCCESS; - AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt); - } +fail6: + Error("fail6\n"); +fail5: + Error("fail5\n"); +fail4: + Error("fail4\n"); +fail3: + Error("fail3\n"); + XENBUS_STORE(WatchRemove, + &Target->StoreInterface, + Target->BackendWatch); + Target->BackendWatch = NULL; +fail2: + Error("fail2\n"); +fail1: + Error("fail1 %08x\n", status); + return status; } -VOID -TargetPreResume( - __in PXENVBD_TARGET Target +static NTSTATUS +TargetConnect( + IN PXENVBD_TARGET Target ) { - LIST_ENTRY List; - - InitializeListHead(&List); + XenbusState State; + NTSTATUS status; - // 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 = Request->Srb->SrbExtension; + Trace("[%u] ----->\n", Target->TargetId); - TargetPutRequest(Target, Request); + status = GranterConnect(Target->Granter); + if (!NT_SUCCESS(status)) + goto fail1; - if (InterlockedDecrement(&SrbExt->RequestCount) == 0) { - InsertTailList(&List, &SrbExt->ListEntry); - } - } + status = BlockRingConnect(Target->BlockRing); + if (!NT_SUCCESS(status)) + goto fail2; - // 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) + PXENBUS_STORE_TRANSACTION Transaction; + + status = XENBUS_STORE(TransactionStart, + &Target->StoreInterface, + &Transaction); + if (!NT_SUCCESS(status)) break; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - SrbExt = Request->Srb->SrbExtension; - TargetPutRequest(Target, Request); + status = BlockRingStoreWrite(Target->BlockRing, Transaction); + if (!NT_SUCCESS(status)) + goto abort; - if (InterlockedDecrement(&SrbExt->RequestCount) == 0) { - InsertTailList(&List, &SrbExt->ListEntry); - } - } + status = GranterStoreWrite(Target->Granter, Transaction); + if (!NT_SUCCESS(status)) + goto abort; - // foreach SRB in list, put on start of FreshSrbs - for (;;) { - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY ListEntry = RemoveTailList(&List); - if (ListEntry == &List) - break; - SrbExt = CONTAINING_RECORD(ListEntry, XENVBD_SRBEXT, ListEntry); + status = TargetStoreWrite(Target, Transaction); + if (!NT_SUCCESS(status)) + goto abort; + + status = XENBUS_STORE(TransactionEnd, + &Target->StoreInterface, + Transaction, + TRUE); + if (status == STATUS_RETRY) + continue; + break; - QueueUnPop(&Target->FreshSrbs, &SrbExt->ListEntry); +abort: + (VOID) XENBUS_STORE(TransactionEnd, + &Target->StoreInterface, + Transaction, + FALSE); + break; } + if (!NT_SUCCESS(status)) + goto fail3; - // now the first set of requests popped off submitted list is the next SRB - // to be popped off the fresh list -} + status = XENBUS_STORE(Printf, + &Target->StoreInterface, + NULL, + Target->Path, + "state", + "%u", + (ULONG)XenbusStateInitialised); + if (!NT_SUCCESS(status)) + goto fail4; + + State = XenbusStateUnknown; + do { + TargetWaitForBackendStateChange(Target, &State); + + status = STATUS_UNSUCCESSFUL; + if (State == XenbusStateUnknown) + goto fail5; + } while (State == XenbusStateInitWait || + State == XenbusStateInitialising || + State == XenbusStateInitialised); + + status = STATUS_UNSUCCESSFUL; + if (State != XenbusStateConnected) + goto fail6; + + TargetStoreReadDiskInfo(Target); + TargetStoreReadFeatures(Target); + + status = XENBUS_STORE(Printf, + &Target->StoreInterface, + NULL, + Target->Path, + "state", + "%u", + (ULONG)XenbusStateConnected); + if (!NT_SUCCESS(status)) + goto fail7; -VOID -TargetPostResume( - __in PXENVBD_TARGET Target - ) -{ - KIRQL Irql; + Trace("[%u] <-----\n", Target->TargetId); + return STATUS_SUCCESS; - 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); +fail7: + Error("fail7\n"); +fail6: + Error("fail6\n"); +fail5: + Error("fail5\n"); +fail4: + Error("fali4\n"); +fail3: + Error("fail3\n"); + BlockRingDisconnect(Target->BlockRing); +fail2: + Error("fail2\n"); + GranterDisconnect(Target->Granter); +fail1: + Error("fail1 %08x\n", status); + return status; } -//============================================================================= -// SRBs -__checkReturn -static FORCEINLINE BOOLEAN -__ValidateSectors( - __in ULONG64 SectorCount, - __in ULONG64 Start, - __in ULONG Length +static VOID +TargetEnable( + IN PXENVBD_TARGET Target ) { - // Deal with overflow - return (Start < SectorCount) && ((Start + Length) <= SectorCount); -} + Trace("[%u] ----->\n", Target->TargetId); -__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; - } - } + GranterEnable(Target->Granter); + BlockRingEnable(Target->BlockRing); - return TRUE; + Trace("[%u] <-----\n", Target->TargetId); } -static DECLSPEC_NOINLINE VOID -TargetReadWrite( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt +static VOID +TargetDisable( + IN PXENVBD_TARGET Target ) { - PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; - PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Target->Frontend); - 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; - Srb->SrbStatus = SRB_STATUS_ERROR; - return; - } + Trace("[%u] ----->\n", Target->TargetId); - // 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 - Srb->SrbStatus = SRB_STATUS_ERROR; - return; // Complete now - } + BlockRingDisable(Target->BlockRing); + GranterDisable(Target->Granter); - QueueAppend(&Target->FreshSrbs, &SrbExt->ListEntry); - NotifierKick(Notifier); + Trace("[%u] <-----\n", Target->TargetId); } -static DECLSPEC_NOINLINE VOID -TargetSyncCache( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt +static VOID +TargetDisconnect( + IN PXENVBD_TARGET Target ) { - PSCSI_REQUEST_BLOCK Srb = SrbExt->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; - Srb->SrbStatus = SRB_STATUS_ERROR; - return; - } + Trace("[%u] ----->\n", Target->TargetId); - 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; - } + BlockRingDisconnect(Target->BlockRing); + GranterDisconnect(Target->Granter); - QueueAppend(&Target->FreshSrbs, &SrbExt->ListEntry); - NotifierKick(Notifier); + Trace("[%u] <-----\n", Target->TargetId); } -static DECLSPEC_NOINLINE VOID -TargetUnmap( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt +static FORCEINLINE PCHAR +XenvbdStateName( + IN XENVBD_STATE State ) { - PSCSI_REQUEST_BLOCK Srb = SrbExt->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; - Srb->SrbStatus = SRB_STATUS_ERROR; - return; - } - - 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; + switch (State) { + case XENVBD_STATE_INVALID: return "INVALID"; + case XENVBD_INITIALIZED: return "INITIAIZED"; + case XENVBD_CLOSING: return "CLOSING"; + case XENVBD_CLOSED: return "CLOSED"; + case XENVBD_PREPARED: return "PREPARED"; + case XENVBD_CONNECTED: return "CONNECTED"; + case XENVBD_ENABLED: return "ENABLED"; + default: return "<UNKNOWN>"; } - - QueueAppend(&Target->FreshSrbs, &SrbExt->ListEntry); - NotifierKick(Notifier); } -#define MODE_CACHING_PAGE_LENGTH 20 -static DECLSPEC_NOINLINE VOID -TargetModeSense( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt - ) -{ - PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; - PMODE_PARAMETER_HEADER Header = Srb->DataBuffer; - const UCHAR PageCode = Cdb_PageCode(Srb); - ULONG LengthLeft = Cdb_AllocationLength(Srb); - PVOID CurrentPage = Srb->DataBuffer; +static NTSTATUS +TargetSetState( + IN PXENVBD_TARGET Target, + IN XENVBD_STATE State + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + Verbose("[%u] %s -> %s\n", + Target->TargetId, + XenvbdStateName(Target->State), + XenvbdStateName(State)); + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + while (NT_SUCCESS(status) && Target->State != State) { + switch (Target->State) { + case XENVBD_INITIALIZED: + switch (State) { + case XENVBD_CLOSING: + case XENVBD_CLOSED: + case XENVBD_PREPARED: + case XENVBD_CONNECTED: + case XENVBD_ENABLED: + status = TargetClose(Target); + if (!NT_SUCCESS(status)) + break; + Target->State = XENVBD_CLOSED; + break; + default: + status = STATUS_UNSUCCESSFUL; + break; + } + break; - UNREFERENCED_PARAMETER(Target); + case XENVBD_CLOSING: + switch (State) { + case XENVBD_INITIALIZED: + case XENVBD_CLOSED: + case XENVBD_PREPARED: + case XENVBD_CONNECTED: + case XENVBD_ENABLED: + TargetDisconnect(Target); + Target->State = XENVBD_CLOSED; + break; + default: + status = STATUS_UNSUCCESSFUL; + break; + } + break; - RtlZeroMemory(Srb->DataBuffer, Srb->DataTransferLength); + case XENVBD_CLOSED: + switch (State) { + //case XENVBD_INITIALIZING: + // Target->State = XENVBD_INITIALISED; + // break; + case XENVBD_PREPARED: + case XENVBD_CONNECTED: + case XENVBD_ENABLED: + status = TargetPrepare(Target); + if (!NT_SUCCESS(status)) { + TargetClose(Target); + Target->State = XENVBD_CLOSED; + break; + } + Target->State = XENVBD_PREPARED; + break; + default: + status = STATUS_UNSUCCESSFUL; + break; + } + break; - if (!__ValidateSrbBuffer(__FUNCTION__, Srb, (ULONG)sizeof(struct _MODE_SENSE))) { - Srb->ScsiStatus = 0x40; - Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; - Srb->DataTransferLength = 0; - return; - } + case XENVBD_PREPARED: + switch (State) { + case XENVBD_CLOSING: + case XENVBD_CLOSED: + status = TargetClose(Target); + if (!NT_SUCCESS(status)) + break; + Target->State = XENVBD_CLOSED; + break; + case XENVBD_CONNECTED: + case XENVBD_ENABLED: + status = TargetConnect(Target); + if (!NT_SUCCESS(status)) { + TargetClose(Target); + Target->State = XENVBD_CLOSED; + break; + } + Target->State = XENVBD_CONNECTED; + break; + default: + status = STATUS_UNSUCCESSFUL; + break; + } + break; - // 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; + case XENVBD_CONNECTED: + switch (State) { + case XENVBD_ENABLED: + TargetEnable(Target); + Target->State = XENVBD_ENABLED; + break; + case XENVBD_CLOSING: + case XENVBD_CLOSED: + status = TargetClose(Target); + if (!NT_SUCCESS(status)) + break; + Target->State = XENVBD_CLOSING; + break; + default: + status = STATUS_UNSUCCESSFUL; + break; + } + break; - Header->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK); - Header->ModeDataLength += sizeof(MODE_PARAMETER_BLOCK); - LengthLeft -= sizeof(MODE_PARAMETER_BLOCK); - CurrentPage = ((PUCHAR)CurrentPage + sizeof(MODE_PARAMETER_BLOCK)); - } + case XENVBD_ENABLED: + switch (State) { + case XENVBD_CLOSING: + case XENVBD_CLOSED: + case XENVBD_CONNECTED: + TargetDisable(Target); + Target->State = XENVBD_CONNECTED; + break; + default: + status = STATUS_UNSUCCESSFUL; + break; + } + break; - // 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); + default: + status = STATUS_UNSUCCESSFUL; + break; + } } - // 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)); - } + Verbose("[%u] in state %s\n", + Target->TargetId, + XenvbdStateName(Target->State)); - // Finish this SRB - Srb->SrbStatus = SRB_STATUS_SUCCESS; - Srb->DataTransferLength = __min(Cdb_AllocationLength(Srb), (ULONG)(Header->ModeDataLength + 1)); + return status; } -static DECLSPEC_NOINLINE VOID -TargetRequestSense( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt +static FORCEINLINE NTSTATUS +__TargetD3ToD0( + IN PXENVBD_TARGET Target ) { - PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; - PSENSE_DATA Sense = Srb->DataBuffer; + NTSTATUS status; - UNREFERENCED_PARAMETER(Target); + status = XENBUS_STORE(Acquire, &Target->StoreInterface); + if (!NT_SUCCESS(status)) + goto fail1; - if (!__ValidateSrbBuffer(__FUNCTION__, Srb, (ULONG)sizeof(SENSE_DATA))) { - Srb->ScsiStatus = 0x40; - Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; - return; - } + status = TargetSetState(Target, XENVBD_ENABLED); + if (!NT_SUCCESS(status)) + goto fail2; - RtlZeroMemory(Sense, sizeof(SENSE_DATA)); + return STATUS_SUCCESS; - 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; +fail2: + Error("fail2\n"); + XENBUS_STORE(Release, &Target->StoreInterface); +fail1: + Error("fail1 %08x\n", status); + return status; } -static DECLSPEC_NOINLINE VOID -TargetReportLuns( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt +static FORCEINLINE VOID +__TargetD0ToD3( + IN PXENVBD_TARGET Target ) { - PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; - ULONG Length; - ULONG Offset; - ULONG AllocLength = Cdb_AllocationLength(Srb); - PUCHAR Buffer = Srb->DataBuffer; - - UNREFERENCED_PARAMETER(Target); + TargetSetState(Target, XENVBD_CLOSED); - if (!__ValidateSrbBuffer(__FUNCTION__, Srb, 8)) { - Srb->ScsiStatus = 0x40; - Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; - Srb->DataTransferLength = 0; - return; - } + XENBUS_STORE(Release, &Target->StoreInterface); +} - RtlZeroMemory(Buffer, AllocLength); +static DECLSPEC_NOINLINE VOID +TargetSuspendCallback( + IN PVOID Context + ) +{ + PXENVBD_TARGET Target = Context; + LIST_ENTRY List; + NTSTATUS status; - Length = 0; - Offset = 8; + // Any outstanding requests are going to cause problems... + // Submitted requests are lost + // Prepared requests will need re-preparing (different grant/backend) + // Fresh SRBs will be ok + InitializeListHead(&List); + for (;;) { + PLIST_ENTRY ListEntry; + PXENVBD_REQUEST Request; + PXENVBD_SRBEXT SrbExt; - if (Offset + 8 <= AllocLength) { - Buffer[Offset] = 0; - Offset += 8; - Length += 8; - } + ListEntry = RemoveHeadList(&Target->Submitted); + if (ListEntry == &Target->Submitted) + break; + Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); + SrbExt = Request->SrbExt; - if (Offset + 8 <= AllocLength) { - Buffer[Offset] = XENVBD_MAX_TARGETS; - Offset += 8; - Length += 8; + TargetPutRequest(Target, Request); + if (InterlockedDecrement(&SrbExt->RequestCount) == 0) { + SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; + AdapterCompleteSrb(Target->Adapter, SrbExt); + } } + for (;;) { + PLIST_ENTRY ListEntry; + PXENVBD_REQUEST Request; + PXENVBD_SRBEXT SrbExt; - REVERSE_BYTES(Buffer, &Length); - - Srb->DataTransferLength = __min(Length, AllocLength); - Srb->SrbStatus = SRB_STATUS_SUCCESS; -} + ListEntry = RemoveHeadList(&Target->Prepared); + if (ListEntry == &Target->Prepared) + break; + Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); + SrbExt = Request->SrbExt; -static DECLSPEC_NOINLINE VOID -TargetReadCapacity( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt - ) -{ - PSCSI_REQUEST_BLOCK Srb = SrbExt->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; + TargetPutRequest(Target, Request); + if (InterlockedDecrement(&SrbExt->RequestCount) == 0) { + InsertHeadList(&List, &SrbExt->ListEntry); + } } - - SectorCount = DiskInfo->SectorCount; - SectorSize = DiskInfo->SectorSize; + for (;;) { + PLIST_ENTRY ListEntry; - if (SectorCount == (ULONG)SectorCount) - LastBlock = (ULONG)SectorCount - 1; - else - LastBlock = ~(ULONG)0; + ListEntry = RemoveHeadList(&List); + if (ListEntry == &List) + break; - if (Capacity) { - Capacity->LogicalBlockAddress = _byteswap_ulong(LastBlock); - Capacity->BytesPerBlock = _byteswap_ulong(SectorSize); + InsertHeadList(&Target->Fresh, ListEntry); } - Srb->SrbStatus = SRB_STATUS_SUCCESS; + __TargetD0ToD3(Target); + + status = __TargetD3ToD0(Target); + ASSERT(NT_SUCCESS(status)); } static DECLSPEC_NOINLINE VOID -TargetReadCapacity16( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt +TargetDebugCallback( + IN PVOID Context, + IN BOOLEAN Crashing ) -{ - PSCSI_REQUEST_BLOCK Srb = SrbExt->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; +{ + PXENVBD_TARGET Target = Context; - LogicalPerPhysical = PhysSectorSize / SectorSize; + UNREFERENCED_PARAMETER(Crashing); - if (!_BitScanReverse(&LogicalPerPhysicalExponent, LogicalPerPhysical)) - LogicalPerPhysicalExponent = 0; + XENBUS_DEBUG(Printf, + &Target->DebugInterface, + "Adapter: 0x%p DeviceObject: 0x%p\n", + Target->Adapter, + Target->DeviceObject); - if (Capacity) { - Capacity->LogicalBlockAddress.QuadPart = _byteswap_uint64(SectorCount - 1); - Capacity->BytesPerBlock = _byteswap_ulong(SectorSize); - Capacity->LogicalPerPhysicalExponent = (UCHAR)LogicalPerPhysicalExponent; - } + XENBUS_DEBUG(Printf, + &Target->DebugInterface, + "TargetI: %u DeviceId: %u BackendId: %u\n", + Target->TargetId, + Target->DeviceId, + Target->BackendId); + + XENBUS_DEBUG(Printf, + &Target->DebugInterface, + "Path: %s\n", + Target->Path); + + XENBUS_DEBUG(Printf, + &Target->DebugInterface, + "BackendPath: %s\n", + Target->BackendPath ? Target->BackendPath : "NULL"); + + XENBUS_DEBUG(Printf, + &Target->DebugInterface, + "TargetPath: %s\n", + Target->TargetPath); + + XENBUS_DEBUG(Printf, + &Target->DebugInterface, + "Features: %s%s%s%s%s\n", + Target->Removable ? "REMOVABLE " : "", + Target->FeatureBarrier ? "BARRIER " : "", + Target->FeatureDiscard ? "DISCARD " : "", + Target->FeatureFlush ? "FLUSH " : "", + Target->FeatureIndirect ? "INDIRECT " : ""); + + if (Target->FeatureDiscard) { + XENBUS_DEBUG(Printf, + &Target->DebugInterface, + "DISCARD: %s%u @ %u\n", + Target->DiscardSecure ? "SECURE " : "", + Target->DiscardAlignment, + Target->DiscardGranularity); + } + + if (Target->FeatureIndirect) { + XENBUS_DEBUG(Printf, + &Target->DebugInterface, + "INDIRECT: %u MaxSegsPerInd\n", + Target->FeatureIndirect); + } + + XENBUS_DEBUG(Printf, + &Target->DebugInterface, + "%llu sectors @ %u (%u) %08x\n", + Target->SectorCount, + Target->SectorSize, + Target->PhysicalSectorSize, + Target->DiskInfo); +} + +static DECLSPEC_NOINLINE NTSTATUS +TargetBackendThread( + IN PXENVBD_THREAD Self, + IN PVOID Context + ) +{ + PXENVBD_TARGET Target = Context; + PKEVENT Event = ThreadGetEvent(Self); + LARGE_INTEGER Start; + LARGE_INTEGER Now; + + KeQuerySystemTime(&Start); + for (;;) { + PCHAR Buffer; + NTSTATUS status; + KIRQL Irql; + BOOLEAN Online = TRUE; + + (VOID) KeWaitForSingleObject(Event, + Executive, + KernelMode, + FALSE, + NULL); + if (ThreadIsAlerted(Self)) + break; - Srb->SrbStatus = SRB_STATUS_SUCCESS; -} + KeQuerySystemTime(&Now); + // Rate limit checking to once a second + if ((Now.QuadPart - Start.QuadPart) < 10000000ull) + continue; + Start.QuadPart = Now.QuadPart; -static FORCEINLINE VOID -__TargetQueueShutdown( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt - ) -{ - PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend); + KeAcquireSpinLock(&Target->StateLock, &Irql); + if (Target->DevicePowerState != PowerDeviceD0) { + KeReleaseSpinLock(&Target->StateLock, Irql); + continue; + } + KeReleaseSpinLock(&Target->StateLock, Irql); + + TargetStoreReadDiskInfo(Target); + + status = XENBUS_STORE(Read, + &Target->StoreInterface, + NULL, + Target->BackendPath, + "online", + &Buffer); + if (NT_SUCCESS(status)) { + Online = (BOOLEAN)strtoul(Buffer, NULL, 2); + + XENBUS_STORE(Free, + &Target->StoreInterface, + Buffer); + } - QueueAppend(&Target->ShutdownSrbs, &SrbExt->ListEntry); - NotifierKick(Notifier); + if (!Online) { + // eject! + TargetSetMissing(Target, "Ejecting"); + AdapterTargetListChanged(TargetGetAdapter(Target)); + } + } - SrbExt->Srb->SrbStatus = SRB_STATUS_PENDING; + return STATUS_SUCCESS; } -VOID -TargetReset( +NTSTATUS +TargetD3ToD0( IN PXENVBD_TARGET Target ) { + KIRQL Irql; + NTSTATUS status; + + if (Target->DevicePowerState == PowerDeviceD0) + return STATUS_SUCCESS; + Verbose("[%u] =====>\n", - TargetGetTargetId(Target)); + Target->TargetId); - __TargetPauseDataPath(Target, TRUE); + status = XENBUS_DEBUG(Acquire, &Target->DebugInterface); + if (!NT_SUCCESS(status)) + goto fail1; - if (QueueCount(&Target->SubmittedReqs)) { - Error("Target[%d] : backend has %u outstanding requests after a TargetReset\n", - TargetGetTargetId(Target), QueueCount(&Target->SubmittedReqs)); - } + status = XENBUS_SUSPEND(Acquire, &Target->SuspendInterface); + if (!NT_SUCCESS(status)) + goto fail2; - __TargetUnpauseDataPath(Target); + status = XENBUS_DEBUG(Register, + &Target->DebugInterface, + __MODULE__, + TargetDebugCallback, + Target, + &Target->DebugCallback); + if (!NT_SUCCESS(status)) + goto fail3; - Verbose("[%u] <=====\n", - TargetGetTargetId(Target)); -} + status = XENBUS_SUSPEND(Register, + &Target->SuspendInterface, + SUSPEND_CALLBACK_LATE, + TargetSuspendCallback, + Target, + &Target->SuspendCallback); + if (!NT_SUCCESS(status)) + goto fail4; -VOID -TargetPrepareSrb( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt - ) -{ - PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + KeAcquireSpinLock(&Target->StateLock, &Irql); + status = __TargetD3ToD0(Target); + KeReleaseSpinLock(&Target->StateLock, Irql); + if (!NT_SUCCESS(status)) + goto fail5; - SrbExt->Srb->SrbStatus = SRB_STATUS_NO_DEVICE; - if (TargetIsMissing(Target)) - return; + Target->DevicePowerState = PowerDeviceD0; + Verbose("[%u] <=====\n", + Target->TargetId); + return STATUS_SUCCESS; - Srb->SrbStatus = SRB_STATUS_PENDING; +fail5: + Error("fail5\n"); + XENBUS_SUSPEND(Deregister, + &Target->SuspendInterface, + Target->SuspendCallback); + Target->SuspendCallback = NULL; +fail4: + Error("fail4\n"); + XENBUS_DEBUG(Deregister, + &Target->DebugInterface, + Target->DebugCallback); + Target->DebugCallback = NULL; +fail3: + Error("fail3\n"); + XENBUS_SUSPEND(Release, + &Target->SuspendInterface); +fail2: + Error("fail2\n"); + XENBUS_DEBUG(Release, + &Target->DebugInterface); +fail1: + Error("fail1 %08x\n", status); + return status; } VOID -TargetStartSrb( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt +TargetD0ToD3( + IN PXENVBD_TARGET Target ) { - const UCHAR Operation = Cdb_OperationEx(SrbExt->Srb); - PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Target->Frontend); + KIRQL Irql; - if (DiskInfo->DiskInfo & VDISK_READONLY) { - Trace("Target[%d] : (%08x) Read-Only, fail SRB (%02x:%s)\n", TargetGetTargetId(Target), - DiskInfo->DiskInfo, Operation, Cdb_OperationName(Operation)); - SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORT - SrbExt->Srb->SrbStatus = SRB_STATUS_ERROR; + if (Target->DevicePowerState == PowerDeviceD3) return; - } - - switch (Operation) { - case SCSIOP_READ: - TargetReadWrite(Target, SrbExt); - case SCSIOP_WRITE: - TargetReadWrite(Target, SrbExt); - break; - - case SCSIOP_SYNCHRONIZE_CACHE: - TargetSyncCache(Target, SrbExt); - break; + Verbose("[%u] =====>\n", + Target->TargetId); + Target->DevicePowerState = PowerDeviceD3; - case SCSIOP_UNMAP: - TargetUnmap(Target, SrbExt); - break; + KeAcquireSpinLock(&Target->StateLock, &Irql); + __TargetD0ToD3(Target); + KeReleaseSpinLock(&Target->StateLock, Irql); - 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), SrbExt->Srb); - break; - case SCSIOP_MODE_SENSE: - TargetModeSense(Target, SrbExt); - break; - case SCSIOP_REQUEST_SENSE: - TargetRequestSense(Target, SrbExt); - break; - case SCSIOP_REPORT_LUNS: - TargetReportLuns(Target, SrbExt); - break; - case SCSIOP_READ_CAPACITY: - TargetReadCapacity(Target, SrbExt); - break; - case SCSIOP_READ_CAPACITY16: - TargetReadCapacity16(Target, SrbExt); - break; + XENBUS_SUSPEND(Deregister, + &Target->SuspendInterface, + Target->SuspendCallback); + Target->SuspendCallback = NULL; - 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: - case SCSIOP_START_STOP_UNIT: - SrbExt->Srb->SrbStatus = SRB_STATUS_SUCCESS; - break; + XENBUS_DEBUG(Deregister, + &Target->DebugInterface, + Target->DebugCallback); + Target->DebugCallback = NULL; - default: - Trace("Target[%d] : Unsupported CDB (%02x:%s)\n", - TargetGetTargetId(Target), - Operation, - Cdb_OperationName(Operation)); - SrbExt->Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; - break; - } -} + XENBUS_SUSPEND(Release, + &Target->SuspendInterface); -VOID -TargetFlush( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt - ) -{ - __TargetQueueShutdown(Target, SrbExt); -} + XENBUS_DEBUG(Release, + &Target->DebugInterface); -VOID -TargetShutdown( - IN PXENVBD_TARGET Target, - IN PXENVBD_SRBEXT SrbExt - ) -{ - __TargetQueueShutdown(Target, SrbExt); + Verbose("[%u] <=====\n", + Target->TargetId); } -VOID -TargetSrbPnp( - __in PXENVBD_TARGET Target, - __in PSCSI_PNP_REQUEST_BLOCK Srb +static FORCEINLINE PCHAR +__DeviceUsageName( + IN ULONG Index ) { - 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; + switch (Index) { + case DeviceUsageTypeUndefined: return NULL; + case DeviceUsageTypePaging: return "paging"; + case DeviceUsageTypeHibernation: return "hibernation"; + case DeviceUsageTypeDumpFile: return "dump"; + default: return NULL; } } -//============================================================================= -// PnP Handler static FORCEINLINE VOID __TargetDeviceUsageNotification( - __in PXENVBD_TARGET Target, - __in PIRP Irp + IN PXENVBD_TARGET Target, + IN PIRP Irp ) { PIO_STACK_LOCATION StackLocation; + ULONG Index; 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; + Index = (ULONG)StackLocation->Parameters.UsageNotification.Type; - default: + if (__DeviceUsageName(Index) == NULL) + return; + if (Target->DeviceUsage[Index] == Value) 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); - AdapterTargetListChanged(TargetGetAdapter(Target)); - break; + Target->DeviceUsage[Index] = Value; - default: - TargetSetMissing(Target, "Removed"); - TargetSetDevicePnpState(Target, Deleted); - AdapterTargetListChanged(TargetGetAdapter(Target)); - break; - } -} + Verbose("[%u] %s %s\n", + Target->TargetId, + Value ? "ADDING" : "REMOVING", + __DeviceUsageName(Index)); -static FORCEINLINE VOID -__TargetEject( - __in PXENVBD_TARGET Target - ) -{ - TargetSetMissing(Target, "Ejected"); - TargetSetDevicePnpState(Target, Deleted); - AdapterTargetListChanged(TargetGetAdapter(Target)); + (VOID) XENBUS_STORE(Printf, + &Target->StoreInterface, + NULL, + Target->TargetPath, + __DeviceUsageName(Index), + "%u", + Value); } -__checkReturn NTSTATUS TargetDispatchPnp( - __in PXENVBD_TARGET Target, - __in PDEVICE_OBJECT DeviceObject, - __in PIRP Irp + IN PXENVBD_TARGET Target, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp ) { - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); - - __TargetCheckEjectPending(Target); - - switch (Stack->MinorFunction) { + PIO_STACK_LOCATION StackLocation; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + switch (StackLocation->MinorFunction) { case IRP_MN_START_DEVICE: (VOID) TargetD3ToD0(Target); TargetSetDevicePnpState(Target, Started); @@ -2340,7 +2847,7 @@ TargetDispatchPnp( break; case IRP_MN_CANCEL_STOP_DEVICE: - __TargetRestoreDevicePnpState(Target, StopPending); + TargetRestoreDevicePnpState(Target); break; case IRP_MN_STOP_DEVICE: @@ -2353,8 +2860,8 @@ TargetDispatchPnp( break; case IRP_MN_CANCEL_REMOVE_DEVICE: - __TargetCheckEjectFailed(Target); - __TargetRestoreDevicePnpState(Target, RemovePending); + // Should write something to Xenstore to indicate the VETO on deviceeject + TargetRestoreDevicePnpState(Target); break; case IRP_MN_SURPRISE_REMOVAL: @@ -2362,11 +2869,16 @@ TargetDispatchPnp( break; case IRP_MN_REMOVE_DEVICE: - __TargetRemoveDevice(Target); + TargetD0ToD3(Target); + TargetSetMissing(Target, DevicePnpStateName(Target->DevicePnpState)); + TargetSetDevicePnpState(Target, Deleted); + AdapterTargetListChanged(TargetGetAdapter(Target)); break; case IRP_MN_EJECT: - __TargetEject(Target); + TargetSetMissing(Target, "Ejected"); + TargetSetDevicePnpState(Target, Deleted); + AdapterTargetListChanged(TargetGetAdapter(Target)); break; case IRP_MN_DEVICE_USAGE_NOTIFICATION: @@ -2376,114 +2888,15 @@ TargetDispatchPnp( default: break; } - 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)); - AdapterTargetListChanged(TargetGetAdapter(Target)); - } -} - -__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()); + return DriverDispatchPnp(DeviceObject, Irp); } static FORCEINLINE ULONG __ParseVbd( - IN PCHAR DeviceIdStr + IN ULONG DeviceId ) -{ - ULONG DeviceId = strtoul(DeviceIdStr, NULL, 10); - +{ ASSERT3U((DeviceId & ~((1 << 29) - 1)), ==, 0); if (DeviceId & (1 << 28)) @@ -2504,140 +2917,235 @@ __ParseVbd( } } -__checkReturn NTSTATUS TargetCreate( - __in PXENVBD_ADAPTER Adapter, - __in __nullterminated PCHAR DeviceId, - OUT PXENVBD_TARGET* _Target + IN PXENVBD_ADAPTER Adapter, + IN PANSI_STRING Device, + OUT PXENVBD_TARGET* _Target ) { - NTSTATUS Status; - PXENVBD_TARGET Target; - ULONG TargetId; + PXENVBD_TARGET Target; + ULONG DeviceId; + ULONG TargetId; + ULONG Size; + NTSTATUS status; + DeviceId = strtoul(Device->Buffer, NULL, 10); TargetId = __ParseVbd(DeviceId); if (TargetId >= XENVBD_MAX_TARGETS) return STATUS_RETRY; - if (AdapterIsTargetEmulated(Adapter, TargetId)) return STATUS_RETRY; - Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); + Verbose("[%u] =====> %s\n", TargetId, Device->Buffer); - Status = STATUS_INSUFFICIENT_RESOURCES; -#pragma warning(suppress: 6014) - Target = __TargetAlloc(sizeof(XENVBD_TARGET)); - if (!Target) + status = STATUS_NO_MEMORY; + Target = __TargetAllocate(sizeof(XENVBD_TARGET)); + if (Target == NULL) goto fail1; - Verbose("Target[%d] : Creating\n", TargetId); - Target->Signature = TARGET_SIGNATURE; - Target->Adapter = Adapter; - Target->DeviceObject = NULL; // filled in later - Target->Paused = 1; // Paused until D3->D0 transition - Target->DevicePnpState = Present; + Target->Adapter = Adapter; + Target->DeviceObject = NULL; // filled in later + Target->DevicePnpState = Present; Target->DevicePowerState = PowerDeviceD3; - - 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)) + Target->DeviceId = DeviceId; + Target->TargetId = TargetId; + Target->State = XENVBD_INITIALIZED; + Target->BackendId = DOMID_INVALID; + KeInitializeSpinLock(&Target->StateLock); + KeInitializeSpinLock(&Target->QueueLock); + + AdapterGetDebugInterface(Adapter, &Target->DebugInterface); + AdapterGetStoreInterface(Adapter, &Target->StoreInterface); + AdapterGetSuspendInterface(Adapter, &Target->SuspendInterface); + + status = STATUS_NO_MEMORY; + Size = sizeof("device/vbd/") + Device->Length + 1; + Target->Path = __TargetAllocate(Size); + if (Target->Path == NULL) goto fail2; - Status = TargetD3ToD0(Target); - if (!NT_SUCCESS(Status)) + status = RtlStringCbPrintfA(Target->Path, + Size, + "device/vbd/%s", + Device->Buffer); + if (!NT_SUCCESS(status)) goto fail3; - *_Target = Target; + status = STATUS_NO_MEMORY; + Size = sizeof("data/scsi/target/XXXX") + 1; + Target->TargetPath = __TargetAllocate(Size); + if (Target->TargetPath == NULL) + goto fail4; - Verbose("Target[%d] : Created (%s)\n", TargetId, Target); - Trace("Target[%d] @ (%d) <=====\n", TargetId, KeGetCurrentIrql()); + status = RtlStringCbPrintfA(Target->TargetPath, + Size, + "data/scsi/target/%u", + TargetId); + if (!NT_SUCCESS(status)) + goto fail5; + + status = GranterCreate(Target, &Target->Granter); + if (!NT_SUCCESS(status)) + goto fail6; + + status = BlockRingCreate(Target, &Target->BlockRing); + if (!NT_SUCCESS(status)) + goto fail7; + + status = ThreadCreate(TargetBackendThread, + Target, + &Target->BackendThread); + if (!NT_SUCCESS(status)) + goto fail8; + + InitializeListHead(&Target->Fresh); + InitializeListHead(&Target->Prepared); + InitializeListHead(&Target->Submitted); + InitializeListHead(&Target->Shutdown); + + ExInitializeNPagedLookasideList(&Target->RequestList, + NULL, + NULL, + 0, + sizeof(XENVBD_REQUEST), + REQUEST_POOL_TAG, + 0); + ExInitializeNPagedLookasideList(&Target->SegmentList, + NULL, + NULL, + 0, + sizeof(XENVBD_SEGMENT), + SEGMENT_POOL_TAG, + 0); + ExInitializeNPagedLookasideList(&Target->IndirectList, + NULL, + NULL, + 0, + sizeof(XENVBD_INDIRECT), + INDIRECT_POOL_TAG, + 0); + + status = TargetD3ToD0(Target); + if (!NT_SUCCESS(status)) + goto fail9; + + Verbose("[%u] <=====\n", TargetId); + *_Target = Target; return STATUS_SUCCESS; +fail9: + Error("fail9\n"); + + ExDeleteNPagedLookasideList(&Target->RequestList); + ExDeleteNPagedLookasideList(&Target->SegmentList); + ExDeleteNPagedLookasideList(&Target->IndirectList); + + RtlZeroMemory(&Target->Fresh, sizeof(LIST_ENTRY)); + RtlZeroMemory(&Target->Prepared, sizeof(LIST_ENTRY)); + RtlZeroMemory(&Target->Submitted, sizeof(LIST_ENTRY)); + RtlZeroMemory(&Target->Shutdown, sizeof(LIST_ENTRY)); + + ThreadAlert(Target->BackendThread); + ThreadJoin(Target->BackendThread); + Target->BackendThread = NULL; +fail8: + Error("fail8\n"); + BlockRingDestroy(Target->BlockRing); + Target->BlockRing = NULL; +fail7: + Error("fail7\n"); + GranterDestroy(Target->Granter); + Target->Granter = NULL; +fail6: + Error("fail6\n"); +fail5: + Error("fail5\n"); + __TargetFree(Target->TargetPath); + Target->TargetPath = NULL; +fail4: + Error("fail4\n"); fail3: - Error("Fail3\n"); - FrontendDestroy(Target->Frontend); - Target->Frontend = NULL; - + Error("fail3\n"); + __TargetFree(Target->Path); + Target->Path = NULL; fail2: - Error("Fail2\n"); - __LookasideTerm(&Target->IndirectList); - __LookasideTerm(&Target->SegmentList); - __LookasideTerm(&Target->RequestList); + Error("fail2\n"); + RtlZeroMemory(&Target->DebugInterface, sizeof(XENBUS_DEBUG_INTERFACE)); + RtlZeroMemory(&Target->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); + RtlZeroMemory(&Target->SuspendInterface, sizeof(XENBUS_SUSPEND_INTERFACE)); + + Target->Adapter = NULL; + Target->DeviceObject = NULL; // filled in later + Target->DevicePnpState = 0; + Target->DevicePowerState = 0; + Target->DeviceId = 0; + Target->TargetId = 0; + Target->State = 0; + Target->BackendId = 0; + RtlZeroMemory(&Target->QueueLock, sizeof(KSPIN_LOCK)); + RtlZeroMemory(&Target->StateLock, sizeof(KSPIN_LOCK)); + + ASSERT(IsZeroMemory(Target, sizeof(XENVBD_TARGET))); __TargetFree(Target); - fail1: - Error("Fail1 (%08x)\n", Status); - return Status; + Error("fail1 %08x\n", status); + return status; } VOID TargetDestroy( - __in PXENVBD_TARGET Target + IN PXENVBD_TARGET Target ) { - const ULONG TargetId = TargetGetTargetId(Target); - PVOID Objects[3]; - PKWAIT_BLOCK WaitBlock; + ASSERT(IsListEmpty(&Target->Fresh)); + ASSERT(IsListEmpty(&Target->Prepared)); + ASSERT(IsListEmpty(&Target->Submitted)); + ASSERT(IsListEmpty(&Target->Shutdown)); - Trace("Target[%d] @ (%d) =====>\n", TargetId, KeGetCurrentIrql()); - Verbose("Target[%d] : Destroying\n", TargetId); + ExDeleteNPagedLookasideList(&Target->RequestList); + ExDeleteNPagedLookasideList(&Target->SegmentList); + ExDeleteNPagedLookasideList(&Target->IndirectList); - ASSERT3U(Target->Signature, ==, TARGET_SIGNATURE); + RtlZeroMemory(&Target->Fresh, sizeof(LIST_ENTRY)); + RtlZeroMemory(&Target->Prepared, sizeof(LIST_ENTRY)); + RtlZeroMemory(&Target->Submitted, sizeof(LIST_ENTRY)); + RtlZeroMemory(&Target->Shutdown, sizeof(LIST_ENTRY)); - TargetD0ToD3(Target); + ThreadAlert(Target->BackendThread); + ThreadJoin(Target->BackendThread); + Target->BackendThread = NULL; - Verbose("Target[%d] : RequestListUsed %d\n", TargetId, Target->RequestList.Used); - Objects[0] = &Target->RequestList.Empty; - Objects[1] = &Target->SegmentList.Empty; - Objects[2] = &Target->IndirectList.Empty; + BlockRingDestroy(Target->BlockRing); + Target->BlockRing = NULL; - WaitBlock = (PKWAIT_BLOCK)__TargetAlloc(sizeof(KWAIT_BLOCK) * ARRAYSIZE(Objects)); - if (WaitBlock == NULL) { - ULONG Index; + GranterDestroy(Target->Granter); + Target->Granter = NULL; - Error("Unable to allocate resources for KWAIT_BLOCK\n"); + __TargetFree(Target->BackendPath); + Target->BackendPath = NULL; - 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); - } + __TargetFree(Target->TargetPath); + Target->TargetPath = NULL; - ASSERT3U(TargetGetDevicePnpState(Target), ==, Deleted); + __TargetFree(Target->Path); + Target->Path = NULL; - FrontendDestroy(Target->Frontend); - Target->Frontend = NULL; + RtlZeroMemory(&Target->DebugInterface, sizeof(XENBUS_DEBUG_INTERFACE)); + RtlZeroMemory(&Target->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); + RtlZeroMemory(&Target->SuspendInterface, sizeof(XENBUS_SUSPEND_INTERFACE)); - __LookasideTerm(&Target->IndirectList); - __LookasideTerm(&Target->SegmentList); - __LookasideTerm(&Target->RequestList); + Target->Adapter = NULL; + Target->DeviceObject = NULL; // filled in later + Target->DevicePnpState = 0; + Target->DevicePowerState = 0; + Target->DeviceId = 0; + Target->TargetId = 0; + Target->State = 0; + Target->BackendId = 0; + RtlZeroMemory(&Target->QueueLock, sizeof(KSPIN_LOCK)); + RtlZeroMemory(&Target->StateLock, sizeof(KSPIN_LOCK)); - ASSERT3U(Target->Signature, ==, TARGET_SIGNATURE); - RtlZeroMemory(Target, sizeof(XENVBD_TARGET)); + ASSERT(IsZeroMemory(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 index 86f57fd..43660dd 100644 --- a/src/xenvbd/target.h +++ b/src/xenvbd/target.h @@ -36,197 +36,117 @@ typedef struct _XENVBD_TARGET XENVBD_TARGET, *PXENVBD_TARGET; -#include "adapter.h" -#include "srbext.h" #include "types.h" -#include <debug_interface.h> - -extern VOID -TargetDebugCallback( - __in PXENVBD_TARGET Target, - __in PXENBUS_DEBUG_INTERFACE Debug - ); - -// Creation/Deletion -__checkReturn -extern NTSTATUS -TargetCreate( - __in PXENVBD_ADAPTER Adapter, - __in __nullterminated PCHAR DeviceId, - OUT PXENVBD_TARGET* _Target - ); - -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 - ); +#include "srbext.h" +#include "adapter.h" +#include "granter.h" -__checkReturn -extern BOOLEAN -TargetIsMissing( - __in PXENVBD_TARGET Target +#define TARGET_GET_PROPERTY(_name, _type) \ +extern _type \ +TargetGet ## _name ## ( \ + IN PXENVBD_TARGET Target \ ); -extern const CHAR* -TargetMissingReason( - __in PXENVBD_TARGET Target - ); +TARGET_GET_PROPERTY(DeviceId, ULONG) +TARGET_GET_PROPERTY(TargetId, ULONG) +TARGET_GET_PROPERTY(DeviceObject, PDEVICE_OBJECT) +TARGET_GET_PROPERTY(Missing, BOOLEAN) +TARGET_GET_PROPERTY(DevicePnpState, DEVICE_PNP_STATE) +TARGET_GET_PROPERTY(Adapter, PXENVBD_ADAPTER) +TARGET_GET_PROPERTY(Granter, PXENVBD_GRANTER) +TARGET_GET_PROPERTY(Path, PCHAR) +TARGET_GET_PROPERTY(BackendPath, PCHAR) +TARGET_GET_PROPERTY(BackendId, USHORT) +TARGET_GET_PROPERTY(Removable, BOOLEAN) -__checkReturn -extern BOOLEAN -TargetIsEmulatedUnplugged( - __in PXENVBD_TARGET Target - ); +#undef TARGET_GET_PROPERTY extern VOID TargetSetDevicePnpState( - __in PXENVBD_TARGET Target, - __in DEVICE_PNP_STATE State - ); - -__checkReturn -extern DEVICE_PNP_STATE -TargetGetDevicePnpState( - __in PXENVBD_TARGET Target - ); - -// Query Methods -extern ULONG -TargetGetTargetId( - __in PXENVBD_TARGET Target - ); - -extern ULONG -TargetGetDeviceId( - __in PXENVBD_TARGET Target - ); - -__checkReturn -extern PDEVICE_OBJECT -TargetGetDeviceObject( - __in PXENVBD_TARGET Target + IN PXENVBD_TARGET Target, + IN DEVICE_PNP_STATE State ); 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 + IN PXENVBD_TARGET Target, + IN PDEVICE_OBJECT DeviceObject ); -__checkReturn -extern PXENVBD_ADAPTER -TargetGetAdapter( - __in PXENVBD_TARGET Target +extern VOID +TargetSetMissing( + IN PXENVBD_TARGET Target, + IN const CHAR* Reason ); -extern ULONG -TargetSectorSize( - __in PXENVBD_TARGET Target +extern NTSTATUS +TargetCreate( + IN PXENVBD_ADAPTER Adapter, + IN PANSI_STRING Device, + OUT PXENVBD_TARGET* _Target ); -// Queue-Related extern VOID -TargetSubmitRequests( - __in PXENVBD_TARGET Target +TargetDestroy( + IN PXENVBD_TARGET Target ); -extern VOID -TargetCompleteResponse( - __in PXENVBD_TARGET Target, - __in ULONG Tag, - __in SHORT Status +extern NTSTATUS +TargetD3ToD0( + IN PXENVBD_TARGET Target ); extern VOID -TargetPreResume( - __in PXENVBD_TARGET Target +TargetD0ToD3( + IN PXENVBD_TARGET Target ); -extern VOID -TargetPostResume( - __in PXENVBD_TARGET Target +extern NTSTATUS +TargetDispatchPnp( + IN PXENVBD_TARGET Target, + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp ); -// StorPort Methods extern VOID TargetReset( IN PXENVBD_TARGET Target ); extern VOID -TargetPrepareSrb( +TargetFlush( IN PXENVBD_TARGET Target, IN PXENVBD_SRBEXT SrbExt ); extern VOID -TargetStartSrb( +TargetShutdown( IN PXENVBD_TARGET Target, IN PXENVBD_SRBEXT SrbExt ); extern VOID -TargetFlush( +TargetPrepareSrb( IN PXENVBD_TARGET Target, IN PXENVBD_SRBEXT SrbExt ); extern VOID -TargetShutdown( +TargetStartSrb( IN PXENVBD_TARGET Target, IN PXENVBD_SRBEXT SrbExt ); 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 +TargetSubmitRequests( + IN PXENVBD_TARGET Target ); -__drv_maxIRQL(DISPATCH_LEVEL) extern VOID -TargetIssueDeviceEject( - __in PXENVBD_TARGET Target, - __in __nullterminated const CHAR* Reason +TargetCompleteResponse( + IN PXENVBD_TARGET Target, + IN ULONG64 Id, + IN SHORT Status ); #endif // _XENVBD_TARGET_H diff --git a/vs2012/xenvbd/xenvbd.vcxproj b/vs2012/xenvbd/xenvbd.vcxproj index 04aff7c..993310d 100644 --- a/vs2012/xenvbd/xenvbd.vcxproj +++ b/vs2012/xenvbd/xenvbd.vcxproj @@ -76,12 +76,8 @@ <ClCompile Include="../../src/xenvbd/driver.c" /> <ClCompile Include="../../src/xenvbd/registry.c" /> <ClCompile Include="../../src/xenvbd/adapter.c" /> - <ClCompile Include="../../src/xenvbd/frontend.c" /> <ClCompile Include="../../src/xenvbd/target.c" /> - <ClCompile Include="../../src/xenvbd/pdoinquiry.c" /> - <ClCompile Include="../../src/xenvbd/queue.c" /> <ClCompile Include="../../src/xenvbd/thread.c" /> - <ClCompile Include="../../src/xenvbd/notifier.c" /> <ClCompile Include="../../src/xenvbd/blockring.c" /> <ClCompile Include="../../src/xenvbd/granter.c" /> </ItemGroup> diff --git a/vs2013/xenvbd/xenvbd.vcxproj b/vs2013/xenvbd/xenvbd.vcxproj index 4dc5bb5..19d5a40 100644 --- a/vs2013/xenvbd/xenvbd.vcxproj +++ b/vs2013/xenvbd/xenvbd.vcxproj @@ -104,12 +104,8 @@ <ClCompile Include="../../src/xenvbd/driver.c" /> <ClCompile Include="../../src/xenvbd/registry.c" /> <ClCompile Include="../../src/xenvbd/adapter.c" /> - <ClCompile Include="../../src/xenvbd/frontend.c" /> <ClCompile Include="../../src/xenvbd/target.c" /> - <ClCompile Include="../../src/xenvbd/pdoinquiry.c" /> - <ClCompile Include="../../src/xenvbd/queue.c" /> <ClCompile Include="../../src/xenvbd/thread.c" /> - <ClCompile Include="../../src/xenvbd/notifier.c" /> <ClCompile Include="../../src/xenvbd/blockring.c" /> <ClCompile Include="../../src/xenvbd/granter.c" /> </ItemGroup> diff --git a/vs2015/xenvbd/xenvbd.vcxproj b/vs2015/xenvbd/xenvbd.vcxproj index 4ae5159..f93ed7d 100644 --- a/vs2015/xenvbd/xenvbd.vcxproj +++ b/vs2015/xenvbd/xenvbd.vcxproj @@ -68,12 +68,8 @@ <ClCompile Include="../../src/xenvbd/driver.c" /> <ClCompile Include="../../src/xenvbd/registry.c" /> <ClCompile Include="../../src/xenvbd/adapter.c" /> - <ClCompile Include="../../src/xenvbd/frontend.c" /> <ClCompile Include="../../src/xenvbd/target.c" /> - <ClCompile Include="../../src/xenvbd/pdoinquiry.c" /> - <ClCompile Include="../../src/xenvbd/queue.c" /> <ClCompile Include="../../src/xenvbd/thread.c" /> - <ClCompile Include="../../src/xenvbd/notifier.c" /> <ClCompile Include="../../src/xenvbd/blockring.c" /> <ClCompile Include="../../src/xenvbd/granter.c" /> </ItemGroup> -- 2.8.3 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |