#include "srbext.h"
#include "driver.h"
#include "granter.h"
-#include "queue.h"
#include "util.h"
#include "debug.h"
#define XENVBD_MAX_RING_PAGE_ORDER (4)
#define XENVBD_MAX_RING_PAGES (1 << XENVBD_MAX_RING_PAGE_ORDER)
-struct _XENVBD_RING {
- PXENVBD_FRONTEND Frontend;
+#define xen_mb KeMemoryBarrier
+#define xen_wmb KeMemoryBarrier
+
+typedef struct _XENVBD_SRB_STATE {
+ LIST_ENTRY List;
+ ULONG Count;
+} XENVBD_SRB_STATE, *PXENVBD_SRB_STATE;
+
+typedef struct _XENVBD_BLKIF_RING {
+ PXENVBD_RING Ring;
+ ULONG Index;
+ PCHAR Path;
+ PXENBUS_CACHE RequestCache;
+ PXENBUS_CACHE SegmentCache;
+ PXENBUS_CACHE IndirectCache;
+ PMDL Mdl;
+ blkif_sring_t *Shared;
+ blkif_front_ring_t Front;
+ PXENBUS_GNTTAB_ENTRY Grants[XENVBD_MAX_RING_PAGES];
+ PXENBUS_EVTCHN_CHANNEL Channel;
+ KDPC Dpc;
+ ULONG Dpcs;
+ ULONG Events;
BOOLEAN Connected;
BOOLEAN Enabled;
+ BOOLEAN Stopped;
+ PVOID Lock;
+ PKTHREAD LockThread;
+ XENVBD_SRB_STATE State;
+ LIST_ENTRY SrbQueue;
+ LIST_ENTRY SubmittedList;
+ LIST_ENTRY ShutdownQueue;
+ ULONG SrbsQueued;
+ ULONG SrbsCompleted;
+ ULONG SrbsFailed;
+ ULONG RequestsPosted;
+ ULONG RequestsPushed;
+ ULONG ResponsesProcessed;
+ PXENBUS_DEBUG_CALLBACK DebugCallback;
+} XENVBD_BLKIF_RING, *PXENVBD_BLKIF_RING;
+
+typedef enum _XENVBD_STAT {
+ XENVBD_STAT_BLKIF_OP_READ_DIRECT = 0,
+ XENVBD_STAT_BLKIF_OP_READ_INDIRECT,
+ XENVBD_STAT_BLKIF_OP_WRITE_DIRECT,
+ XENVBD_STAT_BLKIF_OP_WRITE_INDIRECT,
+ XENVBD_STAT_BLKIF_OP_WRITE_BARRIER,
+ XENVBD_STAT_BLKIF_OP_FLUSH_DISKCACHE,
+ XENVBD_STAT_BLKIF_OP_DISCARD,
+ XENVBD_STAT_BLKIF_OP_UNKNOWN,
+ XENVBD_STAT_SEGMENTS_GRANTED,
+ XENVBD_STAT_SEGMENTS_BOUNCED,
+
+ XENVBD_STAT__MAX
+} XENVBD_STAT, *PXENVBD_STAT;
+struct _XENVBD_RING {
+ PXENVBD_FRONTEND Frontend;
+ XENBUS_DEBUG_INTERFACE DebugInterface;
XENBUS_CACHE_INTERFACE CacheInterface;
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;
-
- PXENBUS_CACHE RequestCache;
- PXENBUS_CACHE SegmentCache;
- PXENBUS_CACHE IndirectCache;
- XENVBD_QUEUE PreparedReqs;
- XENVBD_QUEUE SubmittedReqs;
- XENVBD_QUEUE ShutdownSrbs;
-
- ULONG Submitted;
- ULONG Received;
- ULONG Events;
- ULONG Dpcs;
- ULONG BlkOpRead;
- ULONG BlkOpWrite;
- ULONG BlkOpIndirectRead;
- ULONG BlkOpIndirectWrite;
- ULONG BlkOpBarrier;
- ULONG BlkOpDiscard;
- ULONG BlkOpFlush;
- ULONG64 SegsGranted;
- ULONG64 SegsBounced;
+ PXENVBD_BLKIF_RING *Ring;
+ LONG Stats[XENVBD_STAT__MAX];
};
#define MAX_NAME_LEN 64
RING_POOL_TAG);
}
-static FORCEINLINE VOID
-xen_mb()
+static FORCEINLINE PCHAR
+__BlkifOperationName(
+ IN UCHAR Operation
+ )
{
- KeMemoryBarrier();
- _ReadWriteBarrier();
+ 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>";
+ }
}
-static FORCEINLINE VOID
-xen_wmb()
+static FORCEINLINE PCHAR
+__StatName(
+ IN XENVBD_STAT Operation
+ )
{
- KeMemoryBarrier();
- _WriteBarrier();
+ switch (Operation) {
+ case XENVBD_STAT_BLKIF_OP_READ_DIRECT: return "BLKIF_OP_READ (direct)";
+ case XENVBD_STAT_BLKIF_OP_READ_INDIRECT: return "BLKIF_OP_READ (indirect)";
+ case XENVBD_STAT_BLKIF_OP_WRITE_DIRECT: return "BLKIF_OP_WRITE (direct)";
+ case XENVBD_STAT_BLKIF_OP_WRITE_INDIRECT: return "BLKIF_OP_WRITE (indirect)";
+ case XENVBD_STAT_BLKIF_OP_WRITE_BARRIER: return "BLKIF_OP_WRITE_BARRIER";
+ case XENVBD_STAT_BLKIF_OP_FLUSH_DISKCACHE: return "BLKIF_OP_FLUSH_DISKCACHE";
+ case XENVBD_STAT_BLKIF_OP_DISCARD: return "BLKIF_OP_DISCARD";
+ case XENVBD_STAT_SEGMENTS_GRANTED: return "SegmentsGranted";
+ case XENVBD_STAT_SEGMENTS_BOUNCED: return "SegmentsBounced";
+ default: return "UNKNOWN";
+ }
}
-static FORCEINLINE VOID
-__RingInsert(
- IN PXENVBD_RING Ring,
- IN PXENVBD_REQUEST Request,
- IN blkif_request_t* req
+static FORCEINLINE ULONG
+__SectorsPerPage(
+ IN ULONG SectorSize
)
{
- 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 = (ULONG64)(ULONG_PTR)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, ListEntry);
-
- 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, ListEntry);
-
- 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 = (ULONG64)(ULONG_PTR)Request;
- req->sector_number = Request->FirstSector;
+ ASSERT3U(SectorSize, != , 0);
+ return PAGE_SIZE / SectorSize;
+}
- 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, ListEntry);
- req->seg[Index].gref = GranterReference(Granter, Segment->Grant);
- req->seg[Index].first_sect = Segment->FirstSector;
- req->seg[Index].last_sect = Segment->LastSector;
- }
- }
+static FORCEINLINE VOID
+__Operation(
+ IN UCHAR CdbOp,
+ OUT PUCHAR RingOp,
+ OUT PBOOLEAN ReadOnly
+ )
+{
+ switch (CdbOp) {
+ case SCSIOP_READ:
+ *RingOp = BLKIF_OP_READ;
+ *ReadOnly = FALSE;
break;
-
- case 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 = (ULONG64)(ULONG_PTR)Request;
- req->sector_number = Request->FirstSector;
+ case SCSIOP_WRITE:
+ *RingOp = BLKIF_OP_WRITE;
+ *ReadOnly = TRUE;
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 = (ULONG64)(ULONG_PTR)Request;
- req_discard->sector_number = Request->FirstSector;
- req_discard->nr_sectors = Request->NrSectors;
- } break;
-
default:
ASSERT(FALSE);
- break;
}
- ++Ring->Submitted;
+}
+
+static FORCEINLINE ULONG
+__UseIndirect(
+ IN ULONG SectorsPerPage,
+ IN ULONG MaxIndirectSegs,
+ IN ULONG SectorsLeft
+ )
+{
+ if (MaxIndirectSegs <= BLKIF_MAX_SEGMENTS_PER_REQUEST)
+ return BLKIF_MAX_SEGMENTS_PER_REQUEST; // not supported
+
+ if (SectorsLeft < BLKIF_MAX_SEGMENTS_PER_REQUEST * SectorsPerPage)
+ return BLKIF_MAX_SEGMENTS_PER_REQUEST; // first into a single BLKIF_OP_{READ/WRITE}
+
+ return MaxIndirectSegs;
+}
+
+static FORCEINLINE MM_PAGE_PRIORITY
+__Priority(
+ IN PXENVBD_CAPS Caps
+ )
+{
+ return (Caps->Paging ||
+ Caps->Hibernation ||
+ Caps->DumpFile) ? HighPagePriority :
+ NormalPagePriority;
}
static PXENVBD_INDIRECT
-RingGetIndirect(
- IN PXENVBD_RING Ring
+BlkifRingGetIndirect(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- PXENVBD_INDIRECT Indirect;
- NTSTATUS status;
- PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_FRONTEND Frontend = Ring->Frontend;
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Frontend);
+ PXENVBD_INDIRECT Indirect;
+ NTSTATUS status;
Indirect = XENBUS_CACHE(Get,
&Ring->CacheInterface,
- Ring->IndirectCache,
- FALSE);
+ BlkifRing->IndirectCache,
+ TRUE);
if (Indirect == NULL)
goto fail1;
- ASSERT3P(Indirect->Mdl, !=, NULL);
- ASSERT3P(Indirect->Page, !=, NULL);
+ ASSERT3P(Indirect->Mdl, != , NULL);
+ ASSERT3P(Indirect->Page, != , NULL);
status = GranterGet(Granter,
MmGetMdlPfnArray(Indirect->Mdl)[0],
TRUE,
fail2:
XENBUS_CACHE(Put,
&Ring->CacheInterface,
- Ring->IndirectCache,
+ BlkifRing->IndirectCache,
Indirect,
- FALSE);
+ TRUE);
fail1:
return NULL;
}
static VOID
-RingPutIndirect(
- IN PXENVBD_RING Ring,
+BlkifRingPutIndirect(
+ IN PXENVBD_BLKIF_RING BlkifRing,
IN PXENVBD_INDIRECT Indirect
)
{
- PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_FRONTEND Frontend = Ring->Frontend;
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Frontend);
if (Indirect->Grant)
GranterPut(Granter, Indirect->Grant);
XENBUS_CACHE(Put,
&Ring->CacheInterface,
- Ring->IndirectCache,
+ BlkifRing->IndirectCache,
Indirect,
- FALSE);
+ TRUE);
}
static PXENVBD_SEGMENT
-RingGetSegment(
- IN PXENVBD_RING Ring
+BlkifRingGetSegment(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
+ PXENVBD_RING Ring = BlkifRing->Ring;
+
return XENBUS_CACHE(Get,
&Ring->CacheInterface,
- Ring->SegmentCache,
- FALSE);
+ BlkifRing->SegmentCache,
+ TRUE);
}
static VOID
-RingPutSegment(
- IN PXENVBD_RING Ring,
- IN PXENVBD_SEGMENT Segment
+BlkifRingPutSegment(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PXENVBD_SEGMENT Segment
)
{
- PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
- PXENVBD_BOUNCE Bounce = Segment->Bounce;
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_FRONTEND Frontend = Ring->Frontend;
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Frontend);
+ PXENVBD_BOUNCE Bounce = Segment->Bounce;
if (Segment->Grant)
GranterPut(Granter, Segment->Grant);
Bounce->SourcePfn[0] = 0;
Bounce->SourcePfn[1] = 0;
- AdapterPutBounce(TargetGetAdapter(FrontendGetTarget(Ring->Frontend)),
+ AdapterPutBounce(TargetGetAdapter(FrontendGetTarget(Frontend)),
Bounce);
}
Segment->Bounce = NULL;
XENBUS_CACHE(Put,
&Ring->CacheInterface,
- Ring->SegmentCache,
+ BlkifRing->SegmentCache,
Segment,
- FALSE);
+ TRUE);
}
static PXENVBD_REQUEST
-RingGetRequest(
- IN PXENVBD_RING Ring
+BlkifRingGetRequest(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
+ PXENVBD_RING Ring = BlkifRing->Ring;
+
return XENBUS_CACHE(Get,
&Ring->CacheInterface,
- Ring->RequestCache,
- FALSE);
+ BlkifRing->RequestCache,
+ TRUE);
}
static VOID
-RingPutRequest(
- IN PXENVBD_RING Ring,
- IN PXENVBD_REQUEST Request
+BlkifRingPutRequest(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PXENVBD_REQUEST Request
)
{
- PLIST_ENTRY ListEntry;
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PLIST_ENTRY ListEntry;
for (;;) {
PXENVBD_SEGMENT Segment;
if (ListEntry == &Request->Segments)
break;
Segment = CONTAINING_RECORD(ListEntry, XENVBD_SEGMENT, ListEntry);
- RingPutSegment(Ring, Segment);
+ BlkifRingPutSegment(BlkifRing, Segment);
}
for (;;) {
if (ListEntry == &Request->Indirects)
break;
Indirect = CONTAINING_RECORD(ListEntry, XENVBD_INDIRECT, ListEntry);
- RingPutIndirect(Ring, Indirect);
+ BlkifRingPutIndirect(BlkifRing, Indirect);
}
Request->SrbExt = NULL;
XENBUS_CACHE(Put,
&Ring->CacheInterface,
- Ring->RequestCache,
+ BlkifRing->RequestCache,
Request,
- FALSE);
+ TRUE);
}
-static FORCEINLINE PXENVBD_REQUEST
-RingFindRequest(
- IN PXENVBD_RING Ring,
- IN ULONG64 Id
+static DECLSPEC_NOINLINE NTSTATUS
+BlkifRingRequestCtor(
+ IN PVOID Argument,
+ IN PVOID Object
)
{
- KIRQL Irql;
- PLIST_ENTRY ListEntry;
- PXENVBD_REQUEST Request;
- PXENVBD_QUEUE Queue = &Ring->SubmittedReqs;
-
- KeAcquireSpinLock(&Queue->Lock, &Irql);
+ PXENVBD_REQUEST Request = Object;
- for (ListEntry = Queue->List.Flink;
- ListEntry != &Queue->List;
- ListEntry = ListEntry->Flink) {
- Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry);
- if ((ULONG64)(ULONG_PTR)Request == Id) {
- RemoveEntryList(&Request->ListEntry);
- --Queue->Current;
- KeReleaseSpinLock(&Queue->Lock, Irql);
- return Request;
- }
- }
+ UNREFERENCED_PARAMETER(Argument);
- KeReleaseSpinLock(&Queue->Lock, Irql);
- Warning("Target[%d] : Tag %llx not found in submitted list (%u items)\n",
- FrontendGetTargetId(Ring->Frontend),
- Id,
- QueueCount(Queue));
- return NULL;
+ InitializeListHead(&Request->Segments);
+ InitializeListHead(&Request->Indirects);
+ return STATUS_SUCCESS;
}
-static FORCEINLINE VOID
-__RingIncBlkifOpCount(
- IN PXENVBD_RING Ring,
- IN PXENVBD_REQUEST Request
+static DECLSPEC_NOINLINE VOID
+BlkifRingRequestDtor(
+ IN PVOID Argument,
+ IN PVOID Object
)
{
- switch (Request->Operation) {
- case BLKIF_OP_READ:
- if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST)
- ++Ring->BlkOpIndirectRead;
- else
- ++Ring->BlkOpRead;
- break;
- case BLKIF_OP_WRITE:
- if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST)
- ++Ring->BlkOpIndirectWrite;
- else
- ++Ring->BlkOpWrite;
- break;
- case BLKIF_OP_WRITE_BARRIER:
- ++Ring->BlkOpBarrier;
- break;
- case BLKIF_OP_DISCARD:
- ++Ring->BlkOpDiscard;
- break;
- case BLKIF_OP_FLUSH_DISKCACHE:
- ++Ring->BlkOpFlush;
- break;
- default:
- ASSERT(FALSE);
- break;
- }
+ UNREFERENCED_PARAMETER(Argument);
+ UNREFERENCED_PARAMETER(Object);
}
-static FORCEINLINE ULONG
-__RingSectorsPerPage(
- IN ULONG SectorSize
+static DECLSPEC_NOINLINE NTSTATUS
+BlkifRingSegmentCtor(
+ IN PVOID Argument,
+ IN PVOID Object
)
{
- ASSERT3U(SectorSize, !=, 0);
- return PAGE_SIZE / SectorSize;
+ UNREFERENCED_PARAMETER(Argument);
+ UNREFERENCED_PARAMETER(Object);
+ return STATUS_SUCCESS;
}
-static FORCEINLINE VOID
-__RingOperation(
- IN UCHAR CdbOp,
- OUT PUCHAR RingOp,
- OUT PBOOLEAN ReadOnly
+static DECLSPEC_NOINLINE VOID
+BlkifRingSegmentDtor(
+ IN PVOID Argument,
+ IN PVOID Object
)
{
- 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);
- }
+ UNREFERENCED_PARAMETER(Argument);
+ UNREFERENCED_PARAMETER(Object);
}
-static FORCEINLINE MM_PAGE_PRIORITY
-__RingPriority(
- IN PXENVBD_RING Ring
+static DECLSPEC_NOINLINE NTSTATUS
+BlkifRingIndirectCtor(
+ IN PVOID Argument,
+ IN PVOID Object
)
{
- PXENVBD_CAPS Caps = FrontendGetCaps(Ring->Frontend);
- if (!(Caps->Paging ||
- Caps->Hibernation ||
- Caps->DumpFile))
- return NormalPagePriority;
+ PXENVBD_INDIRECT Indirect = Object;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Argument);
+
+ status = STATUS_NO_MEMORY;
+ Indirect->Mdl = __AllocatePage();
+ if (Indirect->Mdl == NULL)
+ goto fail1;
+
+ Indirect->Page = MmGetSystemAddressForMdlSafe(Indirect->Mdl,
+ NormalPagePriority);
+ ASSERT(Indirect->Page);
- return HighPagePriority;
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 %08x\n", status);
+ return status;
}
-static FORCEINLINE VOID
-RingRequestCopyOutput(
- IN PXENVBD_REQUEST Request
+static DECLSPEC_NOINLINE VOID
+BlkifRingIndirectDtor(
+ IN PVOID Argument,
+ IN PVOID Object
)
{
- PLIST_ENTRY ListEntry;
-
- if (Request->Operation != BLKIF_OP_READ)
- return;
+ PXENVBD_INDIRECT Indirect = Object;
- for (ListEntry = Request->Segments.Flink;
- ListEntry != &Request->Segments;
- ListEntry = ListEntry->Flink) {
- PXENVBD_SEGMENT Segment = CONTAINING_RECORD(ListEntry, XENVBD_SEGMENT, ListEntry);
- PXENVBD_BOUNCE Bounce = Segment->Bounce;
+ UNREFERENCED_PARAMETER(Argument);
- if (Bounce) {
- RtlCopyMemory(Bounce->SourcePtr,
- Bounce->BouncePtr,
- MmGetMdlByteCount(&Bounce->SourceMdl));
- }
- }
+ __FreePages(Indirect->Mdl);
+ Indirect->Page = NULL;
+ Indirect->Mdl = NULL;
}
-static BOOLEAN
-RingPrepareSegment(
- IN PXENVBD_RING Ring,
- IN PXENVBD_SEGMENT Segment,
- IN PXENVBD_SRBEXT SrbExt,
- IN BOOLEAN ReadOnly,
- IN ULONG SectorsLeft,
- OUT PULONG SectorsNow
- )
-{
- PFN_NUMBER Pfn;
- ULONG Offset;
- ULONG Length;
- NTSTATUS Status;
- PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
- const ULONG SectorSize = FrontendGetDiskInfo(Ring->Frontend)->SectorSize;
- const ULONG SectorsPerPage = __RingSectorsPerPage(SectorSize);
- PXENVBD_TARGET Target = FrontendGetTarget(Ring->Frontend);
- PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target);
+static VOID
+BlkifRingDebugCallback(
+ IN PVOID Argument,
+ IN BOOLEAN Crashing
+ )
+{
+ PXENVBD_BLKIF_RING BlkifRing = Argument;
+ PXENVBD_RING Ring = BlkifRing->Ring;
- Pfn = AdapterGetNextSGEntry(Adapter,
- SrbExt,
- 0,
- &Offset,
- &Length);
- if ((Offset & (SectorSize - 1)) == 0 &&
+ UNREFERENCED_PARAMETER(Crashing);
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "0x%p [%s]\n",
+ BlkifRing,
+ (BlkifRing->Enabled) ? "ENABLED" : "DISABLED");
+
+ // Dump front ring
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "FRONT: req_prod_pvt = %u rsp_cons = %u nr_ents = %u sring = %p\n",
+ BlkifRing->Front.req_prod_pvt,
+ BlkifRing->Front.rsp_cons,
+ BlkifRing->Front.nr_ents,
+ BlkifRing->Front.sring);
+
+ // Dump shared ring
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "SHARED: req_prod = %u req_event = %u rsp_prod = %u rsp_event = %u\n",
+ BlkifRing->Shared->req_prod,
+ BlkifRing->Shared->req_event,
+ BlkifRing->Shared->rsp_prod,
+ BlkifRing->Shared->rsp_event);
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "RequestsPosted = %u RequestsPushed = %u ResponsesProcessed = %u\n",
+ BlkifRing->RequestsPosted,
+ BlkifRing->RequestsPushed,
+ BlkifRing->ResponsesProcessed);
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "SrbsQueued = %u, SrbsCompleted = %u, SrbsFailed = %u\n",
+ BlkifRing->SrbsQueued,
+ BlkifRing->SrbsCompleted,
+ BlkifRing->SrbsFailed);
+
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "Dpcs = %u, Events = %u\n",
+ BlkifRing->Dpcs,
+ BlkifRing->Events);
+}
+
+static DECLSPEC_NOINLINE VOID
+__BlkifRingCompleteSrb(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PXENVBD_SRBEXT SrbExt
+ )
+{
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_FRONTEND Frontend = Ring->Frontend;
+ PXENVBD_TARGET Target = FrontendGetTarget(Frontend);
+ PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target);
+ PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb;
+
+ 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
+ ++BlkifRing->SrbsCompleted;
+ } else {
+ // Srb->SrbStatus has already been set by 1 or more requests with Status != BLKIF_RSP_OKAY
+ Srb->ScsiStatus = 0x40; // SCSI_ABORTED
+ ++BlkifRing->SrbsFailed;
+ }
+
+ AdapterCompleteSrb(Adapter, SrbExt);
+}
+
+static FORCEINLINE VOID
+BlkifRingUnprepareRequest(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PLIST_ENTRY List
+ )
+{
+ for (;;) {
+ PLIST_ENTRY ListEntry;
+ PXENVBD_REQUEST Request;
+
+ ListEntry = RemoveHeadList(List);
+ if (ListEntry == List)
+ break;
+
+ Request = CONTAINING_RECORD(ListEntry,
+ XENVBD_REQUEST,
+ ListEntry);
+
+ BlkifRingPutRequest(BlkifRing, Request);
+ }
+}
+
+static FORCEINLINE VOID
+BlkifRingQueueRequests(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PLIST_ENTRY List
+ )
+{
+ PXENVBD_SRB_STATE State = &BlkifRing->State;
+
+ for (;;) {
+ PLIST_ENTRY ListEntry;
+ PXENVBD_REQUEST Request;
+
+ ListEntry = RemoveHeadList(List);
+ if (ListEntry == List)
+ break;
+
+ Request = CONTAINING_RECORD(ListEntry,
+ XENVBD_REQUEST,
+ ListEntry);
+
+ InsertTailList(&State->List, ListEntry);
+ State->Count++;
+ }
+}
+
+static BOOLEAN
+BlkifRingPrepareSegment(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PXENVBD_SEGMENT Segment,
+ IN PXENVBD_SRBEXT SrbExt,
+ IN BOOLEAN ReadOnly,
+ IN ULONG SectorsLeft,
+ OUT PULONG SectorsNow
+ )
+{
+ PFN_NUMBER Pfn;
+ ULONG Offset;
+ ULONG Length;
+ NTSTATUS Status;
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
+ PXENVBD_TARGET Target = FrontendGetTarget(Ring->Frontend);
+ PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target);
+
+ const ULONG SectorSize = FrontendGetDiskInfo(Ring->Frontend)->SectorSize;
+ const ULONG SectorsPerPage = __SectorsPerPage(SectorSize);
+
+ Pfn = AdapterGetNextSGEntry(Adapter,
+ SrbExt,
+ 0,
+ &Offset,
+ &Length);
+ if ((Offset & (SectorSize - 1)) == 0 &&
(Length & (SectorSize - 1)) == 0) {
- ++Ring->SegsGranted;
+ InterlockedIncrement(&Ring->Stats[XENVBD_STAT_SEGMENTS_GRANTED]);
+
// get first sector, last sector and count
- Segment->FirstSector = (UCHAR)((Offset + SectorSize - 1) / SectorSize);
- *SectorsNow = __min(SectorsLeft, SectorsPerPage - Segment->FirstSector);
- Segment->LastSector = (UCHAR)(Segment->FirstSector + *SectorsNow - 1);
+ Segment->FirstSector = (UCHAR)((Offset + SectorSize - 1) / SectorSize);
+ *SectorsNow = __min(SectorsLeft, SectorsPerPage - Segment->FirstSector);
+ Segment->LastSector = (UCHAR)(Segment->FirstSector + *SectorsNow - 1);
- ASSERT3U((Length / SectorSize), ==, *SectorsNow);
+ ASSERT3U((Length / SectorSize), == , *SectorsNow);
} else {
PXENVBD_BOUNCE Bounce;
PMDL Mdl;
+ PXENVBD_CAPS Caps = FrontendGetCaps(Ring->Frontend);
+
+ InterlockedIncrement(&Ring->Stats[XENVBD_STAT_SEGMENTS_BOUNCED]);
- ++Ring->SegsBounced;
// get first sector, last sector and count
- Segment->FirstSector = 0;
- *SectorsNow = __min(SectorsLeft, SectorsPerPage);
- Segment->LastSector = (UCHAR)(*SectorsNow - 1);
+ Segment->FirstSector = 0;
+ *SectorsNow = __min(SectorsLeft, SectorsPerPage);
+ Segment->LastSector = (UCHAR)(*SectorsNow - 1);
Bounce = AdapterGetBounce(Adapter);
if (Bounce == NULL)
#pragma warning(push)
#pragma warning(disable:28145)
Mdl = &Bounce->SourceMdl;
- 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 = Length;
- Mdl->ByteOffset = Offset;
- Bounce->SourcePfn[0] = Pfn;
+ 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 = Length;
+ Mdl->ByteOffset = Offset;
+ Bounce->SourcePfn[0] = Pfn;
if (Length < *SectorsNow * SectorSize) {
Pfn = AdapterGetNextSGEntry(Adapter,
Length,
&Offset,
&Length);
- Mdl->Size += sizeof(PFN_NUMBER);
- Mdl->ByteCount += Length;
+ Mdl->Size += sizeof(PFN_NUMBER);
+ Mdl->ByteCount += Length;
Bounce->SourcePfn[1] = Pfn;
}
#pragma warning(pop)
ASSERT((Mdl->ByteCount & (SectorSize - 1)) == 0);
- ASSERT3U(Mdl->ByteCount, <=, PAGE_SIZE);
- ASSERT3U(*SectorsNow, ==, (Mdl->ByteCount / SectorSize));
+ ASSERT3U(Mdl->ByteCount, <= , PAGE_SIZE);
+ ASSERT3U(*SectorsNow, == , (Mdl->ByteCount / SectorSize));
Bounce->SourcePtr = MmMapLockedPagesSpecifyCache(Mdl,
KernelMode,
MmCached,
NULL,
FALSE,
- __RingPriority(Ring));
+ __Priority(Caps));
if (Bounce->SourcePtr == NULL)
goto fail2;
- ASSERT3P(MmGetMdlPfnArray(Mdl)[0], ==, Bounce->SourcePfn[0]);
- ASSERT3P(MmGetMdlPfnArray(Mdl)[1], ==, Bounce->SourcePfn[1]);
+ ASSERT3P(MmGetMdlPfnArray(Mdl)[0], == , Bounce->SourcePfn[0]);
+ ASSERT3P(MmGetMdlPfnArray(Mdl)[1], == , Bounce->SourcePfn[1]);
// copy contents in
if (ReadOnly) { // Operation == BLKIF_OP_WRITE
return FALSE;
}
-static BOOLEAN
-RingPrepareBlkifReadWrite(
- IN PXENVBD_RING Ring,
- IN PXENVBD_REQUEST Request,
- IN PXENVBD_SRBEXT SrbExt,
- IN ULONG MaxSegments,
- IN ULONG64 SectorStart,
- IN ULONG SectorsLeft,
- OUT PULONG SectorsDone
+static NTSTATUS
+BlkifRingPrepareReadWrite(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PXENVBD_SRBEXT SrbExt
)
{
- PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb;
- UCHAR Operation;
- BOOLEAN ReadOnly;
- ULONG Index;
- __RingOperation(Cdb_OperationEx(Srb), &Operation, &ReadOnly);
-
- Request->Operation = Operation;
- Request->NrSegments = 0;
- Request->FirstSector = SectorStart;
-
- for (Index = 0;
- Index < MaxSegments &&
- SectorsLeft > 0;
- ++Index) {
- PXENVBD_SEGMENT Segment;
- ULONG SectorsNow;
-
- Segment = RingGetSegment(Ring);
- if (Segment == NULL)
- goto fail1;
-
- InsertTailList(&Request->Segments, &Segment->ListEntry);
- ++Request->NrSegments;
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_FRONTEND Frontend = Ring->Frontend;
+ PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb;
+ ULONG64 SectorStart = Cdb_LogicalBlock(Srb);
+ ULONG SectorsLeft = Cdb_TransferBlock(Srb);
+ UCHAR Operation;
+ BOOLEAN ReadOnly;
+ LIST_ENTRY List;
- if (!RingPrepareSegment(Ring,
- Segment,
- SrbExt,
- ReadOnly,
- SectorsLeft,
- &SectorsNow))
- goto fail2;
+ const ULONG SectorSize = FrontendGetDiskInfo(Frontend)->SectorSize;
+ const ULONG SectorsPerPage = __SectorsPerPage(SectorSize);
+ const ULONG MaxIndirect = FrontendGetFeatures(Frontend)->Indirect;
- *SectorsDone += SectorsNow;
- SectorsLeft -= SectorsNow;
- }
- ASSERT3U(Request->NrSegments, >, 0);
- ASSERT3U(Request->NrSegments, <=, MaxSegments);
+ InitializeListHead(&List);
- return TRUE;
+ __Operation(Cdb_OperationEx(Srb), &Operation, &ReadOnly);
-fail2:
-fail1:
- return FALSE;
-}
+ Srb->SrbStatus = SRB_STATUS_PENDING;
-static BOOLEAN
-RingPrepareBlkifIndirect(
- IN PXENVBD_RING Ring,
- IN PXENVBD_REQUEST Request
- )
-{
- ULONG Index;
- ULONG NrSegments = 0;
+ SrbExt->RequestCount = 0;
- for (Index = 0;
- Index < BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST &&
- NrSegments < Request->NrSegments;
- ++Index) {
- PXENVBD_INDIRECT Indirect;
+ while (SectorsLeft > 0) {
+ ULONG Index;
+ ULONG MaxSegments;
+ PXENVBD_REQUEST Request;
- Indirect = RingGetIndirect(Ring);
- if (Indirect == NULL)
+ Request = BlkifRingGetRequest(BlkifRing);
+ if (Request == NULL)
goto fail1;
- InsertTailList(&Request->Indirects, &Indirect->ListEntry);
-
- NrSegments += XENVBD_MAX_SEGMENTS_PER_PAGE;
- }
-
- return TRUE;
-
-fail1:
- return FALSE;
-}
+ InsertTailList(&List, &Request->ListEntry);
+ SrbExt->RequestCount++;
-static FORCEINLINE ULONG
-RingUseIndirect(
- IN PXENVBD_RING Ring,
- IN ULONG SectorsLeft
- )
-{
- const ULONG SectorsPerPage = __RingSectorsPerPage(FrontendGetDiskInfo(Ring->Frontend)->SectorSize);
- const ULONG MaxIndirectSegs = FrontendGetFeatures(Ring->Frontend)->Indirect;
+ Request->SrbExt = SrbExt;
- if (MaxIndirectSegs <= BLKIF_MAX_SEGMENTS_PER_REQUEST)
- return BLKIF_MAX_SEGMENTS_PER_REQUEST; // not supported
+ MaxSegments = __UseIndirect(SectorsPerPage,
+ MaxIndirect,
+ SectorsLeft);
+
+ Request->Operation = Operation;
+ Request->NrSegments = 0;
+ Request->FirstSector = SectorStart;
+
+ for (Index = 0;
+ Index < MaxSegments &&
+ SectorsLeft > 0;
+ ++Index) {
+ PXENVBD_SEGMENT Segment;
+ ULONG SectorsNow;
+
+ Segment = BlkifRingGetSegment(BlkifRing);
+ if (Segment == NULL)
+ goto fail2;
+
+ InsertTailList(&Request->Segments, &Segment->ListEntry);
+ ++Request->NrSegments;
+
+ if (!BlkifRingPrepareSegment(BlkifRing,
+ Segment,
+ SrbExt,
+ ReadOnly,
+ SectorsLeft,
+ &SectorsNow))
+ goto fail3;
- if (SectorsLeft < BLKIF_MAX_SEGMENTS_PER_REQUEST * SectorsPerPage)
- return BLKIF_MAX_SEGMENTS_PER_REQUEST; // first into a single BLKIF_OP_{READ/WRITE}
+ SectorsLeft -= SectorsNow;
+ SectorStart += SectorsNow;
+ }
+ ASSERT3U(Request->NrSegments, >, 0);
+ ASSERT3U(Request->NrSegments, <= , MaxSegments);
- return MaxIndirectSegs;
-}
+ if (MaxSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+ ULONG NrSegments = 0;
-static FORCEINLINE VOID
-RingQueueRequestList(
- IN PXENVBD_RING Ring,
- IN PLIST_ENTRY List
- )
-{
- for (;;) {
- PXENVBD_REQUEST Request;
- PLIST_ENTRY ListEntry;
+ for (Index = 0;
+ Index < BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST &&
+ NrSegments < Request->NrSegments;
+ ++Index) {
+ PXENVBD_INDIRECT Indirect;
- ListEntry = RemoveHeadList(List);
- if (ListEntry == List)
- break;
+ Indirect = BlkifRingGetIndirect(BlkifRing);
+ if (Indirect == NULL)
+ goto fail3;
+ InsertTailList(&Request->Indirects, &Indirect->ListEntry);
- Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry);
- __RingIncBlkifOpCount(Ring, Request);
- QueueAppend(&Ring->PreparedReqs, &Request->ListEntry);
+ NrSegments += XENVBD_MAX_SEGMENTS_PER_PAGE;
+ }
+ }
}
-}
-
-static FORCEINLINE VOID
-RingCancelRequestList(
- IN PXENVBD_RING Ring,
- IN PLIST_ENTRY List
- )
-{
- for (;;) {
- PXENVBD_REQUEST Request;
- PLIST_ENTRY ListEntry;
- ListEntry = RemoveHeadList(List);
- if (ListEntry == List)
- break;
+ BlkifRingQueueRequests(BlkifRing, &List);
+ return STATUS_SUCCESS;
- Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry);
- RingPutRequest(Ring, Request);
- }
+fail3:
+fail2:
+fail1:
+ BlkifRingUnprepareRequest(BlkifRing, &List);
+ SrbExt->RequestCount = 0;
+ Srb->SrbStatus = SRB_STATUS_ERROR;
+ return STATUS_UNSUCCESSFUL;
}
-static BOOLEAN
-RingPrepareReadWrite(
- IN PXENVBD_RING Ring,
+static NTSTATUS
+BlkifRingPrepareUnmap(
+ IN PXENVBD_BLKIF_RING BlkifRing,
IN PXENVBD_SRBEXT SrbExt
)
{
PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb;
- ULONG64 SectorStart = Cdb_LogicalBlock(Srb);
- ULONG SectorsLeft = Cdb_TransferBlock(Srb);
+ PUNMAP_LIST_HEADER Unmap = Srb->DataBuffer;
+ ULONG Count;
+ ULONG Index;
LIST_ENTRY List;
+ InitializeListHead(&List);
+
+ Count = _byteswap_ushort(*(PUSHORT)Unmap->BlockDescrDataLength) / sizeof(UNMAP_BLOCK_DESCRIPTOR);
Srb->SrbStatus = SRB_STATUS_PENDING;
- InitializeListHead(&List);
SrbExt->RequestCount = 0;
- while (SectorsLeft > 0) {
- ULONG MaxSegments;
- ULONG SectorsDone = 0;
- PXENVBD_REQUEST Request;
+ for (Index = 0; Index < Count; ++Index) {
+ PUNMAP_BLOCK_DESCRIPTOR Descr = &Unmap->Descriptors[Index];
+ PXENVBD_REQUEST Request;
- Request = RingGetRequest(Ring);
+ Request = BlkifRingGetRequest(BlkifRing);
if (Request == NULL)
goto fail1;
InsertTailList(&List, &Request->ListEntry);
- InterlockedIncrement(&SrbExt->RequestCount);
+ SrbExt->RequestCount++;
Request->SrbExt = SrbExt;
- MaxSegments = RingUseIndirect(Ring, SectorsLeft);
-
- if (!RingPrepareBlkifReadWrite(Ring,
- Request,
- SrbExt,
- MaxSegments,
- SectorStart,
- SectorsLeft,
- &SectorsDone))
- goto fail2;
-
- if (MaxSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) {
- if (!RingPrepareBlkifIndirect(Ring, Request))
- goto fail3;
- }
-
- SectorsLeft -= SectorsDone;
- SectorStart += SectorsDone;
+ Request->Operation = BLKIF_OP_DISCARD;
+ Request->FirstSector = _byteswap_uint64(*(PULONG64)Descr->StartingLba);
+ Request->NrSectors = _byteswap_ulong(*(PULONG)Descr->LbaCount);
+ Request->Flags = 0;
}
- RingQueueRequestList(Ring, &List);
- return TRUE;
+ BlkifRingQueueRequests(BlkifRing, &List);
+ return STATUS_SUCCESS;
-fail3:
-fail2:
fail1:
- RingCancelRequestList(Ring, &List);
+ BlkifRingUnprepareRequest(BlkifRing, &List);
SrbExt->RequestCount = 0;
Srb->SrbStatus = SRB_STATUS_ERROR;
- return FALSE;
+ return STATUS_UNSUCCESSFUL;
}
-static BOOLEAN
-RingPrepareSyncCache(
- IN PXENVBD_RING Ring,
+static NTSTATUS
+BlkifRingPrepareSyncCache(
+ IN PXENVBD_BLKIF_RING BlkifRing,
IN PXENVBD_SRBEXT SrbExt
)
{
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_FRONTEND Frontend = Ring->Frontend;
PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb;
PXENVBD_REQUEST Request;
- LIST_ENTRY List;
UCHAR Operation;
+ LIST_ENTRY List;
+ InitializeListHead(&List);
Srb->SrbStatus = SRB_STATUS_PENDING;
- if (FrontendGetDiskInfo(Ring->Frontend)->FlushCache)
+ if (FrontendGetDiskInfo(Frontend)->FlushCache)
Operation = BLKIF_OP_FLUSH_DISKCACHE;
else
Operation = BLKIF_OP_WRITE_BARRIER;
- InitializeListHead(&List);
SrbExt->RequestCount = 0;
- Request = RingGetRequest(Ring);
+ Request = BlkifRingGetRequest(BlkifRing);
if (Request == NULL)
goto fail1;
InsertTailList(&List, &Request->ListEntry);
- InterlockedIncrement(&SrbExt->RequestCount);
+ SrbExt->RequestCount++;
- Request->SrbExt = SrbExt;
- Request->Operation = Operation;
+ Request->SrbExt = SrbExt;
+ Request->Operation = Operation;
Request->FirstSector = Cdb_LogicalBlock(Srb);
- RingQueueRequestList(Ring, &List);
- return TRUE;
+ BlkifRingQueueRequests(BlkifRing, &List);
+ return STATUS_SUCCESS;
fail1:
- RingCancelRequestList(Ring, &List);
+ BlkifRingUnprepareRequest(BlkifRing, &List);
SrbExt->RequestCount = 0;
Srb->SrbStatus = SRB_STATUS_ERROR;
- return FALSE;
+ return STATUS_UNSUCCESSFUL;
}
-static BOOLEAN
-RingPrepareUnmap(
- IN PXENVBD_RING Ring,
+static DECLSPEC_NOINLINE NTSTATUS
+__BlkifRingPrepareSrb(
+ IN PXENVBD_BLKIF_RING BlkifRing,
IN PXENVBD_SRBEXT SrbExt
)
-{
- PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb;
- PUNMAP_LIST_HEADER Unmap = Srb->DataBuffer;
- ULONG Count = _byteswap_ushort(*(PUSHORT)Unmap->BlockDescrDataLength) / sizeof(UNMAP_BLOCK_DESCRIPTOR);
- ULONG Index;
- LIST_ENTRY List;
-
- Srb->SrbStatus = SRB_STATUS_PENDING;
-
- InitializeListHead(&List);
- SrbExt->RequestCount = 0;
-
- for (Index = 0; Index < Count; ++Index) {
- PUNMAP_BLOCK_DESCRIPTOR Descr = &Unmap->Descriptors[Index];
- PXENVBD_REQUEST Request;
-
- Request = RingGetRequest(Ring);
- if (Request == NULL)
- goto fail1;
- InsertTailList(&List, &Request->ListEntry);
- InterlockedIncrement(&SrbExt->RequestCount);
-
- 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;
- }
-
- RingQueueRequestList(Ring, &List);
- return TRUE;
-
-fail1:
- RingCancelRequestList(Ring, &List);
- SrbExt->RequestCount = 0;
- Srb->SrbStatus = SRB_STATUS_ERROR;
- return FALSE;
-}
-
-static FORCEINLINE BOOLEAN
-RingPrepareRequest(
- IN PXENVBD_RING Ring,
- IN PXENVBD_SRBEXT SrbExt
- )
{
switch (Cdb_OperationEx(SrbExt->Srb)) {
case SCSIOP_READ:
case SCSIOP_WRITE:
- return RingPrepareReadWrite(Ring, SrbExt);
+ return BlkifRingPrepareReadWrite(BlkifRing,
+ SrbExt);
case SCSIOP_SYNCHRONIZE_CACHE:
- return RingPrepareSyncCache(Ring, SrbExt);
+ return BlkifRingPrepareSyncCache(BlkifRing,
+ SrbExt);
case SCSIOP_UNMAP:
- return RingPrepareUnmap(Ring, SrbExt);
+ return BlkifRingPrepareUnmap(BlkifRing,
+ SrbExt);
default:
ASSERT(FALSE);
- return FALSE;
+ return STATUS_NOT_SUPPORTED;
}
}
-static BOOLEAN
-RingSubmit(
- IN PXENVBD_RING Ring,
- IN PXENVBD_REQUEST Request
+static FORCEINLINE VOID
+__BlkifRingInsertRequest(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PXENVBD_REQUEST Request,
+ IN blkif_request_t *req
)
{
- 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);
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_FRONTEND Frontend = Ring->Frontend;
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Frontend);
- if (Notify) {
- if (!Ring->Enabled)
- return TRUE;
-
- XENBUS_EVTCHN(Send,
- &Ring->EvtchnInterface,
- Ring->Channel);
- }
+ 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;
- return TRUE;
-}
+ 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 = (ULONG64)(ULONG_PTR)Request;
+ req_indirect->sector_number = Request->FirstSector;
+ req_indirect->handle = (USHORT)FrontendGetDeviceId(Frontend);
-static FORCEINLINE BOOLEAN
-RingSubmitRequests(
- IN PXENVBD_RING Ring
- )
-{
- if (!Ring->Enabled) {
- if (QueueCount(&Ring->PreparedReqs))
- Warning("Target[%d] : Paused, not submitting new requests (%u)\n",
- FrontendGetTargetId(Ring->Frontend),
- QueueCount(&Ring->PreparedReqs));
- return FALSE;
- }
+ 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, ListEntry);
- for (;;) {
- PXENVBD_REQUEST Request;
- PLIST_ENTRY ListEntry;
+ req_indirect->indirect_grefs[PageIdx] = GranterReference(Granter, Page->Grant);
- ListEntry = QueuePop(&Ring->PreparedReqs);
- if (ListEntry == NULL)
- break;
+ for (SegIdx = 0;
+ SegIdx < XENVBD_MAX_SEGMENTS_PER_PAGE &&
+ SegEntry != &Request->Segments;
+ ++SegIdx, SegEntry = SegEntry->Flink) {
+ PXENVBD_SEGMENT 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;
+ }
+ }
+ InterlockedIncrement(&Ring->Stats[(Request->Operation == BLKIF_OP_READ) ?
+ XENVBD_STAT_BLKIF_OP_READ_INDIRECT :
+ XENVBD_STAT_BLKIF_OP_WRITE_INDIRECT]);
+ } else {
+ // Direct
+ ULONG Index;
+ PLIST_ENTRY Entry;
- Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry);
+ req->operation = Request->Operation;
+ req->nr_segments = (UCHAR)Request->NrSegments;
+ req->handle = (USHORT)FrontendGetDeviceId(Frontend);
+ req->id = (ULONG64)(ULONG_PTR)Request;
+ req->sector_number = Request->FirstSector;
- QueueAppend(&Ring->SubmittedReqs, &Request->ListEntry);
- KeMemoryBarrier();
+ 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, ListEntry);
+ req->seg[Index].gref = GranterReference(Granter, Segment->Grant);
+ req->seg[Index].first_sect = Segment->FirstSector;
+ req->seg[Index].last_sect = Segment->LastSector;
+ }
+ InterlockedIncrement(&Ring->Stats[(Request->Operation == BLKIF_OP_READ) ?
+ XENVBD_STAT_BLKIF_OP_READ_DIRECT :
+ XENVBD_STAT_BLKIF_OP_WRITE_DIRECT]);
+ }
+ break;
- if (RingSubmit(Ring, Request))
- continue;
+ 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 = (ULONG64)(ULONG_PTR)Request;
+ req->sector_number = Request->FirstSector;
+ InterlockedIncrement(&Ring->Stats[(Request->Operation == BLKIF_OP_WRITE_BARRIER) ?
+ XENVBD_STAT_BLKIF_OP_WRITE_BARRIER :
+ XENVBD_STAT_BLKIF_OP_FLUSH_DISKCACHE]);
+ 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(Frontend);
+ req_discard->id = (ULONG64)(ULONG_PTR)Request;
+ req_discard->sector_number = Request->FirstSector;
+ req_discard->nr_sectors = Request->NrSectors;
+ InterlockedIncrement(&Ring->Stats[XENVBD_STAT_BLKIF_OP_DISCARD]);
+ } break;
- QueueRemove(&Ring->SubmittedReqs, &Request->ListEntry);
- QueueUnPop(&Ring->PreparedReqs, &Request->ListEntry);
+ default:
+ ASSERT(FALSE);
break;
}
-
- return QueueCount(&Ring->PreparedReqs) != 0;
}
-static FORCEINLINE VOID
-RingCompleteShutdown(
- IN PXENVBD_RING Ring
+static FORCEINLINE NTSTATUS
+__BlkifRingPostRequests(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- PXENVBD_TARGET Target;
- PXENVBD_ADAPTER Adapter;
+#define RING_SLOTS_AVAILABLE(_Front, _req_prod, _rsp_cons) \
+ (RING_SIZE(_Front) - ((_req_prod) - (_rsp_cons)))
- if (QueueCount(&Ring->ShutdownSrbs) == 0)
- return;
+ PXENVBD_SRB_STATE State;
+ RING_IDX req_prod;
+ RING_IDX rsp_cons;
+ NTSTATUS status;
- if (QueueCount(&Ring->PreparedReqs) ||
- QueueCount(&Ring->SubmittedReqs))
- return;
+ State = &BlkifRing->State;
- Target = FrontendGetTarget(Ring->Frontend);
- Adapter = TargetGetAdapter(Target);
- for (;;) {
- PXENVBD_SRBEXT SrbExt;
- PSCSI_REQUEST_BLOCK Srb;
+ req_prod = BlkifRing->Front.req_prod_pvt;
+ rsp_cons = BlkifRing->Front.rsp_cons;
+
+ status = STATUS_ALLOTTED_SPACE_EXCEEDED;
+ if (RING_SLOTS_AVAILABLE(&BlkifRing->Front, req_prod, rsp_cons) <= 1)
+ goto fail1;
+
+ while (State->Count != 0) {
+ blkif_request_t *req;
+ PXENVBD_REQUEST Request;
PLIST_ENTRY ListEntry;
- ListEntry = QueuePop(&Ring->ShutdownSrbs);
- if (ListEntry == NULL)
+ --State->Count;
+
+ ListEntry = RemoveHeadList(&State->List);
+ ASSERT3P(ListEntry, != , &State->List);
+
+ RtlZeroMemory(ListEntry, sizeof(LIST_ENTRY));
+
+ Request = CONTAINING_RECORD(ListEntry,
+ XENVBD_REQUEST,
+ ListEntry);
+
+ req = RING_GET_REQUEST(&BlkifRing->Front, req_prod);
+ req_prod++;
+ BlkifRing->RequestsPosted++;
+
+ __BlkifRingInsertRequest(BlkifRing,
+ Request,
+ req);
+
+ InsertTailList(&BlkifRing->SubmittedList, ListEntry);
+
+ if (RING_SLOTS_AVAILABLE(&BlkifRing->Front, req_prod, rsp_cons) <= 1)
break;
- SrbExt = CONTAINING_RECORD(ListEntry, XENVBD_SRBEXT, ListEntry);
- Srb = SrbExt->Srb;
-
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
- AdapterCompleteSrb(Adapter, SrbExt);
}
+
+ BlkifRing->Front.req_prod_pvt = req_prod;
+
+ return STATUS_SUCCESS;
+
+fail1:
+ return status;
+
+#undef RING_SLOTS_AVAILABLE
}
-static FORCEINLINE PCHAR
-__BlkifOperationName(
- IN UCHAR Operation
+static FORCEINLINE PXENVBD_REQUEST
+__BlkifRingGetSubmittedRequest(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN ULONG64 Id
)
{
- 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>";
+ PLIST_ENTRY ListEntry;
+ PXENVBD_REQUEST Request;
+
+ for (ListEntry = BlkifRing->SubmittedList.Flink;
+ ListEntry != &BlkifRing->SubmittedList;
+ ListEntry = ListEntry->Flink) {
+ Request = CONTAINING_RECORD(ListEntry,
+ XENVBD_REQUEST,
+ ListEntry);
+ if ((ULONG64)(ULONG_PTR)Request != Id)
+ continue;
+
+ RemoveEntryList(ListEntry);
+ return Request;
}
+ return NULL;
}
-static VOID
-RingCompleteResponse(
- IN PXENVBD_RING Ring,
- IN ULONG64 Id,
- IN SHORT Status
+static FORCEINLINE VOID
+__BlkifRingCompleteResponse(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PXENVBD_REQUEST Request,
+ IN SHORT Status
)
{
- PXENVBD_REQUEST Request;
- PSCSI_REQUEST_BLOCK Srb;
- PXENVBD_SRBEXT SrbExt;
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_FRONTEND Frontend = Ring->Frontend;
+ PSCSI_REQUEST_BLOCK Srb;
+ PXENVBD_SRBEXT SrbExt;
+ PLIST_ENTRY ListEntry;
- Request = RingFindRequest(Ring, Id);
- if (Request == NULL)
- return;
-
- SrbExt = Request->SrbExt;
- Srb = SrbExt->Srb;
+ SrbExt = Request->SrbExt;
+ Srb = SrbExt->Srb;
switch (Status) {
case BLKIF_RSP_OKAY:
- RingRequestCopyOutput(Request);
+ if (Request->Operation != BLKIF_OP_READ)
+ break;
+
+ for (ListEntry = Request->Segments.Flink;
+ ListEntry != &Request->Segments;
+ ListEntry = ListEntry->Flink) {
+ PXENVBD_SEGMENT Segment = CONTAINING_RECORD(ListEntry, XENVBD_SEGMENT, ListEntry);
+ PXENVBD_BOUNCE Bounce = Segment->Bounce;
+
+ if (Bounce) {
+ RtlCopyMemory(Bounce->SourcePtr,
+ Bounce->BouncePtr,
+ MmGetMdlByteCount(&Bounce->SourceMdl));
+ }
+ }
break;
case BLKIF_RSP_EOPNOTSUPP:
// Remove appropriate feature support
- FrontendRemoveFeature(Ring->Frontend, Request->Operation);
+ FrontendRemoveFeature(Frontend, Request->Operation);
// Succeed this SRB, subsiquent SRBs will be succeeded instead of being passed to the backend.
Srb->SrbStatus = SRB_STATUS_SUCCESS;
break;
case BLKIF_RSP_ERROR:
default:
- Warning("Target[%d] : %s BLKIF_RSP_ERROR (Tag %llx)\n",
- FrontendGetTargetId(Ring->Frontend),
- __BlkifOperationName(Request->Operation),
- Id);
+ Warning("Target[%u][%u] : %s BLKIF_RSP_ERROR\n",
+ FrontendGetTargetId(Frontend),
+ BlkifRing->Index,
+ __BlkifOperationName(Request->Operation));
Srb->SrbStatus = SRB_STATUS_ERROR;
break;
}
- RingPutRequest(Ring, Request);
+ BlkifRingPutRequest(BlkifRing, Request);
// complete srb
if (InterlockedDecrement(&SrbExt->RequestCount) == 0) {
- PXENVBD_TARGET Target = FrontendGetTarget(Ring->Frontend);
- PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target);
-
- if (Srb->SrbStatus == SRB_STATUS_PENDING) {
- // SRB has not hit a failure condition (BLKIF_RSP_ERROR | BLKIF_RSP_EOPNOTSUPP)
- // from any of its responses. SRB must have succeeded
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
- Srb->ScsiStatus = 0x00; // SCSI_GOOD
- } else {
- // Srb->SrbStatus has already been set by 1 or more requests with Status != BLKIF_RSP_OKAY
- Srb->ScsiStatus = 0x40; // SCSI_ABORTED
- }
-
- AdapterCompleteSrb(Adapter, SrbExt);
+ __BlkifRingCompleteSrb(BlkifRing, SrbExt);
}
}
-static BOOLEAN
-RingPoll(
- IN PXENVBD_RING Ring
+static FORCEINLINE BOOLEAN
+BlkifRingPoll(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- BOOLEAN Retry = FALSE;
+#define XENVBD_BATCH(_Ring) (RING_SIZE(&(_Ring)->Front) / 4)
- ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
- KeAcquireSpinLockAtDpcLevel(&Ring->Lock);
+ PXENVBD_RING Ring;
+ BOOLEAN Retry;
- // Guard against this locked region being called after the
- // lock on FrontendSetState
- if (Ring->Enabled == FALSE)
+ Ring = BlkifRing->Ring;
+ Retry = FALSE;
+
+ if (!BlkifRing->Enabled)
goto done;
for (;;) {
- ULONG rsp_prod;
- ULONG rsp_cons;
+ RING_IDX rsp_prod;
+ RING_IDX rsp_cons;
KeMemoryBarrier();
- rsp_prod = Ring->Shared->rsp_prod;
- rsp_cons = Ring->Front.rsp_cons;
+ rsp_prod = BlkifRing->Shared->rsp_prod;
+ rsp_cons = BlkifRing->Front.rsp_cons;
KeMemoryBarrier();
break;
while (rsp_cons != rsp_prod && !Retry) {
- blkif_response_t* rsp;
+ blkif_response_t *rsp;
+ PXENVBD_REQUEST Request;
+
+ rsp = RING_GET_RESPONSE(&BlkifRing->Front, rsp_cons);
+ rsp_cons++;
+ BlkifRing->ResponsesProcessed++;
- rsp = RING_GET_RESPONSE(&Ring->Front, rsp_cons);
- ++rsp_cons;
- ++Ring->Received;
+ BlkifRing->Stopped = FALSE;
- RingCompleteResponse(Ring, rsp->id, rsp->status);
- RtlZeroMemory(rsp, sizeof(union blkif_sring_entry));
+ Request = __BlkifRingGetSubmittedRequest(BlkifRing,
+ rsp->id);
+ ASSERT3P(Request, != , NULL);
- if (rsp_cons - Ring->Front.rsp_cons > RING_SIZE(&Ring->Front) / 4)
+ __BlkifRingCompleteResponse(BlkifRing,
+ Request,
+ rsp->status);
+
+ if (rsp_cons - BlkifRing->Front.rsp_cons > XENVBD_BATCH(BlkifRing))
Retry = TRUE;
}
KeMemoryBarrier();
- Ring->Front.rsp_cons = rsp_cons;
- Ring->Shared->rsp_event = rsp_cons + 1;
+ BlkifRing->Front.rsp_cons = rsp_cons;
}
done:
- KeReleaseSpinLockFromDpcLevel(&Ring->Lock);
-
return Retry;
+
+#undef XENVBD_BATCH
}
-__drv_requiresIRQL(DISPATCH_LEVEL)
-static BOOLEAN
-RingNotifyResponses(
- IN PXENVBD_RING Ring
+static FORCEINLINE VOID
+__BlkifRingSend(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- BOOLEAN Retry = FALSE;
-
- if (!Ring->Enabled)
- return FALSE;
+ PXENVBD_RING Ring = BlkifRing->Ring;
- Retry |= RingPoll(Ring);
- Retry |= RingSubmitRequests(Ring);
-
- RingCompleteShutdown(Ring);
- return Retry;
+ XENBUS_EVTCHN(Send,
+ &Ring->EvtchnInterface,
+ BlkifRing->Channel);
}
-KSERVICE_ROUTINE RingInterrupt;
-
-BOOLEAN
-RingInterrupt(
- IN PKINTERRUPT Interrupt,
- IN PVOID Context
+static FORCEINLINE VOID
+__BlkifRingPushRequests(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- PXENVBD_RING Ring = Context;
+ BOOLEAN Notify;
- UNREFERENCED_PARAMETER(Interrupt);
+ if (BlkifRing->RequestsPosted == BlkifRing->RequestsPushed)
+ return;
- ASSERT(Ring != NULL);
+#pragma warning (push)
+#pragma warning (disable:4244)
- ++Ring->Events;
- if (!Ring->Connected)
- return TRUE;
+ BlkifRing->Shared->rsp_event = BlkifRing->Front.req_prod_pvt;
- if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
- ++Ring->Dpcs;
+ // Make the requests visible to the backend
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&BlkifRing->Front, Notify);
- return TRUE;
+#pragma warning (pop)
+
+ if (Notify)
+ __BlkifRingSend(BlkifRing);
+
+ BlkifRing->RequestsPushed = BlkifRing->RequestsPosted;
}
-KDEFERRED_ROUTINE RingDpc;
+#define XENVBD_LOCK_BIT ((ULONG_PTR)1)
-VOID
-RingDpc(
- __in PKDPC Dpc,
- __in_opt PVOID Context,
- __in_opt PVOID Arg1,
- __in_opt PVOID Arg2
+static DECLSPEC_NOINLINE VOID
+BlkifRingSwizzle(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- PXENVBD_RING Ring = Context;
+ ULONG_PTR Old;
+ ULONG_PTR New;
+ PLIST_ENTRY ListEntry;
+ LIST_ENTRY List;
+ ULONG Count;
- UNREFERENCED_PARAMETER(Dpc);
- UNREFERENCED_PARAMETER(Arg1);
- UNREFERENCED_PARAMETER(Arg2);
+ ASSERT3P(BlkifRing->LockThread, == , KeGetCurrentThread());
- ASSERT(Ring != NULL);
+ InitializeListHead(&List);
- for (;;) {
- KIRQL Irql;
- BOOLEAN Retry;
+ New = XENVBD_LOCK_BIT;
+ Old = (ULONG_PTR)InterlockedExchangePointer(&BlkifRing->Lock, (PVOID)New);
- KeRaiseIrql(DISPATCH_LEVEL, &Irql);
- Retry = RingNotifyResponses(Ring);
- KeLowerIrql(Irql);
+ ASSERT(Old & XENVBD_LOCK_BIT);
+ ListEntry = (PVOID)(Old & ~XENVBD_LOCK_BIT);
- if (!Retry)
- break;
+ if (ListEntry == NULL)
+ return;
+
+ // SRBs are held in the atomic packet list in reverse order
+ // so that the most recent is always head of the list. This is
+ // necessary to allow addition to the list to be done atomically.
+
+ for (Count = 0; ListEntry != NULL; ++Count) {
+ PLIST_ENTRY NextEntry;
+
+ NextEntry = ListEntry->Blink;
+ ListEntry->Flink = ListEntry->Blink = ListEntry;
+
+ InsertHeadList(&List, ListEntry);
+
+ ListEntry = NextEntry;
}
- XENBUS_EVTCHN(Unmask,
- &Ring->EvtchnInterface,
- Ring->Channel,
- FALSE);
+ if (!IsListEmpty(&List)) {
+ ListEntry = List.Flink;
+
+ RemoveEntryList(&List);
+ AppendTailList(&BlkifRing->SrbQueue, ListEntry);
+
+ BlkifRing->SrbsQueued += Count;
+ }
}
static DECLSPEC_NOINLINE VOID
-RingDebugCallback(
- IN PVOID Argument,
- IN BOOLEAN Crashing
+BlkifRingSchedule(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- PXENVBD_RING Ring = Argument;
- PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
- ULONG Index;
+ PXENVBD_SRB_STATE State;
+ BOOLEAN Polled;
- UNREFERENCED_PARAMETER(Crashing);
+ if (!BlkifRing->Enabled)
+ return;
- XENBUS_DEBUG(Printf,
- &Ring->DebugInterface,
- "Submitted: %u Received: %u\n",
- Ring->Submitted,
- Ring->Received);
+ State = &BlkifRing->State;
+ Polled = FALSE;
- XENBUS_DEBUG(Printf,
- &Ring->DebugInterface,
- "Events: %u Dpcs: %u\n",
- Ring->Events,
- Ring->Dpcs);
+ while (!BlkifRing->Stopped) {
+ PLIST_ENTRY ListEntry;
+ PXENVBD_SRBEXT SrbExt;
+ NTSTATUS status;
- XENBUS_DEBUG(Printf,
- &Ring->DebugInterface,
- "Shared : 0x%p\n",
- Ring->Shared);
+ if (State->Count != 0) {
+ status = __BlkifRingPostRequests(BlkifRing);
+ if (!NT_SUCCESS(status))
+ BlkifRing->Stopped = TRUE;
+ }
- 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);
- }
+ if (BlkifRing->Stopped) {
+ if (!Polled) {
+ (VOID)BlkifRingPoll(BlkifRing);
+ Polled = TRUE;
+ }
- XENBUS_DEBUG(Printf,
- &Ring->DebugInterface,
- "Front: %d / %d (%d)\n",
- Ring->Front.req_prod_pvt,
- Ring->Front.rsp_cons,
- Ring->Front.nr_ents);
+ continue;
+ }
- XENBUS_DEBUG(Printf,
- &Ring->DebugInterface,
- "Order: %d\n",
- Ring->Order);
+ if (BlkifRing->RequestsPosted - BlkifRing->RequestsPushed >=
+ RING_SIZE(&BlkifRing->Front) / 4)
+ __BlkifRingPushRequests(BlkifRing);
- 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]));
+ ASSERT3U(State->Count, == , 0);
+
+ if (IsListEmpty(&BlkifRing->SrbQueue))
+ break;
+
+ ListEntry = RemoveHeadList(&BlkifRing->SrbQueue);
+ ASSERT3P(ListEntry, != , &BlkifRing->SrbQueue);
+
+ RtlZeroMemory(ListEntry, sizeof(LIST_ENTRY));
+
+ SrbExt = CONTAINING_RECORD(ListEntry,
+ XENVBD_SRBEXT,
+ ListEntry);
+
+ status = __BlkifRingPrepareSrb(BlkifRing, SrbExt);
+ if (!NT_SUCCESS(status)) {
+ PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb;
+ Srb->SrbStatus = SRB_STATUS_BUSY;
+ __BlkifRingCompleteSrb(BlkifRing, SrbExt);
+ }
}
- if (Ring->Channel) {
- ULONG Port = XENBUS_EVTCHN(GetPort,
- &Ring->EvtchnInterface,
- Ring->Channel);
+ __BlkifRingPushRequests(BlkifRing);
- XENBUS_DEBUG(Printf,
- &Ring->DebugInterface,
- "Channel : %p (%d)\n",
- Ring->Channel,
- Port);
+ if (IsListEmpty(&BlkifRing->ShutdownQueue))
+ return;
+
+ if (!IsListEmpty(&BlkifRing->SrbQueue) ||
+ !IsListEmpty(&BlkifRing->SubmittedList))
+ return;
+
+ for (;;) {
+ PLIST_ENTRY ListEntry;
+ PXENVBD_SRBEXT SrbExt;
+ PSCSI_REQUEST_BLOCK Srb;
+
+ ListEntry = RemoveHeadList(&BlkifRing->ShutdownQueue);
+ if (ListEntry == &BlkifRing->ShutdownQueue)
+ break;
+
+ SrbExt = CONTAINING_RECORD(ListEntry,
+ XENVBD_SRBEXT,
+ ListEntry);
+
+ Srb = SrbExt->Srb;
+ Srb->SrbStatus = SRB_STATUS_SUCCESS;
+ __BlkifRingCompleteSrb(BlkifRing, SrbExt);
}
+}
- XENBUS_DEBUG(Printf,
- &Ring->DebugInterface,
- "BLKIF_OPs: READ=%u WRITE=%u\n",
- Ring->BlkOpRead,
- Ring->BlkOpWrite);
- XENBUS_DEBUG(Printf,
- &Ring->DebugInterface,
- "BLKIF_OPs: INDIRECT_READ=%u INDIRECT_WRITE=%u\n",
- Ring->BlkOpIndirectRead,
- Ring->BlkOpIndirectWrite);
- XENBUS_DEBUG(Printf,
- &Ring->DebugInterface,
- "BLKIF_OPs: BARRIER=%u DISCARD=%u FLUSH=%u\n",
- Ring->BlkOpBarrier,
- Ring->BlkOpDiscard,
- Ring->BlkOpFlush);
- XENBUS_DEBUG(Printf,
- &Ring->DebugInterface,
- "Segments Granted=%llu Bounced=%llu\n",
- Ring->SegsGranted,
- Ring->SegsBounced);
+static FORCEINLINE BOOLEAN
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__BlkifRingTryAcquireLock(
+ IN PXENVBD_BLKIF_RING BlkifRing
+ )
+{
+ ULONG_PTR Old;
+ ULONG_PTR New;
+ BOOLEAN Acquired;
+
+ ASSERT3U(KeGetCurrentIrql(), == , DISPATCH_LEVEL);
+
+ KeMemoryBarrier();
+
+ Old = (ULONG_PTR)BlkifRing->Lock & ~XENVBD_LOCK_BIT;
+ New = Old | XENVBD_LOCK_BIT;
+
+ Acquired = ((ULONG_PTR)InterlockedCompareExchangePointer(&BlkifRing->Lock,
+ (PVOID)New,
+ (PVOID)Old) == Old) ? TRUE : FALSE;
- QueueDebugCallback(&Ring->PreparedReqs,
- "Prepared ",
- &Ring->DebugInterface);
- QueueDebugCallback(&Ring->SubmittedReqs,
- "Submitted",
- &Ring->DebugInterface);
- QueueDebugCallback(&Ring->ShutdownSrbs,
- "Shutdown ",
- &Ring->DebugInterface);
+ KeMemoryBarrier();
+
+ if (Acquired) {
+ ASSERT3P(BlkifRing->LockThread, == , NULL);
+ BlkifRing->LockThread = KeGetCurrentThread();
+ KeMemoryBarrier();
+ }
+
+ return Acquired;
}
-static DECLSPEC_NOINLINE VOID
-RingAcquireLock(
- IN PVOID Argument
+static FORCEINLINE VOID
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__BlkifRingAcquireLock(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- PXENVBD_RING Ring = Argument;
- KeAcquireSpinLockAtDpcLevel(&Ring->Lock);
+ ASSERT3U(KeGetCurrentIrql(), == , DISPATCH_LEVEL);
+
+ for (;;) {
+ if (__BlkifRingTryAcquireLock(BlkifRing))
+ break;
+
+ _mm_pause();
+ }
}
-static DECLSPEC_NOINLINE VOID
-RingReleaseLock(
- IN PVOID Argument
+static VOID
+BlkifRingAcquireLock(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- PXENVBD_RING Ring = Argument;
- KeReleaseSpinLockFromDpcLevel(&Ring->Lock);
+ __BlkifRingAcquireLock(BlkifRing);
}
-static DECLSPEC_NOINLINE NTSTATUS
-RingRequestCtor(
- IN PVOID Argument,
- IN PVOID Object
+static FORCEINLINE BOOLEAN
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__BlkifRingTryReleaseLock(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- PXENVBD_REQUEST Request = Object;
+ ULONG_PTR Old;
+ ULONG_PTR New;
+ BOOLEAN Released;
- UNREFERENCED_PARAMETER(Argument);
+ ASSERT3U(KeGetCurrentIrql(), == , DISPATCH_LEVEL);
+ ASSERT3P(KeGetCurrentThread(), == , BlkifRing->LockThread);
- InitializeListHead(&Request->Segments);
- InitializeListHead(&Request->Indirects);
- return STATUS_SUCCESS;
+ Old = XENVBD_LOCK_BIT;
+ New = 0;
+
+ BlkifRing->LockThread = NULL;
+
+ KeMemoryBarrier();
+
+ Released = ((ULONG_PTR)InterlockedCompareExchangePointer(&BlkifRing->Lock,
+ (PVOID)New,
+ (PVOID)Old) == Old) ? TRUE : FALSE;
+
+ KeMemoryBarrier();
+
+ if (!Released) {
+ ASSERT3P(BlkifRing->LockThread, == , NULL);
+ BlkifRing->LockThread = KeGetCurrentThread();
+ KeMemoryBarrier();
+ }
+
+ return Released;
}
-static DECLSPEC_NOINLINE VOID
-RingRequestDtor(
- IN PVOID Argument,
- IN PVOID Object
+static FORCEINLINE VOID
+__drv_requiresIRQL(DISPATCH_LEVEL)
+__BlkifRingReleaseLock(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- UNREFERENCED_PARAMETER(Argument);
- UNREFERENCED_PARAMETER(Object);
+ ASSERT3U(KeGetCurrentIrql(), == , DISPATCH_LEVEL);
+
+ // As lock holder it is our responsibility to drain the atomic
+ // packet list into the transmit queue before we actually drop the
+ // lock. This may, of course, take a few attempts as another
+ // thread could be simuntaneously adding to the list.
+
+ do {
+ BlkifRingSwizzle(BlkifRing);
+ BlkifRingSchedule(BlkifRing);
+ } while (!__BlkifRingTryReleaseLock(BlkifRing));
}
-static DECLSPEC_NOINLINE NTSTATUS
-RingSegmentCtor(
- IN PVOID Argument,
- IN PVOID Object
+static VOID
+BlkifRingReleaseLock(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- UNREFERENCED_PARAMETER(Argument);
- UNREFERENCED_PARAMETER(Object);
+ __BlkifRingReleaseLock(BlkifRing);
+}
+
+KSERVICE_ROUTINE BlkifRingInterrupt;
+
+BOOLEAN
+BlkifRingInterrupt(
+ IN PKINTERRUPT InterruptObject,
+ IN PVOID Argument
+ )
+{
+ PXENVBD_BLKIF_RING BlkifRing = Argument;
+
+ UNREFERENCED_PARAMETER(InterruptObject);
+
+ ASSERT(BlkifRing != NULL);
+
+ BlkifRing->Events++;
+
+ if (KeInsertQueueDpc(&BlkifRing->Dpc, NULL, NULL))
+ BlkifRing->Dpcs++;
+
+ return TRUE;
+}
+
+__drv_functionClass(KDEFERRED_ROUTINE)
+__drv_maxIRQL(DISPATCH_LEVEL)
+__drv_minIRQL(PASSIVE_LEVEL)
+__drv_sameIRQL
+static VOID
+BlkifRingDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID Argument1,
+ IN PVOID Argument2
+ )
+{
+ PXENVBD_BLKIF_RING BlkifRing = Context;
+ PXENVBD_RING Ring;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(Argument1);
+ UNREFERENCED_PARAMETER(Argument2);
+
+ ASSERT(BlkifRing != NULL);
+
+ Ring = BlkifRing->Ring;
+
+ for (;;) {
+ BOOLEAN Retry;
+ KIRQL Irql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+ __BlkifRingAcquireLock(BlkifRing);
+ Retry = BlkifRingPoll(BlkifRing);
+ __BlkifRingReleaseLock(BlkifRing);
+ KeLowerIrql(Irql);
+
+ if (!Retry)
+ break;
+ }
+
+ XENBUS_EVTCHN(Unmask,
+ &Ring->EvtchnInterface,
+ BlkifRing->Channel,
+ FALSE);
+}
+
+static NTSTATUS
+BlkifRingCreate(
+ IN PXENVBD_RING Ring,
+ IN ULONG Index,
+ OUT PXENVBD_BLKIF_RING* BlkifRing
+ )
+{
+ PXENVBD_FRONTEND Frontend;
+ ULONG Length;
+ PCHAR Path;
+ CHAR Name[MAX_NAME_LEN];
+ NTSTATUS status;
+
+ Frontend = Ring->Frontend;
+
+ Length = (ULONG)strlen(FrontendGetFrontendPath(Frontend)) +
+ (ULONG)strlen("/queue-xxx");
+
+ Path = __RingAllocate(Length + 1);
+
+ status = STATUS_NO_MEMORY;
+ if (Path == NULL)
+ goto fail1;
+
+ status = RtlStringCchPrintfA(Path,
+ Length,
+ "%s/queue-%u",
+ FrontendGetFrontendPath(Frontend),
+ Index);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ *BlkifRing = __RingAllocate(sizeof(XENVBD_BLKIF_RING));
+
+ status = STATUS_NO_MEMORY;
+ if (*BlkifRing == NULL)
+ goto fail3;
+
+ (*BlkifRing)->Ring = Ring;
+ (*BlkifRing)->Index = Index;
+ (*BlkifRing)->Path = Path;
+ Path = NULL;
+
+ InitializeListHead(&(*BlkifRing)->SrbQueue);
+ InitializeListHead(&(*BlkifRing)->ShutdownQueue);
+ InitializeListHead(&(*BlkifRing)->SubmittedList);
+ InitializeListHead(&(*BlkifRing)->State.List);
+
+ KeInitializeThreadedDpc(&(*BlkifRing)->Dpc, BlkifRingDpc, *BlkifRing);
+
+ status = RtlStringCbPrintfA(Name,
+ sizeof(Name),
+ "vbd_%u_queue_%u_request",
+ FrontendGetTargetId(Frontend),
+ Index);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ status = XENBUS_CACHE(Create,
+ &Ring->CacheInterface,
+ Name,
+ sizeof(XENVBD_REQUEST),
+ 0,
+ BlkifRingRequestCtor,
+ BlkifRingRequestDtor,
+ BlkifRingAcquireLock,
+ BlkifRingReleaseLock,
+ *BlkifRing,
+ &(*BlkifRing)->RequestCache);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ status = RtlStringCbPrintfA(Name,
+ sizeof(Name),
+ "vbd_%u_queue_%u_segment",
+ FrontendGetTargetId(Frontend),
+ Index);
+ if (!NT_SUCCESS(status))
+ goto fail6;
+
+ status = XENBUS_CACHE(Create,
+ &Ring->CacheInterface,
+ Name,
+ sizeof(XENVBD_SEGMENT),
+ 0,
+ BlkifRingSegmentCtor,
+ BlkifRingSegmentDtor,
+ BlkifRingAcquireLock,
+ BlkifRingReleaseLock,
+ *BlkifRing,
+ &(*BlkifRing)->SegmentCache);
+ if (!NT_SUCCESS(status))
+ goto fail7;
+
+ status = RtlStringCbPrintfA(Name,
+ sizeof(Name),
+ "vbd_%u_queue_%u_indirect",
+ FrontendGetTargetId(Frontend),
+ Index);
+ if (!NT_SUCCESS(status))
+ goto fail8;
+
+ status = XENBUS_CACHE(Create,
+ &Ring->CacheInterface,
+ Name,
+ sizeof(XENVBD_INDIRECT),
+ 0,
+ BlkifRingIndirectCtor,
+ BlkifRingIndirectDtor,
+ BlkifRingAcquireLock,
+ BlkifRingReleaseLock,
+ *BlkifRing,
+ &(*BlkifRing)->IndirectCache);
+ if (!NT_SUCCESS(status))
+ goto fail9;
+
return STATUS_SUCCESS;
+
+fail9:
+ Error("fail9\n");
+fail8:
+ Error("fail8\n");
+ XENBUS_CACHE(Destroy,
+ &Ring->CacheInterface,
+ (*BlkifRing)->SegmentCache);
+ (*BlkifRing)->SegmentCache = NULL;
+fail7:
+ Error("fail7\n");
+fail6:
+ Error("fail6\n");
+ XENBUS_CACHE(Destroy,
+ &Ring->CacheInterface,
+ (*BlkifRing)->RequestCache);
+ (*BlkifRing)->RequestCache = NULL;
+fail5:
+ Error("fail5\n");
+fail4:
+ Error("fail4\n");
+
+ RtlZeroMemory(&(*BlkifRing)->Dpc, sizeof(KDPC));
+
+ RtlZeroMemory(&(*BlkifRing)->State.List, sizeof(LIST_ENTRY));
+ RtlZeroMemory(&(*BlkifRing)->SubmittedList, sizeof(LIST_ENTRY));
+ RtlZeroMemory(&(*BlkifRing)->ShutdownQueue, sizeof(LIST_ENTRY));
+ RtlZeroMemory(&(*BlkifRing)->SrbQueue, sizeof(LIST_ENTRY));
+
+ __RingFree((*BlkifRing)->Path);
+ (*BlkifRing)->Path;
+ (*BlkifRing)->Index = 0;
+ (*BlkifRing)->Ring = NULL;
+
+ ASSERT(IsZeroMemory(*BlkifRing, sizeof(XENVBD_BLKIF_RING)));
+ __RingFree(*BlkifRing);
+ *BlkifRing = NULL;
+fail3:
+ Error("fail3\n");
+fail2:
+ Error("fail2\n");
+ __RingFree(Path);
+fail1:
+ Error("fail1 (%08x)\n", status);
+ return status;
}
-static DECLSPEC_NOINLINE VOID
-RingSegmentDtor(
- IN PVOID Argument,
- IN PVOID Object
+static VOID
+BlkifRingDestroy(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- UNREFERENCED_PARAMETER(Argument);
- UNREFERENCED_PARAMETER(Object);
+ PXENVBD_RING Ring = BlkifRing->Ring;
+
+ XENBUS_CACHE(Destroy,
+ &Ring->CacheInterface,
+ BlkifRing->IndirectCache);
+ BlkifRing->IndirectCache = NULL;
+
+ XENBUS_CACHE(Destroy,
+ &Ring->CacheInterface,
+ BlkifRing->SegmentCache);
+ BlkifRing->SegmentCache = NULL;
+
+ XENBUS_CACHE(Destroy,
+ &Ring->CacheInterface,
+ BlkifRing->RequestCache);
+ BlkifRing->RequestCache = NULL;
+
+ RtlZeroMemory(&BlkifRing->Dpc, sizeof(KDPC));
+
+ ASSERT3U(BlkifRing->State.Count, == , 0);
+ ASSERT(IsListEmpty(&BlkifRing->State.List));
+ RtlZeroMemory(&BlkifRing->State.List, sizeof(LIST_ENTRY));
+
+ RtlZeroMemory(&BlkifRing->SubmittedList, sizeof(LIST_ENTRY));
+ RtlZeroMemory(&BlkifRing->SrbQueue, sizeof(LIST_ENTRY));
+ RtlZeroMemory(&BlkifRing->ShutdownQueue, sizeof(LIST_ENTRY));
+
+ __RingFree(BlkifRing->Path);
+ BlkifRing->Path;
+ BlkifRing->Index = 0;
+ BlkifRing->Ring = NULL;
+
+ ASSERT(IsZeroMemory(BlkifRing, sizeof(XENVBD_BLKIF_RING)));
+ __RingFree(BlkifRing);
}
-static DECLSPEC_NOINLINE NTSTATUS
-RingIndirectCtor(
- IN PVOID Argument,
- IN PVOID Object
+static NTSTATUS
+BlkifRingConnect(
+ IN PXENVBD_BLKIF_RING BlkifRing
)
{
- PXENVBD_INDIRECT Indirect = Object;
- NTSTATUS status;
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_FRONTEND Frontend = Ring->Frontend;
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Frontend);
+ CHAR Name[MAX_NAME_LEN];
+ ULONG Index;
+ NTSTATUS status;
- UNREFERENCED_PARAMETER(Argument);
+ Trace("====> %u\n", BlkifRing->Index);
+ ASSERT(!BlkifRing->Connected);
+
+ if (FrontendGetNumQueues(Frontend) != 1) {
+ PROCESSOR_NUMBER ProcNumber;
+
+ status = KeGetProcessorNumberFromIndex(BlkifRing->Index, &ProcNumber);
+ ASSERT(NT_SUCCESS(status));
+
+ KeSetTargetProcessorDpcEx(&BlkifRing->Dpc, &ProcNumber);
+ }
+ KeSetImportanceDpc(&BlkifRing->Dpc, MediumHighImportance);
+
+ BlkifRing->Mdl = __AllocatePages(1 << Ring->Order);
status = STATUS_NO_MEMORY;
- Indirect->Mdl = __AllocatePage();
- if (Indirect->Mdl == NULL)
+ if (BlkifRing->Mdl == NULL)
goto fail1;
- Indirect->Page = MmGetSystemAddressForMdlSafe(Indirect->Mdl,
- NormalPagePriority);
- ASSERT(Indirect->Page);
+ BlkifRing->Shared = MmGetSystemAddressForMdlSafe(BlkifRing->Mdl,
+ NormalPagePriority);
+ ASSERT(BlkifRing->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(BlkifRing->Shared);
+ FRONT_RING_INIT(&BlkifRing->Front, BlkifRing->Shared, PAGE_SIZE << Ring->Order);
+#pragma warning(pop)
+
+ for (Index = 0; Index < (1ul << Ring->Order); ++Index) {
+ status = GranterGet(Granter,
+ MmGetMdlPfnArray(BlkifRing->Mdl)[Index],
+ FALSE,
+ &BlkifRing->Grants[Index]);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+ }
+
+ BlkifRing->Channel = XENBUS_EVTCHN(Open,
+ &Ring->EvtchnInterface,
+ XENBUS_EVTCHN_TYPE_UNBOUND,
+ BlkifRingInterrupt,
+ BlkifRing,
+ FrontendGetBackendDomain(Ring->Frontend),
+ TRUE);
+ status = STATUS_NO_MEMORY;
+ if (BlkifRing->Channel == NULL)
+ goto fail3;
+
+ XENBUS_EVTCHN(Unmask,
+ &Ring->EvtchnInterface,
+ BlkifRing->Channel,
+ FALSE);
+
+ status = RtlStringCchPrintfA(Name,
+ MAX_NAME_LEN,
+ __MODULE__"|RING[%u]",
+ Index);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ status = XENBUS_DEBUG(Register,
+ &Ring->DebugInterface,
+ Name,
+ BlkifRingDebugCallback,
+ BlkifRing,
+ &BlkifRing->DebugCallback);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ BlkifRing->Connected = TRUE;
+ Trace("<==== %u\n", BlkifRing->Index);
return STATUS_SUCCESS;
+fail5:
+ Error("fail5\n");
+fail4:
+ Error("fail4\n");
+ XENBUS_EVTCHN(Close,
+ &Ring->EvtchnInterface,
+ BlkifRing->Channel);
+ BlkifRing->Channel = NULL;
+fail3:
+ Error("fail3\n");
+fail2:
+ Error("fail2\n");
+ for (Index = 0; Index < (1ul << Ring->Order); ++Index) {
+ if (BlkifRing->Grants[Index] == NULL)
+ continue;
+
+ GranterPut(Granter, BlkifRing->Grants[Index]);
+ BlkifRing->Grants[Index] = NULL;
+ }
+
+ RtlZeroMemory(&BlkifRing->Front, sizeof(blkif_front_ring_t));
+
+ __FreePages(BlkifRing->Mdl);
+ BlkifRing->Shared = NULL;
+ BlkifRing->Mdl = NULL;
fail1:
Error("fail1 %08x\n", status);
return status;
}
+static NTSTATUS
+BlkifRingStoreWrite(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PVOID Transaction
+ )
+{
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_FRONTEND Frontend = Ring->Frontend;
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Frontend);
+ PCHAR Path;
+ NTSTATUS status;
+
+ Path = (FrontendGetNumQueues(Frontend) == 1) ?
+ FrontendGetFrontendPath(Frontend) :
+ BlkifRing->Path;
+
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ Path,
+ "event-channel",
+ "%u",
+ XENBUS_EVTCHN(GetPort,
+ &Ring->EvtchnInterface,
+ BlkifRing->Channel));
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ if (Ring->Order == 0) {
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ Path,
+ "ring-ref",
+ "%u",
+ GranterReference(Granter, BlkifRing->Grants[0]));
+ if (!NT_SUCCESS(status))
+ goto fail2;
+ } else {
+ ULONG Index;
+
+ 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))
+ goto fail3;
+
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ Path,
+ Name,
+ "%u",
+ GranterReference(Granter, BlkifRing->Grants[Index]));
+ if (!NT_SUCCESS(status))
+ goto fail4;
+ }
+ }
+
+ return STATUS_SUCCESS;
+
+fail4:
+fail3:
+fail2:
+fail1:
+ return status;
+}
+
+static VOID
+BlkifRingEnable(
+ IN PXENVBD_BLKIF_RING BlkifRing
+ )
+{
+ Trace("====> %u\n", BlkifRing->Index);
+
+ __BlkifRingAcquireLock(BlkifRing);
+ ASSERT(!BlkifRing->Enabled);
+ BlkifRing->Enabled = TRUE;
+ __BlkifRingReleaseLock(BlkifRing);
+
+ Trace("<==== %u\n", BlkifRing->Index);
+}
+
+static VOID
+BlkifRingDisable(
+ IN PXENVBD_BLKIF_RING BlkifRing
+ )
+{
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ ULONG Attempt;
+
+ Trace("====> %u\n", BlkifRing->Index);
+
+ __BlkifRingAcquireLock(BlkifRing);
+ ASSERT(BlkifRing->Enabled);
+
+ // Discard any pending requests
+ while (!IsListEmpty(&BlkifRing->State.List)) {
+ PLIST_ENTRY ListEntry;
+ PXENVBD_REQUEST Request;
+ PXENVBD_SRBEXT SrbExt;
+ PSCSI_REQUEST_BLOCK Srb;
+
+ ListEntry = RemoveHeadList(&BlkifRing->State.List);
+ ASSERT3P(ListEntry, != , &BlkifRing->State.List);
+
+ Request = CONTAINING_RECORD(ListEntry,
+ XENVBD_REQUEST,
+ ListEntry);
+ SrbExt = Request->SrbExt;
+ Srb = SrbExt->Srb;
+ Srb->SrbStatus = SRB_STATUS_ABORTED;
+ Srb->ScsiStatus = 0x40; // SCSI_ABORTED
+
+ BlkifRingPutRequest(BlkifRing, Request);
+
+ if (InterlockedDecrement(&SrbExt->RequestCount) == 0)
+ __BlkifRingCompleteSrb(BlkifRing, SrbExt);
+ }
+
+ ASSERT3U(BlkifRing->State.Count, == , 0);
+
+ Attempt = 0;
+ ASSERT3U(BlkifRing->RequestsPushed, == , BlkifRing->RequestsPosted);
+ while (BlkifRing->ResponsesProcessed != BlkifRing->RequestsPushed) {
+ Attempt++;
+ ASSERT(Attempt < 100);
+
+ // Try to move things along
+ __BlkifRingSend(BlkifRing);
+ (VOID)BlkifRingPoll(BlkifRing);
+
+ // We are waiting for a watch event at DISPATCH_LEVEL so
+ // it is our responsibility to poll the store ring.
+ XENBUS_STORE(Poll,
+ &Ring->StoreInterface);
+
+ KeStallExecutionProcessor(1000); // 1ms
+ }
+
+ BlkifRing->Enabled = FALSE;
+ __BlkifRingReleaseLock(BlkifRing);
+
+ Trace("<==== %u\n", BlkifRing->Index);
+}
+
+static VOID
+BlkifRingDisconnect(
+ IN PXENVBD_BLKIF_RING BlkifRing
+ )
+{
+ PXENVBD_RING Ring = BlkifRing->Ring;
+ PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
+ ULONG Index;
+
+ Trace("====> %u\n", BlkifRing->Index);
+ ASSERT(BlkifRing->Connected);
+
+ XENBUS_DEBUG(Deregister,
+ &Ring->DebugInterface,
+ BlkifRing->DebugCallback);
+ BlkifRing->DebugCallback = NULL;
+
+ XENBUS_EVTCHN(Close,
+ &Ring->EvtchnInterface,
+ BlkifRing->Channel);
+ BlkifRing->Channel = NULL;
+
+ for (Index = 0; Index < (1ul << Ring->Order); ++Index) {
+ if (BlkifRing->Grants[Index] == NULL)
+ continue;
+
+ GranterPut(Granter, BlkifRing->Grants[Index]);
+ BlkifRing->Grants[Index] = NULL;
+ }
+
+ RtlZeroMemory(&BlkifRing->Front, sizeof(blkif_front_ring_t));
+
+ __FreePages(BlkifRing->Mdl);
+ BlkifRing->Shared = NULL;
+ BlkifRing->Mdl = NULL;
+
+ BlkifRing->Events = 0;
+ BlkifRing->Dpcs = 0;
+ BlkifRing->RequestsPosted = 0;
+ BlkifRing->RequestsPushed = 0;
+ BlkifRing->ResponsesProcessed = 0;
+
+ BlkifRing->Connected = FALSE;
+
+ Trace("<==== %u\n", BlkifRing->Index);
+}
+
+static VOID
+__BlkifRingQueueSrb(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PXENVBD_SRBEXT SrbExt
+ )
+{
+ PLIST_ENTRY ListEntry;
+ ULONG_PTR Old;
+ ULONG_PTR LockBit;
+ ULONG_PTR New;
+
+ ListEntry = &SrbExt->ListEntry;
+
+ do {
+ Old = (ULONG_PTR)BlkifRing->Lock;
+ LockBit = Old & XENVBD_LOCK_BIT;
+
+ ListEntry->Blink = (PVOID)(Old & ~XENVBD_LOCK_BIT);
+ New = (ULONG_PTR)ListEntry;
+ ASSERT((New & XENVBD_LOCK_BIT) == 0);
+ New |= LockBit;
+ } while ((ULONG_PTR)InterlockedCompareExchangePointer(&BlkifRing->Lock, (PVOID)New, (PVOID)Old) != Old);
+
+ // __BlkifRingReleaseLock() drains the atomic SRB list into the queue therefore,
+ // after adding to the list we need to attempt to grab and release the lock. If we can't
+ // grab it then that's ok because whichever thread is holding it will have to call
+ // __BlkifRingReleaseLock() and will therefore drain the atomic packet list.
+
+ if (__BlkifRingTryAcquireLock(BlkifRing))
+ __BlkifRingReleaseLock(BlkifRing);
+}
+
+static VOID
+__BlkifRingQueueShutdown(
+ IN PXENVBD_BLKIF_RING BlkifRing,
+ IN PXENVBD_SRBEXT SrbExt
+ )
+{
+ __BlkifRingAcquireLock(BlkifRing);
+ InsertTailList(&BlkifRing->ShutdownQueue, &SrbExt->ListEntry);
+ __BlkifRingReleaseLock(BlkifRing);
+}
+
static DECLSPEC_NOINLINE VOID
-RingIndirectDtor(
+RingDebugCallback(
IN PVOID Argument,
- IN PVOID Object
+ IN BOOLEAN Crashing
)
{
- PXENVBD_INDIRECT Indirect = Object;
+ PXENVBD_RING Ring = Argument;
+ XENVBD_STAT Index;
- UNREFERENCED_PARAMETER(Argument);
+ UNREFERENCED_PARAMETER(Crashing);
- __FreePages(Indirect->Mdl);
- Indirect->Page = NULL;
- Indirect->Mdl = NULL;
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "Order: %d\n",
+ Ring->Order);
+
+ for (Index = 0; Index < XENVBD_STAT__MAX; ++Index) {
+ XENBUS_DEBUG(Printf,
+ &Ring->DebugInterface,
+ "%s: %u\n",
+ __StatName(Index),
+ Ring->Stats[Index]);
+ }
}
NTSTATUS
{
PXENVBD_TARGET Target = FrontendGetTarget(Frontend);
PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target);
- CHAR Name[MAX_NAME_LEN];
+ ULONG MaxQueues;
+ ULONG Index;
NTSTATUS status;
*Ring = __RingAllocate(sizeof(XENVBD_RING));
if (*Ring == NULL)
goto fail1;
- (*Ring)->Frontend = Frontend;
- KeInitializeSpinLock(&(*Ring)->Lock);
- KeInitializeThreadedDpc(&(*Ring)->Dpc, RingDpc, *Ring);
- KeSetImportanceDpc(&(*Ring)->Dpc, MediumHighImportance);
-
- QueueInit(&(*Ring)->PreparedReqs);
- QueueInit(&(*Ring)->SubmittedReqs);
- QueueInit(&(*Ring)->ShutdownSrbs);
-
- AdapterGetCacheInterface(Adapter, &(*Ring)->CacheInterface);
-
- status = XENBUS_CACHE(Acquire, &(*Ring)->CacheInterface);
- if (!NT_SUCCESS(status))
- goto fail2;
+ AdapterGetDebugInterface(Adapter,
+ &(*Ring)->DebugInterface);
+ AdapterGetStoreInterface(Adapter,
+ &(*Ring)->StoreInterface);
+ AdapterGetCacheInterface(Adapter,
+ &(*Ring)->CacheInterface);
+ AdapterGetEvtchnInterface(Adapter,
+ &(*Ring)->EvtchnInterface);
- status = RtlStringCbPrintfA(Name,
- sizeof(Name),
- "vbd_%u_req",
- FrontendGetTargetId(Frontend));
- if (!NT_SUCCESS(status))
- goto fail3;
+ (*Ring)->Frontend = Frontend;
- status = XENBUS_CACHE(Create,
- &(*Ring)->CacheInterface,
- Name,
- sizeof(XENVBD_REQUEST),
- 32,
- RingRequestCtor,
- RingRequestDtor,
- RingAcquireLock,
- RingReleaseLock,
- *Ring,
- &(*Ring)->RequestCache);
- if (!NT_SUCCESS(status))
- goto fail4;
+ MaxQueues = FrontendGetMaxQueues(Frontend);
+ (*Ring)->Ring = __RingAllocate(sizeof(PXENVBD_BLKIF_RING) *
+ MaxQueues);
- status = RtlStringCbPrintfA(Name,
- sizeof(Name),
- "vbd_%u_seg",
- FrontendGetTargetId(Frontend));
- if (!NT_SUCCESS(status))
- goto fail5;
+ status = STATUS_NO_MEMORY;
+ if ((*Ring)->Ring == NULL)
+ goto fail2;
- status = XENBUS_CACHE(Create,
- &(*Ring)->CacheInterface,
- Name,
- sizeof(XENVBD_SEGMENT),
- 32,
- RingSegmentCtor,
- RingSegmentDtor,
- RingAcquireLock,
- RingReleaseLock,
- *Ring,
- &(*Ring)->SegmentCache);
- if (!NT_SUCCESS(status))
- goto fail6;
+ Index = 0;
+ while (Index < MaxQueues) {
+ PXENVBD_BLKIF_RING BlkifRing;
- status = RtlStringCbPrintfA(Name,
- sizeof(Name),
- "vbd_%u_ind",
- FrontendGetTargetId(Frontend));
- if (!NT_SUCCESS(status))
- goto fail7;
+ status = BlkifRingCreate(*Ring, Index, &BlkifRing);
+ if (!NT_SUCCESS(status))
+ goto fail3;
- status = XENBUS_CACHE(Create,
- &(*Ring)->CacheInterface,
- Name,
- sizeof(XENVBD_INDIRECT),
- 1,
- RingIndirectCtor,
- RingIndirectDtor,
- RingAcquireLock,
- RingReleaseLock,
- *Ring,
- &(*Ring)->IndirectCache);
- if (!NT_SUCCESS(status))
- goto fail8;
+ (*Ring)->Ring[Index] = BlkifRing;
+ Index++;
+ }
return STATUS_SUCCESS;
-fail8:
- Error("fail8\n");
-fail7:
- Error("fail7\n");
- XENBUS_CACHE(Destroy,
- &(*Ring)->CacheInterface,
- (*Ring)->SegmentCache);
- (*Ring)->SegmentCache = NULL;
-fail6:
- Error("fail6\n");
-fail5:
- Error("fail5\n");
- XENBUS_CACHE(Destroy,
- &(*Ring)->CacheInterface,
- (*Ring)->RequestCache);
- (*Ring)->RequestCache = NULL;
-fail4:
- Error("fail4\n");
fail3:
Error("fail3\n");
- XENBUS_CACHE(Release,
- &(*Ring)->CacheInterface);
+
+ while (--Index > 0) {
+ PXENVBD_BLKIF_RING BlkifRing = (*Ring)->Ring[Index];
+
+ (*Ring)->Ring[Index] = NULL;
+ BlkifRingDestroy(BlkifRing);
+ }
+
+ __RingFree((*Ring)->Ring);
+ (*Ring)->Ring = NULL;
+
fail2:
Error("fail2\n");
+ (*Ring)->Frontend = NULL;
+
RtlZeroMemory(&(*Ring)->CacheInterface,
- sizeof (XENBUS_CACHE_INTERFACE));
+ sizeof(XENBUS_CACHE_INTERFACE));
+
+ RtlZeroMemory(&(*Ring)->EvtchnInterface,
+ sizeof(XENBUS_EVTCHN_INTERFACE));
- RtlZeroMemory(&(*Ring)->PreparedReqs, sizeof(XENVBD_QUEUE));
- RtlZeroMemory(&(*Ring)->SubmittedReqs, sizeof(XENVBD_QUEUE));
- RtlZeroMemory(&(*Ring)->ShutdownSrbs, sizeof(XENVBD_QUEUE));
+ RtlZeroMemory(&(*Ring)->StoreInterface,
+ sizeof(XENBUS_STORE_INTERFACE));
- RtlZeroMemory(&(*Ring)->Dpc, sizeof(KDPC));
- RtlZeroMemory(&(*Ring)->Lock, sizeof(KSPIN_LOCK));
- (*Ring)->Frontend = NULL;
+ RtlZeroMemory(&(*Ring)->DebugInterface,
+ sizeof(XENBUS_DEBUG_INTERFACE));
ASSERT(IsZeroMemory(*Ring, sizeof(XENVBD_RING)));
__RingFree(*Ring);
- *Ring = NULL;
+
fail1:
- Error("fail1 %08x\n", status);
+ Error("fail1 (%08x)\n", status);
return status;
}
IN PXENVBD_RING Ring
)
{
- XENBUS_CACHE(Destroy,
- &Ring->CacheInterface,
- Ring->IndirectCache);
- Ring->IndirectCache = NULL;
+ ULONG Index;
- XENBUS_CACHE(Destroy,
- &Ring->CacheInterface,
- Ring->SegmentCache);
- Ring->SegmentCache = NULL;
+ Index = FrontendGetMaxQueues(Ring->Frontend);
- XENBUS_CACHE(Destroy,
- &Ring->CacheInterface,
- Ring->RequestCache);
- Ring->RequestCache = NULL;
+ while (--Index > 0) {
+ PXENVBD_BLKIF_RING BlkifRing = Ring->Ring[Index];
+
+ Ring->Ring[Index] = NULL;
+ BlkifRingDestroy(BlkifRing);
+ }
+
+ __RingFree(Ring->Ring);
+ Ring->Ring = NULL;
- XENBUS_CACHE(Release,
- &Ring->CacheInterface);
+ Ring->Frontend = NULL;
RtlZeroMemory(&Ring->CacheInterface,
- sizeof (XENBUS_CACHE_INTERFACE));
+ sizeof(XENBUS_CACHE_INTERFACE));
- RtlZeroMemory(&Ring->PreparedReqs, sizeof(XENVBD_QUEUE));
- RtlZeroMemory(&Ring->SubmittedReqs, sizeof(XENVBD_QUEUE));
- RtlZeroMemory(&Ring->ShutdownSrbs, sizeof(XENVBD_QUEUE));
+ RtlZeroMemory(&Ring->EvtchnInterface,
+ sizeof(XENBUS_EVTCHN_INTERFACE));
- RtlZeroMemory(&Ring->Dpc, sizeof(KDPC));
- RtlZeroMemory(&Ring->Lock, sizeof(KSPIN_LOCK));
- Ring->Frontend = NULL;
+ RtlZeroMemory(&Ring->StoreInterface,
+ sizeof(XENBUS_STORE_INTERFACE));
+
+ RtlZeroMemory(&Ring->DebugInterface,
+ sizeof(XENBUS_DEBUG_INTERFACE));
- Ring->BlkOpRead = 0;
- Ring->BlkOpWrite = 0;
- Ring->BlkOpIndirectRead = 0;
- Ring->BlkOpIndirectWrite = 0;
- Ring->BlkOpBarrier = 0;
- Ring->BlkOpDiscard = 0;
- Ring->BlkOpFlush = 0;
- Ring->SegsGranted = 0;
- Ring->SegsBounced = 0;
+ RtlZeroMemory(Ring->Stats, sizeof(Ring->Stats));
ASSERT(IsZeroMemory(Ring, sizeof(XENVBD_RING)));
__RingFree(Ring);
IN PXENVBD_RING Ring
)
{
- PXENVBD_TARGET Target = FrontendGetTarget(Ring->Frontend);
- PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target);
- PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
- PCHAR Buffer;
+ ULONG MaxQueues;
ULONG Index;
+ PCHAR Buffer;
NTSTATUS status;
- ASSERT(Ring->Connected == FALSE);
-
- AdapterGetStoreInterface(Adapter, &Ring->StoreInterface);
- AdapterGetEvtchnInterface(Adapter, &Ring->EvtchnInterface);
- AdapterGetDebugInterface(Adapter, &Ring->DebugInterface);
-
- status = XENBUS_STORE(Acquire, &Ring->StoreInterface);
+ status = XENBUS_DEBUG(Acquire, &Ring->DebugInterface);
if (!NT_SUCCESS(status))
goto fail1;
- status = XENBUS_EVTCHN(Acquire, &Ring->EvtchnInterface);
+ status = XENBUS_STORE(Acquire, &Ring->StoreInterface);
if (!NT_SUCCESS(status))
goto fail2;
- status = XENBUS_DEBUG(Acquire, &Ring->DebugInterface);
+ status = XENBUS_CACHE(Acquire, &Ring->CacheInterface);
if (!NT_SUCCESS(status))
goto fail3;
+ status = XENBUS_EVTCHN(Acquire, &Ring->EvtchnInterface);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
status = XENBUS_STORE(Read,
&Ring->StoreInterface,
NULL,
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)
+ MaxQueues = FrontendGetNumQueues(Ring->Frontend);
+ Index = 0;
+ while (Index < MaxQueues) {
+ PXENVBD_BLKIF_RING BlkifRing = Ring->Ring[Index];
- for (Index = 0; Index < (1ul << Ring->Order); ++Index) {
- status = GranterGet(Granter,
- MmGetMdlPfnArray(Ring->Mdl)[Index],
- FALSE,
- &Ring->Grants[Index]);
+ status = BlkifRingConnect(BlkifRing);
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);
+ ++Index;
+ }
status = XENBUS_DEBUG(Register,
&Ring->DebugInterface,
Ring,
&Ring->DebugCallback);
if (!NT_SUCCESS(status))
- goto fail7;
+ goto fail6;
- Ring->Connected = TRUE;
return STATUS_SUCCESS;
-fail7:
- Error("fail7\n");
- XENBUS_EVTCHN(Close,
- &Ring->EvtchnInterface,
- Ring->Channel);
- Ring->Channel = NULL;
fail6:
Error("fail6\n");
+ Index = FrontendGetNumQueues(Ring->Frontend);
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;
- }
+ while (Index != 0) {
+ PXENVBD_BLKIF_RING BlkifRing;
+
+ --Index;
+ BlkifRing = Ring->Ring[Index];
- RtlZeroMemory(&Ring->Front, sizeof(blkif_front_ring_t));
+ BlkifRingDisconnect(BlkifRing);
+ }
- __FreePages(Ring->Mdl);
- Ring->Shared = NULL;
- Ring->Mdl = NULL;
+ XENBUS_EVTCHN(Release, &Ring->EvtchnInterface);
- Ring->Order = 0;
fail4:
Error("fail4\n");
- XENBUS_DEBUG(Release, &Ring->DebugInterface);
+
+ XENBUS_CACHE(Release, &Ring->CacheInterface);
+
fail3:
Error("fail3\n");
- XENBUS_EVTCHN(Release, &Ring->EvtchnInterface);
+
+ XENBUS_STORE(Release, &Ring->StoreInterface);
+
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));
+ XENBUS_DEBUG(Release, &Ring->DebugInterface);
+fail1:
+ Error("fail1 (%08x)\n", status);
return status;
}
IN PVOID Transaction
)
{
- PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend);
- ULONG Port;
+ ULONG NumQueues;
+ ULONG Index;
NTSTATUS status;
- if (Ring->Order == 0) {
- status = XENBUS_STORE(Printf,
- &Ring->StoreInterface,
- Transaction,
- FrontendGetFrontendPath(Ring->Frontend),
- "ring-ref",
- "%u",
- GranterReference(Granter, Ring->Grants[0]));
+ NumQueues = FrontendGetNumQueues(Ring->Frontend);
+ Index = 0;
+ while (Index < NumQueues) {
+ PXENVBD_BLKIF_RING BlkifRing = Ring->Ring[Index];
+
+ status = BlkifRingStoreWrite(BlkifRing, Transaction);
if (!NT_SUCCESS(status))
- return status;
- } else {
- ULONG Index;
+ goto fail1;
+
+ ++Index;
+ }
+
+ status = XENBUS_STORE(Printf,
+ &Ring->StoreInterface,
+ Transaction,
+ FrontendGetFrontendPath(Ring->Frontend),
+ "multi-queue-num-queues",
+ "%u",
+ NumQueues);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+ if (Ring->Order != 0) {
status = XENBUS_STORE(Printf,
&Ring->StoreInterface,
Transaction,
"%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;
- }
+ goto fail3;
}
status = XENBUS_STORE(Printf,
"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;
+ goto fail4;
return STATUS_SUCCESS;
+
+fail4:
+fail3:
+fail2:
+fail1:
+ return status;
}
VOID
IN PXENVBD_RING Ring
)
{
- ASSERT(Ring->Enabled == FALSE);
- Ring->Enabled = TRUE;
+ ULONG NumQueues;
+ ULONG Index;
- XENBUS_EVTCHN(Trigger,
- &Ring->EvtchnInterface,
- Ring->Channel);
+ NumQueues = FrontendGetNumQueues(Ring->Frontend);
+ Index = 0;
+ while (Index < NumQueues) {
+ PXENVBD_BLKIF_RING BlkifRing = Ring->Ring[Index];
+
+ BlkifRingEnable(BlkifRing);
+
+ ++Index;
+ }
}
VOID
IN PXENVBD_RING Ring
)
{
- ULONG Count;
- KIRQL Irql;
- PXENVBD_TARGET Target = FrontendGetTarget(Ring->Frontend);
- PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target);
-
- ASSERT(Ring->Enabled == TRUE);
- Ring->Enabled = FALSE;
-
- // poll ring and send event channel notification every 1ms (for up to 3 minutes)
- Count = 0;
- while (QueueCount(&Ring->SubmittedReqs)) {
- if (Count > 180000)
- break;
- KeRaiseIrql(DISPATCH_LEVEL, &Irql);
- RingPoll(Ring);
- KeLowerIrql(Irql);
- XENBUS_EVTCHN(Send,
- &Ring->EvtchnInterface,
- Ring->Channel);
- StorPortStallExecution(1000); // 1000 micro-seconds
- ++Count;
- }
-
- Verbose("Target[%d] : %u Submitted requests left (%u iterrations)\n",
- FrontendGetTargetId(Ring->Frontend),
- QueueCount(&Ring->SubmittedReqs),
- Count);
-
- // Fail PreparedReqs
- for (;;) {
- PXENVBD_SRBEXT SrbExt;
- PSCSI_REQUEST_BLOCK Srb;
- PXENVBD_REQUEST Request;
- PLIST_ENTRY ListEntry;
-
- ListEntry = QueuePop(&Ring->PreparedReqs);
- if (ListEntry == NULL)
- break;
- Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry);
- SrbExt = Request->SrbExt;
- Srb = SrbExt->Srb;
-
- Srb->SrbStatus = SRB_STATUS_ABORTED;
- Srb->ScsiStatus = 0x40; // SCSI_ABORTED
+ ULONG Index;
- RingPutRequest(Ring, Request);
+ Index = FrontendGetNumQueues(Ring->Frontend);
+ while (Index != 0) {
+ PXENVBD_BLKIF_RING BlkifRing;
- if (InterlockedDecrement(&SrbExt->RequestCount) == 0)
- AdapterCompleteSrb(Adapter, SrbExt);
+ --Index;
+ BlkifRing = Ring->Ring[Index];
+ BlkifRingDisable(BlkifRing);
}
}
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;
+ Index = FrontendGetNumQueues(Ring->Frontend);
- GranterPut(Granter, Ring->Grants[Index]);
- Ring->Grants[Index] = NULL;
- }
+ while (Index != 0) {
+ PXENVBD_BLKIF_RING BlkifRing;
- RtlZeroMemory(&Ring->Front, sizeof(blkif_front_ring_t));
+ --Index;
+ BlkifRing = Ring->Ring[Index];
- __FreePages(Ring->Mdl);
- Ring->Shared = NULL;
- Ring->Mdl = NULL;
+ BlkifRingDisconnect(BlkifRing);
+ }
Ring->Order = 0;
- XENBUS_DEBUG(Release, &Ring->DebugInterface);
XENBUS_EVTCHN(Release, &Ring->EvtchnInterface);
+ XENBUS_CACHE(Release, &Ring->CacheInterface);
XENBUS_STORE(Release, &Ring->StoreInterface);
+ XENBUS_DEBUG(Release, &Ring->DebugInterface);
+}
- RtlZeroMemory(&Ring->DebugInterface,
- sizeof(XENBUS_DEBUG_INTERFACE));
- RtlZeroMemory(&Ring->EvtchnInterface,
- sizeof(XENBUS_EVTCHN_INTERFACE));
- RtlZeroMemory(&Ring->StoreInterface,
- sizeof(XENBUS_STORE_INTERFACE));
+static FORCEINLINE PXENVBD_BLKIF_RING
+__RingGetBlkifRing(
+ IN PXENVBD_RING Ring,
+ IN ULONG Tag
+ )
+{
+ ULONG Value;
+ ULONG Index;
+
+ if (Tag == 0)
+ Value = KeGetCurrentProcessorNumberEx(NULL);
+ else
+ Value = Tag;
+
+ Index = Value % FrontendGetNumQueues(Ring->Frontend);
- Ring->Events = 0;
- Ring->Dpcs = 0;
- Ring->Submitted = 0;
- Ring->Received = 0;
+ return Ring->Ring[Index];
}
BOOLEAN
)
{
PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb;
+ PXENVBD_BLKIF_RING BlkifRing;
- if (!Ring->Enabled)
- goto fail1;
-
- if (!RingPrepareRequest(Ring, SrbExt))
- goto fail2;
+ BlkifRing = __RingGetBlkifRing(Ring, Srb->QueueTag);
+ ASSERT(BlkifRing != NULL);
- if (RingSubmitRequests(Ring)) {
- // more prepared-reqs to submit
- if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
- ++Ring->Dpcs;
- }
+ __BlkifRingQueueSrb(BlkifRing, SrbExt);
return TRUE;
-
-fail2:
-fail1:
- Srb->SrbStatus = SRB_STATUS_BUSY;
- return FALSE;
}
VOID
IN PXENVBD_SRBEXT SrbExt
)
{
- QueueAppend(&Ring->ShutdownSrbs,
- &SrbExt->ListEntry);
+ PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb;
+ PXENVBD_BLKIF_RING BlkifRing;
- if (!Ring->Enabled)
- return;
+ BlkifRing = __RingGetBlkifRing(Ring, Srb->QueueTag);
+ ASSERT(BlkifRing != NULL);
- if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
- ++Ring->Dpcs;
+ __BlkifRingQueueShutdown(BlkifRing, SrbExt);
}