Remove the seperation between the event channel and shared ring.
Fixes the debug callback and adds more error messages.
Signed-off-by: Owen Smith <owen.smith@citrix.com>
+++ /dev/null
-/* 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 "blockring.h"
-#include "frontend.h"
-#include "target.h"
-#include "adapter.h"
-#include "util.h"
-#include "debug.h"
-#include "srbext.h"
-#include "driver.h"
-#include <stdlib.h>
-#include <xenvbd-ntstrsafe.h>
-
-#define TAG_HEADER 'gaTX'
-#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;
-};
-
-#define MAX_NAME_LEN 64
-#define BLOCKRING_POOL_TAG 'gnRX'
-
-#define XEN_IO_PROTO_ABI "x86_64-abi"
-
-static FORCEINLINE PVOID
-__BlockRingAllocate(
- IN ULONG Length
- )
-{
- return __AllocatePoolWithTag(NonPagedPool, Length, BLOCKRING_POOL_TAG);
-}
-
-static FORCEINLINE VOID
-__BlockRingFree(
- IN PVOID Buffer
- )
-{
- if (Buffer)
- __FreePoolWithTag(Buffer, BLOCKRING_POOL_TAG);
-}
-
-static FORCEINLINE VOID
-xen_mb()
-{
- KeMemoryBarrier();
- _ReadWriteBarrier();
-}
-
-static FORCEINLINE VOID
-xen_wmb()
-{
- KeMemoryBarrier();
- _WriteBarrier();
-}
-
-static FORCEINLINE PFN_NUMBER
-__Pfn(
- __in PVOID VirtAddr
- )
-{
- return (PFN_NUMBER)(ULONG_PTR)(MmGetPhysicalAddress(VirtAddr).QuadPart >> PAGE_SHIFT);
-}
-
-static FORCEINLINE ULONG64
-__BlockRingGetTag(
- IN PXENVBD_BLOCKRING BlockRing,
- IN PXENVBD_REQUEST Request
- )
-{
- UNREFERENCED_PARAMETER(BlockRing);
- return ((ULONG64)TAG_HEADER << 32) | (ULONG64)Request->Id;
-}
-
-static FORCEINLINE BOOLEAN
-__BlockRingPutTag(
- IN PXENVBD_BLOCKRING BlockRing,
- IN ULONG64 Id,
- OUT PULONG Tag
- )
-{
- ULONG Header = (ULONG)((Id >> 32) & 0xFFFFFFFF);
-
- UNREFERENCED_PARAMETER(BlockRing);
-
- *Tag = (ULONG)(Id & 0xFFFFFFFF);
- if (Header != TAG_HEADER) {
- Error("PUT_TAG (%llx) TAG_HEADER (%08x%08x)\n", Id, Header, *Tag);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static FORCEINLINE VOID
-__BlockRingInsert(
- IN PXENVBD_BLOCKRING BlockRing,
- IN PXENVBD_REQUEST Request,
- IN blkif_request_t* req
- )
-{
- PXENVBD_GRANTER Granter = FrontendGetGranter(BlockRing->Frontend);
-
- 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);
-
- 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;
-
- 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;
-
- default:
- ASSERT(FALSE);
- break;
- }
- ++BlockRing->Submitted;
-}
-
-NTSTATUS
-BlockRingCreate(
- IN PXENVBD_FRONTEND Frontend,
- IN ULONG DeviceId,
- OUT PXENVBD_BLOCKRING* BlockRing
- )
-{
- *BlockRing = __BlockRingAllocate(sizeof(XENVBD_BLOCKRING));
- if (*BlockRing == NULL)
- goto fail1;
-
- (*BlockRing)->Frontend = Frontend;
- (*BlockRing)->DeviceId = DeviceId;
- KeInitializeSpinLock(&(*BlockRing)->Lock);
-
- return STATUS_SUCCESS;
-
-fail1:
- return STATUS_NO_MEMORY;
-}
-
-VOID
-BlockRingDestroy(
- IN PXENVBD_BLOCKRING BlockRing
- )
-{
- BlockRing->Frontend = NULL;
- BlockRing->DeviceId = 0;
- RtlZeroMemory(&BlockRing->Lock, sizeof(KSPIN_LOCK));
-
- ASSERT(IsZeroMemory(BlockRing, sizeof(XENVBD_BLOCKRING)));
-
- __BlockRingFree(BlockRing);
-}
-
-NTSTATUS
-BlockRingConnect(
- IN PXENVBD_BLOCKRING BlockRing
- )
-{
- NTSTATUS status;
- PCHAR Value;
- ULONG Index, RingPages;
- PXENVBD_ADAPTER Adapter = TargetGetAdapter(FrontendGetTarget(BlockRing->Frontend));
- PXENVBD_GRANTER Granter = FrontendGetGranter(BlockRing->Frontend);
-
- ASSERT(BlockRing->Connected == FALSE);
-
- AdapterGetStoreInterface(Adapter, &BlockRing->StoreInterface);
-
- status = XENBUS_STORE(Acquire, &BlockRing->StoreInterface);
- if (!NT_SUCCESS(status))
- goto fail1;
-
- status = FrontendStoreReadBackend(BlockRing->Frontend, "max-ring-page-order", &Value);
- if (NT_SUCCESS(status)) {
- BlockRing->Order = __min(strtoul(Value, NULL, 10), XENVBD_MAX_RING_PAGE_ORDER);
- FrontendStoreFree(BlockRing->Frontend, Value);
- } else {
- BlockRing->Order = 0;
- }
-
- BlockRing->Mdl = __AllocatePages(1 << BlockRing->Order);
-
- status = STATUS_NO_MEMORY;
- if (BlockRing->Mdl == NULL)
- goto fail2;
-
- BlockRing->SharedRing = MmGetSystemAddressForMdlSafe(BlockRing->Mdl,
- NormalPagePriority);
- ASSERT(BlockRing->SharedRing != 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);
-#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]);
- if (!NT_SUCCESS(status))
- goto fail3;
- }
-
- 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;
- }
-
- RtlZeroMemory(&BlockRing->FrontRing, sizeof(BlockRing->FrontRing));
- __FreePages(BlockRing->Mdl);
- BlockRing->SharedRing = NULL;
- BlockRing->Mdl = NULL;
-
-fail2:
-fail1:
- return status;
-}
-
-NTSTATUS
-BlockRingStoreWrite(
- IN PXENVBD_BLOCKRING BlockRing,
- IN PXENBUS_STORE_TRANSACTION Transaction,
- IN PCHAR FrontendPath
- )
-{
- PXENVBD_GRANTER Granter = FrontendGetGranter(BlockRing->Frontend);
- NTSTATUS status;
-
- if (BlockRing->Order == 0) {
- status = XENBUS_STORE(Printf,
- &BlockRing->StoreInterface,
- Transaction,
- FrontendPath,
- "ring-ref",
- "%u",
- GranterReference(Granter, BlockRing->Grants[0]));
- if (!NT_SUCCESS(status))
- return status;
- } else {
- ULONG Index, RingPages;
-
- status = XENBUS_STORE(Printf,
- &BlockRing->StoreInterface,
- Transaction,
- FrontendPath,
- "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);
- if (!NT_SUCCESS(status))
- return status;
- status = XENBUS_STORE(Printf,
- &BlockRing->StoreInterface,
- Transaction,
- FrontendPath,
- Name,
- "%u",
- GranterReference(Granter, BlockRing->Grants[Index]));
- if (!NT_SUCCESS(status))
- return status;
- }
- }
-
- status = XENBUS_STORE(Printf,
- &BlockRing->StoreInterface,
- Transaction,
- FrontendPath,
- "protocol",
- XEN_IO_PROTO_ABI);
- if (!NT_SUCCESS(status))
- return status;
-
- return STATUS_SUCCESS;
-}
-
-VOID
-BlockRingEnable(
- IN PXENVBD_BLOCKRING BlockRing
- )
-{
- ASSERT(BlockRing->Enabled == FALSE);
-
- BlockRing->Enabled = TRUE;
-}
-
-VOID
-BlockRingDisable(
- IN PXENVBD_BLOCKRING BlockRing
- )
-{
- ASSERT(BlockRing->Enabled == TRUE);
-
- BlockRing->Enabled = FALSE;
-}
-
-VOID
-BlockRingDisconnect(
- IN PXENVBD_BLOCKRING BlockRing
- )
-{
- ULONG Index;
- PXENVBD_GRANTER Granter = FrontendGetGranter(BlockRing->Frontend);
-
- ASSERT(BlockRing->Connected == TRUE);
-
- BlockRing->Submitted = 0;
- BlockRing->Received = 0;
-
- for (Index = 0; Index < XENVBD_MAX_RING_PAGES; ++Index) {
- if (BlockRing->Grants[Index]) {
- GranterPut(Granter, BlockRing->Grants[Index]);
- }
- BlockRing->Grants[Index] = 0;
- }
-
- RtlZeroMemory(&BlockRing->FrontRing, sizeof(BlockRing->FrontRing));
- __FreePages(BlockRing->Mdl);
- BlockRing->SharedRing = NULL;
- BlockRing->Mdl = NULL;
-
- BlockRing->Order = 0;
-
- XENBUS_STORE(Release, &BlockRing->StoreInterface);
- RtlZeroMemory(&BlockRing->StoreInterface, sizeof(XENBUS_STORE_INTERFACE));
-
- 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;
-}
-
-BOOLEAN
-BlockRingPoll(
- IN PXENVBD_BLOCKRING BlockRing
- )
-{
- PXENVBD_TARGET Target = FrontendGetTarget(BlockRing->Frontend);
- BOOLEAN Retry = FALSE;
-
- ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
- KeAcquireSpinLockAtDpcLevel(&BlockRing->Lock);
-
- // Guard against this locked region being called after the
- // lock on FrontendSetState
- if (BlockRing->Enabled == FALSE)
- goto done;
-
- for (;;) {
- ULONG rsp_prod;
- ULONG rsp_cons;
-
- KeMemoryBarrier();
-
- rsp_prod = BlockRing->SharedRing->rsp_prod;
- rsp_cons = BlockRing->FrontRing.rsp_cons;
-
- KeMemoryBarrier();
-
- if (rsp_cons == rsp_prod || Retry)
- break;
-
- while (rsp_cons != rsp_prod && !Retry) {
- 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);
- }
-
- RtlZeroMemory(Response, sizeof(union blkif_sring_entry));
-
- if (rsp_cons - BlockRing->FrontRing.rsp_cons > RING_SIZE(&BlockRing->FrontRing) / 4)
- Retry = TRUE;
- }
-
- KeMemoryBarrier();
-
- BlockRing->FrontRing.rsp_cons = rsp_cons;
- BlockRing->SharedRing->rsp_event = rsp_cons + 1;
- }
-
-done:
- KeReleaseSpinLockFromDpcLevel(&BlockRing->Lock);
-
- return Retry;
-}
-
-BOOLEAN
-BlockRingSubmit(
- IN PXENVBD_BLOCKRING BlockRing,
- IN PXENVBD_REQUEST Request
- )
-{
- KIRQL Irql;
- blkif_request_t* req;
- BOOLEAN Notify;
-
- KeAcquireSpinLock(&BlockRing->Lock, &Irql);
- if (RING_FULL(&BlockRing->FrontRing)) {
- KeReleaseSpinLock(&BlockRing->Lock, Irql);
- return FALSE;
- }
-
- req = RING_GET_REQUEST(&BlockRing->FrontRing, BlockRing->FrontRing.req_prod_pvt);
- __BlockRingInsert(BlockRing, Request, req);
- KeMemoryBarrier();
- ++BlockRing->FrontRing.req_prod_pvt;
-
- RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&BlockRing->FrontRing, Notify);
- KeReleaseSpinLock(&BlockRing->Lock, Irql);
-
- if (Notify)
- NotifierSend(FrontendGetNotifier(BlockRing->Frontend));
-
- return TRUE;
-}
+++ /dev/null
-/* 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_BLOCKRING_H
-#define _XENVBD_BLOCKRING_H
-
-typedef struct _XENVBD_BLOCKRING XENVBD_BLOCKRING, *PXENVBD_BLOCKRING;
-
-#include "frontend.h"
-#include <debug_interface.h>
-#include <store_interface.h>
-
-extern NTSTATUS
-BlockRingCreate(
- IN PXENVBD_FRONTEND Frontend,
- IN ULONG DeviceId,
- OUT PXENVBD_BLOCKRING* BlockRing
- );
-
-extern VOID
-BlockRingDestroy(
- IN PXENVBD_BLOCKRING BlockRing
- );
-
-extern NTSTATUS
-BlockRingConnect(
- IN PXENVBD_BLOCKRING BlockRing
- );
-
-extern NTSTATUS
-BlockRingStoreWrite(
- IN PXENVBD_BLOCKRING BlockRing,
- IN PXENBUS_STORE_TRANSACTION Transaction,
- IN PCHAR FrontendPath
- );
-
-extern VOID
-BlockRingEnable(
- IN PXENVBD_BLOCKRING BlockRing
- );
-
-extern VOID
-BlockRingDisable(
- IN PXENVBD_BLOCKRING BlockRing
- );
-
-extern VOID
-BlockRingDisconnect(
- IN PXENVBD_BLOCKRING BlockRing
- );
-
-extern VOID
-BlockRingDebugCallback(
- IN PXENVBD_BLOCKRING BlockRing,
- IN PXENBUS_DEBUG_INTERFACE Debug
- );
-
-extern BOOLEAN
-BlockRingPoll(
- IN PXENVBD_BLOCKRING BlockRing
- );
-
-extern BOOLEAN
-BlockRingSubmit(
- IN PXENVBD_BLOCKRING BlockRing,
- IN PXENVBD_REQUEST Request
- );
-
-#endif // _XENVBD_BLOCKRING_H
#include "assert.h"
#include "util.h"
#include "names.h"
-#include "notifier.h"
-#include "blockring.h"
+#include "ring.h"
#include "granter.h"
#include "thread.h"
#include <store_interface.h>
PXENBUS_SUSPEND_CALLBACK SuspendLateCallback;
// Ring
- PXENVBD_NOTIFIER Notifier;
- PXENVBD_BLOCKRING BlockRing;
+ PXENVBD_RING Ring;
PXENVBD_GRANTER Granter;
// Backend State Watch
//=============================================================================
// Accessors
+ULONG
+FrontendGetDeviceId(
+ IN PXENVBD_FRONTEND Frontend
+ )
+{
+ return Frontend->DeviceId;
+}
+
+ULONG
+FrontendGetBackendDomain(
+ IN PXENVBD_FRONTEND Frontend
+ )
+{
+ return Frontend->BackendId;
+}
+
+PCHAR
+FrontendGetBackendPath(
+ IN PXENVBD_FRONTEND Frontend
+ )
+{
+ return Frontend->BackendPath;
+}
+
+PCHAR
+FrontendGetFrontendPath(
+ IN PXENVBD_FRONTEND Frontend
+ )
+{
+ return Frontend->FrontendPath;
+}
+
VOID
FrontendRemoveFeature(
IN PXENVBD_FRONTEND Frontend,
{
return Frontend->TargetId;
}
-ULONG
-FrontendGetDeviceId(
- __in PXENVBD_FRONTEND Frontend
- )
-{
- return Frontend->DeviceId;
-}
PVOID
FrontendGetInquiry(
__in PXENVBD_FRONTEND Frontend
{
return Frontend->Target;
}
-PXENVBD_BLOCKRING
-FrontendGetBlockRing(
- __in PXENVBD_FRONTEND Frontend
- )
-{
- return Frontend->BlockRing;
-}
-PXENVBD_NOTIFIER
-FrontendGetNotifier(
+PXENVBD_RING
+FrontendGetRing(
__in PXENVBD_FRONTEND Frontend
)
{
- return Frontend->Notifier;
+ return Frontend->Ring;
}
PXENVBD_GRANTER
FrontendGetGranter(
{
BOOLEAN Retry = FALSE;
- Retry |= BlockRingPoll(Frontend->BlockRing);
+ Retry |= RingPoll(Frontend->Ring);
Retry |= TargetSubmitRequests(Frontend->Target);
return Retry;
if (!NT_SUCCESS(Status))
goto fail1;
- Status = BlockRingConnect(Frontend->BlockRing);
+ Status = RingConnect(Frontend->Ring);
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;
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);
+ Status = RingStoreWrite(Frontend->Ring, Transaction);
if (!NT_SUCCESS(Status))
goto abort;
break;
}
if (!NT_SUCCESS(Status))
- goto fail4;
+ goto fail3;
// Frontend: -> INITIALIZED
Status = ___SetState(Frontend, XenbusStateInitialised);
if (!NT_SUCCESS(Status))
- goto fail5;
+ goto fail4;
// Backend : -> CONNECTED
BackendState = XenbusStateUnknown;
do {
Status = __WaitState(Frontend, &BackendState);
if (!NT_SUCCESS(Status))
- goto fail6;
+ goto fail5;
} while (BackendState == XenbusStateInitWait ||
BackendState == XenbusStateInitialising ||
BackendState == XenbusStateInitialised);
Status = STATUS_UNSUCCESSFUL;
if (BackendState != XenbusStateConnected)
- goto fail7;
+ goto fail6;
// read disk info
__ReadDiskInfo(Frontend);
// Frontend: -> CONNECTED
Status = ___SetState(Frontend, XenbusStateConnected);
if (!NT_SUCCESS(Status))
- goto fail8;
+ goto fail7;
return STATUS_SUCCESS;
-fail8:
- Error("Fail8\n");
fail7:
Error("Fail7\n");
fail6:
Error("Fail5\n");
fail4:
Error("Fail4\n");
- NotifierDisconnect(Frontend->Notifier);
fail3:
Error("Fail3\n");
- BlockRingDisconnect(Frontend->BlockRing);
+ RingDisconnect(Frontend->Ring);
fail2:
Error("Fail2\n");
GranterDisconnect(Frontend->Granter);
__in PXENVBD_FRONTEND Frontend
)
{
- NotifierDisconnect(Frontend->Notifier);
- BlockRingDisconnect(Frontend->BlockRing);
+ RingDisconnect(Frontend->Ring);
GranterDisconnect(Frontend->Granter);
}
__drv_requiresIRQL(DISPATCH_LEVEL)
KeMemoryBarrier();
GranterEnable(Frontend->Granter);
- BlockRingEnable(Frontend->BlockRing);
- NotifierEnable(Frontend->Notifier);
+ RingEnable(Frontend->Ring);
}
__drv_requiresIRQL(DISPATCH_LEVEL)
static FORCEINLINE VOID
{
Frontend->Caps.Connected = FALSE;
- NotifierDisable(Frontend->Notifier);
- BlockRingDisable(Frontend->BlockRing);
+ RingDisable(Frontend->Ring);
GranterDisable(Frontend->Granter);
}
ASSERT(FALSE);
}
- NotifierTrigger(Frontend->Notifier);
+ RingTrigger(Frontend->Ring);
Verbose("Target[%d] : <=== restored %s\n", Frontend->TargetId, __XenvbdStateName(Frontend->State));
}
if (!NT_SUCCESS(status))
goto fail3;
- status = NotifierCreate(Frontend, &Frontend->Notifier);
+ status = RingCreate(Frontend, &Frontend->Ring);
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;
+ goto fail5;
status = ThreadCreate(FrontendBackend, Frontend, &Frontend->BackendThread);
if (!NT_SUCCESS(status))
- goto fail7;
+ goto fail6;
// kernel objects
KeInitializeSpinLock(&Frontend->StateLock);
*_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;
+ GranterDestroy(Frontend->Granter);
+ Frontend->Granter = NULL;
fail5:
Error("fail5\n");
- NotifierDestroy(Frontend->Notifier);
- Frontend->Notifier = NULL;
+ RingDestroy(Frontend->Ring);
+ Frontend->Ring = NULL;
fail4:
Error("fail4\n");
fail3:
GranterDestroy(Frontend->Granter);
Frontend->Granter = NULL;
- BlockRingDestroy(Frontend->BlockRing);
- Frontend->BlockRing = NULL;
-
- NotifierDestroy(Frontend->Notifier);
- Frontend->Notifier = NULL;
+ RingDestroy(Frontend->Ring);
+ Frontend->Ring = NULL;
ASSERT3P(Frontend->BackendPath, ==, NULL);
ASSERT3P(Frontend->Inquiry, ==, NULL);
Frontend->DiskInfo.DiskInfo);
GranterDebugCallback(Frontend->Granter, Debug);
- BlockRingDebugCallback(Frontend->BlockRing, Debug);
- NotifierDebugCallback(Frontend->Notifier, Debug);
}
typedef struct _XENVBD_FRONTEND XENVBD_FRONTEND, *PXENVBD_FRONTEND;
-// Accessors
+extern ULONG
+FrontendGetDeviceId(
+ IN PXENVBD_FRONTEND Frontend
+ );
+
+extern ULONG
+FrontendGetBackendDomain(
+ IN PXENVBD_FRONTEND Frontend
+ );
+
+extern PCHAR
+FrontendGetBackendPath(
+ IN PXENVBD_FRONTEND Frontend
+ );
+
+extern PCHAR
+FrontendGetFrontendPath(
+ IN PXENVBD_FRONTEND Frontend
+ );
+
extern VOID
FrontendRemoveFeature(
IN PXENVBD_FRONTEND Frontend,
FrontendGetTargetId(
__in PXENVBD_FRONTEND Frontend
);
-extern ULONG
-FrontendGetDeviceId(
- __in PXENVBD_FRONTEND Frontend
- );
extern PVOID
FrontendGetInquiry(
__in PXENVBD_FRONTEND Frontend
FrontendGetTarget(
__in PXENVBD_FRONTEND Frontend
);
-#include "blockring.h"
-extern PXENVBD_BLOCKRING
-FrontendGetBlockRing(
- __in PXENVBD_FRONTEND Frontend
- );
-#include "notifier.h"
-extern PXENVBD_NOTIFIER
-FrontendGetNotifier(
+#include "ring.h"
+extern PXENVBD_RING
+FrontendGetRing(
__in PXENVBD_FRONTEND Frontend
);
#include "granter.h"
+++ /dev/null
-/* 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;
- KDPC TimerDpc;
- KTIMER Timer;
-};
-
-#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;
-}
-
-static FORCEINLINE BOOLEAN
-__NotifierDpcTimeout(
- IN PXENVBD_NOTIFIER Notifier
- )
-{
- KDPC_WATCHDOG_INFORMATION Watchdog;
- NTSTATUS status;
-
- UNREFERENCED_PARAMETER(Notifier);
-
- RtlZeroMemory(&Watchdog, sizeof (Watchdog));
-
- status = KeQueryDpcWatchdogInformation(&Watchdog);
- ASSERT(NT_SUCCESS(status));
-
- if (Watchdog.DpcTimeLimit == 0 ||
- Watchdog.DpcWatchdogLimit == 0)
- return FALSE;
-
- if (Watchdog.DpcTimeCount > (Watchdog.DpcTimeLimit / 2) &&
- Watchdog.DpcWatchdogCount > (Watchdog.DpcWatchdogLimit / 2))
- return FALSE;
-
- return TRUE;
-}
-
-#define TIME_US(_us) ((_us) * 10)
-#define TIME_MS(_ms) (TIME_US((_ms) * 1000))
-#define TIME_S(_s) (TIME_MS((_s) * 1000))
-#define TIME_RELATIVE(_t) (-(_t))
-
-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;
-
- for (;;) {
- if (!FrontendNotifyResponses(Notifier->Frontend)) {
- XENBUS_EVTCHN(Unmask,
- &Notifier->EvtchnInterface,
- Notifier->Channel,
- FALSE);
- break;
- }
- if (__NotifierDpcTimeout(Notifier)) {
- LARGE_INTEGER Delay;
-
- Delay.QuadPart = TIME_RELATIVE(TIME_US(100));
-
- KeSetTimer(&Notifier->Timer,
- Delay,
- &Notifier->TimerDpc);
- break;
- }
- }
-}
-
-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);
- KeInitializeDpc(&(*Notifier)->TimerDpc, NotifierDpc, *Notifier);
- KeInitializeTimer(&(*Notifier)->Timer);
-
- return STATUS_SUCCESS;
-
-fail1:
- return STATUS_NO_MEMORY;
-}
-
-VOID
-NotifierDestroy(
- IN PXENVBD_NOTIFIER Notifier
- )
-{
- Notifier->Frontend = NULL;
- RtlZeroMemory(&Notifier->Dpc, sizeof(KDPC));
- RtlZeroMemory(&Notifier->TimerDpc, sizeof(KDPC));
- RtlZeroMemory(&Notifier->Timer, sizeof(KTIMER));
-
- 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;
-
- //
- // No new timers can be scheduled once Enabled goes to FALSE.
- // Cancel any existing ones.
- //
- (VOID) KeCancelTimer(&Notifier->Timer);
-}
-
-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);
-}
-
+++ /dev/null
-/* 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
--- /dev/null
+/* 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 <stdlib.h>
+#include <ntstrsafe.h>
+
+#include <store_interface.h>
+#include <evtchn_interface.h>
+#include <debug_interface.h>
+
+#include "ring.h"
+#include "frontend.h"
+#include "target.h"
+#include "adapter.h"
+#include "srbext.h"
+#include "driver.h"
+#include "granter.h"
+
+#include "util.h"
+#include "debug.h"
+#include "assert.h"
+
+#define TAG_HEADER 'gaTX'
+#define XENVBD_MAX_RING_PAGE_ORDER (4)
+#define XENVBD_MAX_RING_PAGES (1 << XENVBD_MAX_RING_PAGE_ORDER)
+
+struct _XENVBD_RING {
+ PXENVBD_FRONTEND Frontend;
+ BOOLEAN Connected;
+ BOOLEAN Enabled;
+
+ XENBUS_STORE_INTERFACE StoreInterface;
+ XENBUS_EVTCHN_INTERFACE EvtchnInterface;
+ XENBUS_DEBUG_INTERFACE DebugInterface;
+
+ 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;
+ KDPC TimerDpc;
+ KTIMER Timer;
+
+ ULONG Submitted;
+ ULONG Received;
+ ULONG Events;
+ ULONG Dpcs;
+};
+
+#define MAX_NAME_LEN 64
+#define RING_POOL_TAG 'gnRX'
+#define XEN_IO_PROTO_ABI "x86_64-abi"
+
+static FORCEINLINE PVOID
+__RingAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool,
+ Length,
+ RING_POOL_TAG);
+}
+
+static FORCEINLINE VOID
+__RingFree(
+ IN PVOID Buffer
+ )
+{
+ if (Buffer)
+ __FreePoolWithTag(Buffer,
+ RING_POOL_TAG);
+}
+
+static FORCEINLINE VOID
+xen_mb()
+{
+ KeMemoryBarrier();
+ _ReadWriteBarrier();
+}
+
+static FORCEINLINE VOID
+xen_wmb()
+{
+ KeMemoryBarrier();
+ _WriteBarrier();
+}
+
+static FORCEINLINE PFN_NUMBER
+__Pfn(
+ __in PVOID VirtAddr
+ )
+{
+ return (PFN_NUMBER)(ULONG_PTR)(MmGetPhysicalAddress(VirtAddr).QuadPart >> PAGE_SHIFT);
+}
+
+static FORCEINLINE ULONG64
+__RingGetTag(
+ IN PXENVBD_RING Ring,
+ IN PXENVBD_REQUEST Request
+ )
+{
+ UNREFERENCED_PARAMETER(Ring);
+ return ((ULONG64)TAG_HEADER << 32) | (ULONG64)Request->Id;
+}
+
+static FORCEINLINE BOOLEAN
+__RingPutTag(
+ IN PXENVBD_RING Ring,
+ IN ULONG64 Id,
+ OUT PULONG Tag
+ )
+{
+ ULONG Header = (ULONG)((Id >> 32) & 0xFFFFFFFF);
+
+ UNREFERENCED_PARAMETER(Ring);
+
+ *Tag = (ULONG)(Id & 0xFFFFFFFF);
+ if (Header != TAG_HEADER) {
+ Error("PUT_TAG (%llx) TAG_HEADER (%08x%08x)\n", Id, Header, *Tag);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static FORCEINLINE VOID
+__RingInsert(
+ IN PXENVBD_RING Ring,
+ IN PXENVBD_REQUEST Request,
+ IN blkif_request_t* req
+ )
+{
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
+
+ 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 = __RingGetTag(Ring, Request);
+ req_indirect->sector_number = Request->FirstSector;
+ req_indirect->handle = (USHORT)FrontendGetDeviceId(Ring->Frontend);
+
+ 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);
+
+ 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)FrontendGetDeviceId(Ring->Frontend);
+ req->id = __RingGetTag(Ring, 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)FrontendGetDeviceId(Ring->Frontend);
+ req->id = __RingGetTag(Ring, Request);
+ req->sector_number = Request->FirstSector;
+ break;
+
+ 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)FrontendGetDeviceId(Ring->Frontend);
+ req_discard->id = __RingGetTag(Ring, Request);
+ req_discard->sector_number = Request->FirstSector;
+ req_discard->nr_sectors = Request->NrSectors;
+ } break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ ++Ring->Submitted;
+}
+
+KSERVICE_ROUTINE RingInterrupt;
+
+BOOLEAN
+RingInterrupt(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ )
+{
+ PXENVBD_RING Ring = Context;
+
+ UNREFERENCED_PARAMETER(Interrupt);
+
+ ASSERT(Ring != NULL);
+
+ ++Ring->Events;
+ if (!Ring->Connected)
+ return TRUE;
+
+ if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
+ ++Ring->Dpcs;
+
+ return TRUE;
+}
+
+static FORCEINLINE BOOLEAN
+__RingDpcTimeout(
+ IN PXENVBD_RING Ring
+ )
+{
+ KDPC_WATCHDOG_INFORMATION Watchdog;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Ring);
+
+ RtlZeroMemory(&Watchdog, sizeof (Watchdog));
+
+ status = KeQueryDpcWatchdogInformation(&Watchdog);
+ ASSERT(NT_SUCCESS(status));
+
+ if (Watchdog.DpcTimeLimit == 0 ||
+ Watchdog.DpcWatchdogLimit == 0)
+ return FALSE;
+
+ if (Watchdog.DpcTimeCount > (Watchdog.DpcTimeLimit / 2) &&
+ Watchdog.DpcWatchdogCount > (Watchdog.DpcWatchdogLimit / 2))
+ return FALSE;
+
+ return TRUE;
+}
+
+#define TIME_US(_us) ((_us) * 10)
+#define TIME_MS(_ms) (TIME_US((_ms) * 1000))
+#define TIME_S(_s) (TIME_MS((_s) * 1000))
+#define TIME_RELATIVE(_t) (-(_t))
+
+KDEFERRED_ROUTINE RingDpc;
+
+VOID
+RingDpc(
+ __in PKDPC Dpc,
+ __in_opt PVOID Context,
+ __in_opt PVOID Arg1,
+ __in_opt PVOID Arg2
+ )
+{
+ PXENVBD_RING Ring = Context;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(Arg1);
+ UNREFERENCED_PARAMETER(Arg2);
+
+ ASSERT(Ring != NULL);
+
+ if (!Ring->Connected)
+ return;
+
+ for (;;) {
+ if (!FrontendNotifyResponses(Ring->Frontend)) {
+ XENBUS_EVTCHN(Unmask,
+ &Ring->EvtchnInterface,
+ Ring->Channel,
+ FALSE);
+ break;
+ }
+ if (__RingDpcTimeout(Ring)) {
+ LARGE_INTEGER Delay;
+
+ Delay.QuadPart = TIME_RELATIVE(TIME_US(100));
+
+ KeSetTimer(&Ring->Timer,
+ Delay,
+ &Ring->TimerDpc);
+ break;
+ }
+ }
+}
+
+static DECLSPEC_NOINLINE VOID
+RingDebugCallback(
+ IN PVOID Argument,
+ IN BOOLEAN Crashing
+ )
+{
+ PXENVBD_RING Ring = Argument;
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
+ ULONG Index;
+
+ UNREFERENCED_PARAMETER(Crashing);
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "Submitted: %u Received: %u\n",
+ Ring->Submitted,
+ Ring->Received);
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "Events: %u Dpcs: %u\n",
+ Ring->Events,
+ Ring->Dpcs);
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "Shared : 0x%p\n",
+ Ring->Shared);
+
+ if (Ring->Shared) {
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "Shared: %d / %d - %d / %d\n",
+ Ring->Shared->req_prod,
+ Ring->Shared->req_event,
+ Ring->Shared->rsp_prod,
+ Ring->Shared->rsp_event);
+ }
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "Front: %d / %d (%d)\n",
+ Ring->Front.req_prod_pvt,
+ Ring->Front.rsp_cons,
+ Ring->Front.nr_ents);
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "Order: %d\n",
+ Ring->Order);
+
+ for (Index = 0; Index < (1ul << Ring->Order); ++Index) {
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "Grants[%-2d]: 0x%p (%u)\n",
+ Index,
+ Ring->Grants[Index],
+ GranterReference(Granter, Ring->Grants[Index]));
+ }
+
+ if (Ring->Channel) {
+ ULONG Port = XENBUS_EVTCHN(GetPort,
+ &Ring->EvtchnInterface,
+ Ring->Channel);
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "Channel : %p (%d)\n",
+ Ring->Channel,
+ Port);
+ }
+}
+
+NTSTATUS
+RingCreate(
+ IN PXENVBD_FRONTEND Frontend,
+ OUT PXENVBD_RING* Ring
+ )
+{
+ NTSTATUS status;
+
+ *Ring = __RingAllocate(sizeof(XENVBD_RING));
+
+ status = STATUS_NO_MEMORY;
+ if (*Ring == NULL)
+ goto fail1;
+
+ (*Ring)->Frontend = Frontend;
+ KeInitializeSpinLock(&(*Ring)->Lock);
+ KeInitializeDpc(&(*Ring)->Dpc, RingDpc, *Ring);
+ KeInitializeDpc(&(*Ring)->TimerDpc, RingDpc, *Ring);
+ KeInitializeTimer(&(*Ring)->Timer);
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 %08x\n", status);
+ return status;
+}
+
+VOID
+RingDestroy(
+ IN PXENVBD_RING Ring
+ )
+{
+ RtlZeroMemory(&Ring->Timer, sizeof(KTIMER));
+ RtlZeroMemory(&Ring->TimerDpc, sizeof(KDPC));
+ RtlZeroMemory(&Ring->Dpc, sizeof(KDPC));
+ RtlZeroMemory(&Ring->Lock, sizeof(KSPIN_LOCK));
+ Ring->Frontend = NULL;
+
+ ASSERT(IsZeroMemory(Ring, sizeof(XENVBD_RING)));
+ __RingFree(Ring);
+}
+
+NTSTATUS
+RingConnect(
+ IN PXENVBD_RING Ring
+ )
+{
+ PXENVBD_TARGET Target = FrontendGetTarget(Ring->Frontend);
+ PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target);
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
+ PCHAR Buffer;
+ ULONG Index;
+ NTSTATUS status;
+
+ ASSERT(Ring->Connected == FALSE);
+
+ AdapterGetStoreInterface(Adapter, &Ring->StoreInterface);
+ AdapterGetEvtchnInterface(Adapter, &Ring->EvtchnInterface);
+ AdapterGetDebugInterface(Adapter, &Ring->DebugInterface);
+
+ status = XENBUS_STORE(Acquire, &Ring->StoreInterface);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = XENBUS_EVTCHN(Acquire, &Ring->EvtchnInterface);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = XENBUS_DEBUG(Acquire, &Ring->DebugInterface);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = XENBUS_STORE(Read,
+ &Ring->StoreInterface,
+ NULL,
+ FrontendGetBackendPath(Ring->Frontend),
+ "max-ring-page-order",
+ &Buffer);
+ if (NT_SUCCESS(status)) {
+ Ring->Order = strtoul(Buffer, NULL, 10);
+ if (Ring->Order > XENVBD_MAX_RING_PAGE_ORDER)
+ Ring->Order = XENVBD_MAX_RING_PAGE_ORDER;
+
+ XENBUS_STORE(Free,
+ &Ring->StoreInterface,
+ Buffer);
+ } else {
+ Ring->Order = 0;
+ }
+
+ Ring->Mdl = __AllocatePages(1 << Ring->Order);
+
+ status = STATUS_NO_MEMORY;
+ if (Ring->Mdl == NULL)
+ goto fail4;
+
+ Ring->Shared = MmGetSystemAddressForMdlSafe(Ring->Mdl,
+ NormalPagePriority);
+ ASSERT(Ring->Shared != NULL);
+
+#pragma warning(push)
+#pragma warning(disable: 4305)
+#pragma warning(disable: 4311) // 'type cast' pointer truncation from 'blkif_sring_entry[1]' to 'long'
+ SHARED_RING_INIT(Ring->Shared);
+ FRONT_RING_INIT(&Ring->Front, Ring->Shared, PAGE_SIZE << Ring->Order);
+#pragma warning(pop)
+
+ for (Index = 0; Index < (1ul << Ring->Order); ++Index) {
+ status = GranterGet(Granter,
+ MmGetMdlPfnArray(Ring->Mdl)[Index],
+ FALSE,
+ &Ring->Grants[Index]);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+ }
+
+ Ring->Channel = XENBUS_EVTCHN(Open,
+ &Ring->EvtchnInterface,
+ XENBUS_EVTCHN_TYPE_UNBOUND,
+ RingInterrupt,
+ Ring,
+ FrontendGetBackendDomain(Ring->Frontend),
+ TRUE);
+ status = STATUS_NO_MEMORY;
+ if (Ring->Channel == NULL)
+ goto fail6;
+
+ XENBUS_EVTCHN(Unmask,
+ &Ring->EvtchnInterface,
+ Ring->Channel,
+ FALSE);
+
+ status = XENBUS_DEBUG(Register,
+ &Ring->DebugInterface,
+ __MODULE__"|RING",
+ RingDebugCallback,
+ Ring,
+ &Ring->DebugCallback);
+ if (!NT_SUCCESS(status))
+ goto fail7;
+
+ Ring->Connected = TRUE;
+ return STATUS_SUCCESS;
+
+fail7:
+ Error("fail7\n");
+ XENBUS_EVTCHN(Close,
+ &Ring->EvtchnInterface,
+ Ring->Channel);
+ Ring->Channel = NULL;
+fail6:
+ Error("fail6\n");
+fail5:
+ Error("fail5\n");
+ for (Index = 0; Index < (1ul << Ring->Order); ++Index) {
+ if (Ring->Grants[Index] == NULL)
+ continue;
+
+ GranterPut(Granter, Ring->Grants[Index]);
+ Ring->Grants[Index] = NULL;
+ }
+
+ RtlZeroMemory(&Ring->Front, sizeof(blkif_front_ring_t));
+
+ __FreePages(Ring->Mdl);
+ Ring->Shared = NULL;
+ Ring->Mdl = NULL;
+
+ Ring->Order = 0;
+fail4:
+ Error("fail4\n");
+ XENBUS_DEBUG(Release, &Ring->DebugInterface);
+fail3:
+ Error("fail3\n");
+ XENBUS_EVTCHN(Release, &Ring->EvtchnInterface);
+fail2:
+ Error("fail2\n");
+ XENBUS_STORE(Release, &Ring->StoreInterface);
+fail1:
+ Error("fail1 %08x\n", status);
+
+ RtlZeroMemory(&Ring->DebugInterface,
+ sizeof(XENBUS_DEBUG_INTERFACE));
+ RtlZeroMemory(&Ring->EvtchnInterface,
+ sizeof(XENBUS_EVTCHN_INTERFACE));
+ RtlZeroMemory(&Ring->StoreInterface,
+ sizeof(XENBUS_STORE_INTERFACE));
+
+ return status;
+}
+
+NTSTATUS
+RingStoreWrite(
+ IN PXENVBD_RING Ring,
+ IN PVOID Transaction
+ )
+{
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
+ ULONG Port;
+ NTSTATUS status;
+
+ if (Ring->Order == 0) {
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ FrontendGetFrontendPath(Ring->Frontend),
+ "ring-ref",
+ "%u",
+ GranterReference(Granter, Ring->Grants[0]));
+ if (!NT_SUCCESS(status))
+ return status;
+ } else {
+ ULONG Index;
+
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ FrontendGetFrontendPath(Ring->Frontend),
+ "ring-page-order",
+ "%u",
+ Ring->Order);
+ if (!NT_SUCCESS(status))
+ return status;
+
+ for (Index = 0; Index < (1ul << Ring->Order); ++Index) {
+ CHAR Name[MAX_NAME_LEN+1];
+
+ status = RtlStringCchPrintfA(Name,
+ MAX_NAME_LEN,
+ "ring-ref%u",
+ Index);
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ FrontendGetFrontendPath(Ring->Frontend),
+ Name,
+ "%u",
+ GranterReference(Granter, Ring->Grants[Index]));
+ if (!NT_SUCCESS(status))
+ return status;
+ }
+ }
+
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ FrontendGetFrontendPath(Ring->Frontend),
+ "protocol",
+ XEN_IO_PROTO_ABI);
+ if (!NT_SUCCESS(status))
+ return status;
+
+ Port = XENBUS_EVTCHN(GetPort,
+ &Ring->EvtchnInterface,
+ Ring->Channel);
+
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ FrontendGetFrontendPath(Ring->Frontend),
+ "event-channel",
+ "%u",
+ Port);
+ if (!NT_SUCCESS(status))
+ return status;
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+RingEnable(
+ IN PXENVBD_RING Ring
+ )
+{
+ ASSERT(Ring->Enabled == FALSE);
+ Ring->Enabled = TRUE;
+
+ XENBUS_EVTCHN(Trigger,
+ &Ring->EvtchnInterface,
+ Ring->Channel);
+}
+
+VOID
+RingDisable(
+ IN PXENVBD_RING Ring
+ )
+{
+ ASSERT(Ring->Enabled == TRUE);
+ Ring->Enabled = FALSE;
+
+ //
+ // No new timers can be scheduled once Enabled goes to FALSE.
+ // Cancel any existing ones.
+ //
+ (VOID) KeCancelTimer(&Ring->Timer);
+}
+
+VOID
+RingDisconnect(
+ IN PXENVBD_RING Ring
+ )
+{
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
+ ULONG Index;
+
+ ASSERT3U(Ring->Submitted, ==, Ring->Received);
+ ASSERT(Ring->Connected);
+ Ring->Connected = FALSE;
+
+ XENBUS_DEBUG(Deregister,
+ &Ring->DebugInterface,
+ Ring->DebugCallback);
+ Ring->DebugCallback = NULL;
+
+ XENBUS_EVTCHN(Close,
+ &Ring->EvtchnInterface,
+ Ring->Channel);
+ Ring->Channel = NULL;
+
+ for (Index = 0; Index < (1ul << Ring->Order); ++Index) {
+ if (Ring->Grants[Index] == NULL)
+ continue;
+
+ GranterPut(Granter, Ring->Grants[Index]);
+ Ring->Grants[Index] = NULL;
+ }
+
+ RtlZeroMemory(&Ring->Front, sizeof(blkif_front_ring_t));
+
+ __FreePages(Ring->Mdl);
+ Ring->Shared = NULL;
+ Ring->Mdl = NULL;
+
+ Ring->Order = 0;
+
+ XENBUS_DEBUG(Release, &Ring->DebugInterface);
+ XENBUS_EVTCHN(Release, &Ring->EvtchnInterface);
+ XENBUS_STORE(Release, &Ring->StoreInterface);
+
+ RtlZeroMemory(&Ring->DebugInterface,
+ sizeof(XENBUS_DEBUG_INTERFACE));
+ RtlZeroMemory(&Ring->EvtchnInterface,
+ sizeof(XENBUS_EVTCHN_INTERFACE));
+ RtlZeroMemory(&Ring->StoreInterface,
+ sizeof(XENBUS_STORE_INTERFACE));
+
+ Ring->Events = 0;
+ Ring->Dpcs = 0;
+ Ring->Submitted = 0;
+ Ring->Received = 0;
+}
+
+BOOLEAN
+RingPoll(
+ IN PXENVBD_RING Ring
+ )
+{
+ PXENVBD_TARGET Target = FrontendGetTarget(Ring->Frontend);
+ BOOLEAN Retry = FALSE;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+ KeAcquireSpinLockAtDpcLevel(&Ring->Lock);
+
+ // Guard against this locked region being called after the
+ // lock on FrontendSetState
+ if (Ring->Enabled == FALSE)
+ goto done;
+
+ for (;;) {
+ ULONG rsp_prod;
+ ULONG rsp_cons;
+
+ KeMemoryBarrier();
+
+ rsp_prod = Ring->Shared->rsp_prod;
+ rsp_cons = Ring->Front.rsp_cons;
+
+ KeMemoryBarrier();
+
+ if (rsp_cons == rsp_prod || Retry)
+ break;
+
+ while (rsp_cons != rsp_prod && !Retry) {
+ blkif_response_t* Response;
+ ULONG Tag;
+
+ Response = RING_GET_RESPONSE(&Ring->Front, rsp_cons);
+ ++rsp_cons;
+
+ if (__RingPutTag(Ring, Response->id, &Tag)) {
+ ++Ring->Received;
+ TargetCompleteResponse(Target, Tag, Response->status);
+ }
+
+ RtlZeroMemory(Response, sizeof(union blkif_sring_entry));
+
+ if (rsp_cons - Ring->Front.rsp_cons > RING_SIZE(&Ring->Front) / 4)
+ Retry = TRUE;
+ }
+
+ KeMemoryBarrier();
+
+ Ring->Front.rsp_cons = rsp_cons;
+ Ring->Shared->rsp_event = rsp_cons + 1;
+ }
+
+done:
+ KeReleaseSpinLockFromDpcLevel(&Ring->Lock);
+
+ return Retry;
+}
+
+BOOLEAN
+RingSubmit(
+ IN PXENVBD_RING Ring,
+ IN PXENVBD_REQUEST Request
+ )
+{
+ KIRQL Irql;
+ blkif_request_t* req;
+ BOOLEAN Notify;
+
+ KeAcquireSpinLock(&Ring->Lock, &Irql);
+ if (RING_FULL(&Ring->Front)) {
+ KeReleaseSpinLock(&Ring->Lock, Irql);
+ return FALSE;
+ }
+
+ req = RING_GET_REQUEST(&Ring->Front, Ring->Front.req_prod_pvt);
+ __RingInsert(Ring, Request, req);
+ KeMemoryBarrier();
+ ++Ring->Front.req_prod_pvt;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&Ring->Front, Notify);
+ KeReleaseSpinLock(&Ring->Lock, Irql);
+
+ if (Notify)
+ RingSend(Ring);
+
+ return TRUE;
+}
+
+VOID
+RingKick(
+ IN PXENVBD_RING Ring
+ )
+{
+ if (!Ring->Enabled)
+ return;
+
+ if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
+ ++Ring->Dpcs;
+}
+
+VOID
+RingTrigger(
+ IN PXENVBD_RING Ring
+ )
+{
+ if (!Ring->Enabled)
+ return;
+
+ XENBUS_EVTCHN(Trigger,
+ &Ring->EvtchnInterface,
+ Ring->Channel);
+}
+
+VOID
+RingSend(
+ IN PXENVBD_RING Ring
+ )
+{
+ if (!Ring->Enabled)
+ return;
+
+ XENBUS_EVTCHN(Send,
+ &Ring->EvtchnInterface,
+ Ring->Channel);
+}
--- /dev/null
+/* 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_RING_H
+#define _XENVBD_RING_H
+
+typedef struct _XENVBD_RING XENVBD_RING, *PXENVBD_RING;
+
+#include "frontend.h"
+#include "srbext.h"
+
+extern NTSTATUS
+RingCreate(
+ IN PXENVBD_FRONTEND Frontend,
+ OUT PXENVBD_RING* Ring
+ );
+
+extern VOID
+RingDestroy(
+ IN PXENVBD_RING Ring
+ );
+
+extern NTSTATUS
+RingConnect(
+ IN PXENVBD_RING Ring
+ );
+
+extern NTSTATUS
+RingStoreWrite(
+ IN PXENVBD_RING Ring,
+ IN PVOID Transaction
+ );
+
+extern VOID
+RingEnable(
+ IN PXENVBD_RING Ring
+ );
+
+extern VOID
+RingDisable(
+ IN PXENVBD_RING Ring
+ );
+
+extern VOID
+RingDisconnect(
+ IN PXENVBD_RING Ring
+ );
+
+extern BOOLEAN
+RingPoll(
+ IN PXENVBD_RING Ring
+ );
+
+extern BOOLEAN
+RingSubmit(
+ IN PXENVBD_RING Ring,
+ IN PXENVBD_REQUEST Request
+ );
+
+extern VOID
+RingKick(
+ IN PXENVBD_RING Ring
+ );
+
+extern VOID
+RingTrigger(
+ IN PXENVBD_RING Ring
+ );
+
+extern VOID
+RingSend(
+ IN PXENVBD_RING Ring
+ );
+
+#endif // _XENVBD_RING_H
KIRQL Irql;
ULONG Requests;
ULONG Count = 0;
- PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend);
- PXENVBD_BLOCKRING BlockRing = FrontendGetBlockRing(Target->Frontend);
+ PXENVBD_RING Ring = FrontendGetRing(Target->Frontend);
KeAcquireSpinLock(&Target->Lock, &Irql);
++Target->Paused;
if (Timeout && Count > 180000)
break;
KeRaiseIrql(DISPATCH_LEVEL, &Irql);
- BlockRingPoll(BlockRing);
+ RingPoll(Ring);
KeLowerIrql(Irql);
- NotifierSend(Notifier); // let backend know it needs to do some work
+ RingSend(Ring); // let backend know it needs to do some work
StorPortStallExecution(1000); // 1000 micro-seconds
++Count;
}
__in PXENVBD_TARGET Target
)
{
- PXENVBD_BLOCKRING BlockRing = FrontendGetBlockRing(Target->Frontend);
+ PXENVBD_RING Ring = FrontendGetRing(Target->Frontend);
if (TargetIsPaused(Target)) {
if (QueueCount(&Target->PreparedReqs))
Warning("Target[%d] : Paused, not submitting new requests (%u)\n",
QueueAppend(&Target->SubmittedReqs, &Request->Entry);
KeMemoryBarrier();
- if (BlockRingSubmit(BlockRing, Request))
+ if (RingSubmit(Ring, Request))
continue;
QueueRemove(&Target->SubmittedReqs, &Request->Entry);
{
PXENVBD_DISKINFO DiskInfo = FrontendGetDiskInfo(Target->Frontend);
PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb);
- PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend);
+ PXENVBD_RING Ring = FrontendGetRing(Target->Frontend);
if (FrontendGetCaps(Target->Frontend)->Connected == FALSE) {
Trace("Target[%d] : Not Ready, fail SRB\n", TargetGetTargetId(Target));
}
QueueAppend(&Target->FreshSrbs, &SrbExt->Entry);
- NotifierKick(Notifier);
+ RingKick(Ring);
return FALSE;
}
)
{
PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb);
- PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend);
+ PXENVBD_RING Ring = FrontendGetRing(Target->Frontend);
if (FrontendGetCaps(Target->Frontend)->Connected == FALSE) {
Trace("Target[%d] : Not Ready, fail SRB\n", TargetGetTargetId(Target));
}
QueueAppend(&Target->FreshSrbs, &SrbExt->Entry);
- NotifierKick(Notifier);
+ RingKick(Ring);
return FALSE;
}
)
{
PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb);
- PXENVBD_NOTIFIER Notifier = FrontendGetNotifier(Target->Frontend);
+ PXENVBD_RING Ring = FrontendGetRing(Target->Frontend);
if (FrontendGetCaps(Target->Frontend)->Connected == FALSE) {
Trace("Target[%d] : Not Ready, fail SRB\n", TargetGetTargetId(Target));
}
QueueAppend(&Target->FreshSrbs, &SrbExt->Entry);
- NotifierKick(Notifier);
+ RingKick(Ring);
return FALSE;
}
)
{
QueueAppend(&Target->ShutdownSrbs, &SrbExt->Entry);
- NotifierKick(FrontendGetNotifier(Target->Frontend));
+ RingKick(FrontendGetRing(Target->Frontend));
}
VOID
)
{
QueueAppend(&Target->ShutdownSrbs, &SrbExt->Entry);
- NotifierKick(FrontendGetNotifier(Target->Frontend));
+ RingKick(FrontendGetRing(Target->Frontend));
}
VOID
<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/ring.c" />
<ClCompile Include="../../src/xenvbd/granter.c" />
</ItemGroup>
<ItemGroup>