[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH 3/7] Move request prepare/cleanup to ring
From: Owen Smith <owen.smith@xxxxxxxxxx> Keep the blkif protocol related functions in the ring code, and keep the target code related to SCSI operations Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx> --- src/xenvbd/frontend.c | 42 +- src/xenvbd/frontend.h | 12 +- src/xenvbd/ring.c | 1550 +++++++++++++++++++++++++++++++++++++++++++------ src/xenvbd/ring.h | 22 +- src/xenvbd/target.c | 1281 +--------------------------------------- src/xenvbd/target.h | 12 - 6 files changed, 1434 insertions(+), 1485 deletions(-) diff --git a/src/xenvbd/frontend.c b/src/xenvbd/frontend.c index fca360a..5014593 100644 --- a/src/xenvbd/frontend.c +++ b/src/xenvbd/frontend.c @@ -260,21 +260,6 @@ out: //============================================================================= __drv_requiresIRQL(DISPATCH_LEVEL) -BOOLEAN -FrontendNotifyResponses( - __in PXENVBD_FRONTEND Frontend - ) -{ - BOOLEAN Retry = FALSE; - - Retry |= RingPoll(Frontend->Ring); - Retry |= TargetSubmitRequests(Frontend->Target); - - return Retry; -} - -//============================================================================= -__drv_requiresIRQL(DISPATCH_LEVEL) static NTSTATUS __UpdateBackendPath( __in PXENVBD_FRONTEND Frontend @@ -1574,6 +1559,33 @@ FrontendBackend( } NTSTATUS +FrontendReset( + IN PXENVBD_FRONTEND Frontend + ) +{ + XENVBD_STATE PreviousState = Frontend->State; + NTSTATUS status; + + if (PreviousState != XENVBD_ENABLED) + goto done; + + status = FrontendSetState(Frontend, XENVBD_CLOSED); + if (!NT_SUCCESS(status)) + goto fail1; + + status = FrontendSetState(Frontend, PreviousState); + if (!NT_SUCCESS(status)) + goto fail2; + +done: + return STATUS_SUCCESS; + +fail2: +fail1: + return status; +} + +NTSTATUS FrontendCreate( IN PXENVBD_TARGET Target, IN PCHAR DeviceId, diff --git a/src/xenvbd/frontend.h b/src/xenvbd/frontend.h index 49c121c..d608fef 100644 --- a/src/xenvbd/frontend.h +++ b/src/xenvbd/frontend.h @@ -108,13 +108,6 @@ FrontendWriteUsage( __in PXENVBD_FRONTEND Frontend ); -// Ring -__drv_requiresIRQL(DISPATCH_LEVEL) -extern BOOLEAN -FrontendNotifyResponses( - __in PXENVBD_FRONTEND Frontend - ); - // Init/Term __checkReturn __drv_maxIRQL(DISPATCH_LEVEL) @@ -137,6 +130,11 @@ FrontendSetState( ); extern NTSTATUS +FrontendReset( + IN PXENVBD_FRONTEND Frontend + ); + +extern NTSTATUS FrontendCreate( IN PXENVBD_TARGET Target, IN PCHAR DeviceId, diff --git a/src/xenvbd/ring.c b/src/xenvbd/ring.c index eb5fcc7..ffd271d 100755 --- a/src/xenvbd/ring.c +++ b/src/xenvbd/ring.c @@ -30,9 +30,11 @@ */ #include <ntddk.h> +#include <storport.h> #include <stdlib.h> #include <ntstrsafe.h> +#include <xencdb.h> #include <store_interface.h> #include <evtchn_interface.h> #include <debug_interface.h> @@ -44,6 +46,8 @@ #include "srbext.h" #include "driver.h" #include "granter.h" +#include "queue.h" +#include "buffer.h" #include "util.h" #include "debug.h" @@ -53,6 +57,14 @@ #define XENVBD_MAX_RING_PAGE_ORDER (4) #define XENVBD_MAX_RING_PAGES (1 << XENVBD_MAX_RING_PAGE_ORDER) +typedef struct _XENVBD_LOOKASIDE { + LONG Used; + LONG Max; + ULONG Failed; + ULONG Size; + NPAGED_LOOKASIDE_LIST List; +} XENVBD_LOOKASIDE, *PXENVBD_LOOKASIDE; + struct _XENVBD_RING { PXENVBD_FRONTEND Frontend; BOOLEAN Connected; @@ -75,16 +87,112 @@ struct _XENVBD_RING { KDPC TimerDpc; KTIMER Timer; + XENVBD_LOOKASIDE RequestList; + XENVBD_LOOKASIDE SegmentList; + XENVBD_LOOKASIDE IndirectList; + XENVBD_QUEUE FreshSrbs; + XENVBD_QUEUE PreparedReqs; + XENVBD_QUEUE SubmittedReqs; + XENVBD_QUEUE ShutdownSrbs; + ULONG NextTag; + 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; }; #define MAX_NAME_LEN 64 #define RING_POOL_TAG 'gnRX' +#define REQUEST_POOL_TAG 'qeRX' +#define SEGMENT_POOL_TAG 'geSX' +#define INDIRECT_POOL_TAG 'dnIX' #define XEN_IO_PROTO_ABI "x86_64-abi" +static FORCEINLINE VOID +__LookasideInit( + IN OUT PXENVBD_LOOKASIDE Lookaside, + IN ULONG Size, + IN ULONG Tag + ) +{ + RtlZeroMemory(Lookaside, sizeof(XENVBD_LOOKASIDE)); + Lookaside->Size = Size; + ExInitializeNPagedLookasideList(&Lookaside->List, NULL, NULL, 0, + Size, Tag, 0); +} + +static FORCEINLINE VOID +__LookasideTerm( + IN PXENVBD_LOOKASIDE Lookaside + ) +{ + ASSERT3U(Lookaside->Used, ==, 0); + ExDeleteNPagedLookasideList(&Lookaside->List); + RtlZeroMemory(Lookaside, sizeof(XENVBD_LOOKASIDE)); +} + +static FORCEINLINE PVOID +__LookasideAlloc( + IN PXENVBD_LOOKASIDE Lookaside + ) +{ + LONG Result; + PVOID Buffer; + + Buffer = ExAllocateFromNPagedLookasideList(&Lookaside->List); + if (Buffer == NULL) { + ++Lookaside->Failed; + return NULL; + } + + RtlZeroMemory(Buffer, Lookaside->Size); + Result = InterlockedIncrement(&Lookaside->Used); + ASSERT3S(Result, >, 0); + if (Result > Lookaside->Max) + Lookaside->Max = Result; + + return Buffer; +} + +static FORCEINLINE VOID +__LookasideFree( + IN PXENVBD_LOOKASIDE Lookaside, + IN PVOID Buffer + ) +{ + LONG Result; + + ExFreeToNPagedLookasideList(&Lookaside->List, Buffer); + Result = InterlockedDecrement(&Lookaside->Used); + ASSERT3S(Result, >=, 0); +} + +static FORCEINLINE VOID +__LookasideDebug( + IN PXENVBD_LOOKASIDE Lookaside, + IN PXENBUS_DEBUG_INTERFACE Debug, + IN PCHAR Name + ) +{ + XENBUS_DEBUG(Printf, Debug, + "LOOKASIDE: %s: %u / %u (%u failed)\n", + Name, Lookaside->Used, + Lookaside->Max, Lookaside->Failed); + + Lookaside->Max = Lookaside->Used; + Lookaside->Failed = 0; +} + static FORCEINLINE PVOID __RingAllocate( IN ULONG Length @@ -177,84 +285,1101 @@ __RingInsert( 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); + 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; +} + +static PXENVBD_INDIRECT +RingGetIndirect( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_INDIRECT Indirect; + NTSTATUS status; + PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend); + + Indirect = __LookasideAlloc(&Ring->IndirectList); + if (Indirect == NULL) + goto fail1; + + RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); + + Indirect->Mdl = __AllocatePage(); + if (Indirect->Mdl == NULL) + goto fail2; + + Indirect->Page = MmGetSystemAddressForMdlSafe(Indirect->Mdl, + NormalPagePriority); + + status = GranterGet(Granter, + MmGetMdlPfnArray(Indirect->Mdl)[0], + TRUE, + &Indirect->Grant); + if (!NT_SUCCESS(status)) + goto fail3; + + return Indirect; + +fail3: + __FreePage(Indirect->Mdl); +fail2: + __LookasideFree(&Ring->IndirectList, Indirect); +fail1: + return NULL; +} + +static VOID +RingPutIndirect( + IN PXENVBD_RING Ring, + IN PXENVBD_INDIRECT Indirect + ) +{ + PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend); + + if (Indirect->Grant) + GranterPut(Granter, Indirect->Grant); + if (Indirect->Page) + __FreePage(Indirect->Mdl); + + RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); + __LookasideFree(&Ring->IndirectList, Indirect); +} + +static PXENVBD_SEGMENT +RingGetSegment( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_SEGMENT Segment; + + Segment = __LookasideAlloc(&Ring->SegmentList); + if (Segment == NULL) + goto fail1; + + RtlZeroMemory(Segment, sizeof(XENVBD_SEGMENT)); + return Segment; + +fail1: + return NULL; +} + +static VOID +RingPutSegment( + IN PXENVBD_RING Ring, + IN PXENVBD_SEGMENT Segment + ) +{ + PXENVBD_GRANTER Granter = FrontendGetGranter(Ring->Frontend); + + if (Segment->Grant) + GranterPut(Granter, Segment->Grant); + + if (Segment->BufferId) + BufferPut(Segment->BufferId); + + if (Segment->Buffer) + MmUnmapLockedPages(Segment->Buffer, &Segment->Mdl); + + RtlZeroMemory(Segment, sizeof(XENVBD_SEGMENT)); + __LookasideFree(&Ring->SegmentList, Segment); +} + +static PXENVBD_REQUEST +RingGetRequest( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_REQUEST Request; + + Request = __LookasideAlloc(&Ring->RequestList); + if (Request == NULL) + goto fail1; + + RtlZeroMemory(Request, sizeof(XENVBD_REQUEST)); + Request->Id = (ULONG)InterlockedIncrement((PLONG)&Ring->NextTag); + InitializeListHead(&Request->Segments); + InitializeListHead(&Request->Indirects); + + return Request; + +fail1: + return NULL; +} + +static VOID +RingPutRequest( + IN PXENVBD_RING Ring, + IN PXENVBD_REQUEST Request + ) +{ + PLIST_ENTRY Entry; + + for (;;) { + PXENVBD_SEGMENT Segment; + + Entry = RemoveHeadList(&Request->Segments); + if (Entry == &Request->Segments) + break; + Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); + RingPutSegment(Ring, Segment); + } + + for (;;) { + PXENVBD_INDIRECT Indirect; + + Entry = RemoveHeadList(&Request->Indirects); + if (Entry == &Request->Indirects) + break; + Indirect = CONTAINING_RECORD(Entry, XENVBD_INDIRECT, Entry); + RingPutIndirect(Ring, Indirect); + } + + RtlZeroMemory(Request, sizeof(XENVBD_REQUEST)); + __LookasideFree(&Ring->RequestList, Request); +} + +static FORCEINLINE PXENVBD_REQUEST +RingRequestFromTag( + IN PXENVBD_RING Ring, + IN ULONG Tag + ) +{ + KIRQL Irql; + PLIST_ENTRY Entry; + PXENVBD_QUEUE Queue = &Ring->SubmittedReqs; + + KeAcquireSpinLock(&Queue->Lock, &Irql); + + for (Entry = Queue->List.Flink; Entry != &Queue->List; Entry = Entry->Flink) { + PXENVBD_REQUEST Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + if (Request->Id == Tag) { + RemoveEntryList(&Request->Entry); + --Queue->Current; + KeReleaseSpinLock(&Queue->Lock, Irql); + return Request; + } + } + + KeReleaseSpinLock(&Queue->Lock, Irql); + Warning("Target[%d] : Tag %x not found in submitted list (%u items)\n", + FrontendGetTargetId(Ring->Frontend), + Tag, + QueueCount(Queue)); + return NULL; +} + +static FORCEINLINE VOID +__RingIncBlkifOpCount( + IN PXENVBD_RING Ring, + IN PXENVBD_REQUEST Request + ) +{ + 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; + } +} + +static FORCEINLINE ULONG +__RingSectorsPerPage( + IN ULONG SectorSize + ) +{ + ASSERT3U(SectorSize, !=, 0); + return PAGE_SIZE / SectorSize; +} + +static FORCEINLINE VOID +__RingOperation( + IN UCHAR CdbOp, + OUT PUCHAR RingOp, + OUT PBOOLEAN ReadOnly + ) +{ + switch (CdbOp) { + case SCSIOP_READ: + *RingOp = BLKIF_OP_READ; + *ReadOnly = FALSE; + break; + case SCSIOP_WRITE: + *RingOp = BLKIF_OP_WRITE; + *ReadOnly = TRUE; + break; + default: + ASSERT(FALSE); + } +} + +static FORCEINLINE MM_PAGE_PRIORITY +__RingPriority( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_CAPS Caps = FrontendGetCaps(Ring->Frontend); + if (!(Caps->Paging || + Caps->Hibernation || + Caps->DumpFile)) + return NormalPagePriority; + + return HighPagePriority; +} + +static FORCEINLINE VOID +RingRequestCopyOutput( + IN PXENVBD_REQUEST Request + ) +{ + PLIST_ENTRY Entry; + + if (Request->Operation != BLKIF_OP_READ) + return; + + for (Entry = Request->Segments.Flink; + Entry != &Request->Segments; + Entry = Entry->Flink) { + PXENVBD_SEGMENT Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); + + if (Segment->BufferId) + BufferCopyOut(Segment->BufferId, Segment->Buffer, Segment->Length); + } +} + +static BOOLEAN +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); + + Pfn = AdapterGetNextSGEntry(TargetGetAdapter(Target), + SrbExt, + 0, + &Offset, + &Length); + if ((Offset & (SectorSize - 1)) == 0 && + (Length & (SectorSize - 1)) == 0) { + ++Ring->SegsGranted; + // 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->BufferId = NULL; // granted, ensure its null + Segment->Buffer = NULL; // granted, ensure its null + Segment->Length = 0; // granted, ensure its 0 + + ASSERT3U((Length / SectorSize), ==, *SectorsNow); + } else { + PMDL Mdl; + + ++Ring->SegsBounced; + // get first sector, last sector and count + Segment->FirstSector = 0; + *SectorsNow = __min(SectorsLeft, SectorsPerPage); + Segment->LastSector = (UCHAR)(*SectorsNow - 1); + + // map SGList to Virtual Address. Populates Segment->Buffer and Segment->Length +#pragma warning(push) +#pragma warning(disable:28145) + Mdl = &Segment->Mdl; + Mdl->Next = NULL; + Mdl->Size = (SHORT)(sizeof(MDL) + sizeof(PFN_NUMBER)); + Mdl->MdlFlags = MDL_PAGES_LOCKED; + Mdl->Process = NULL; + Mdl->MappedSystemVa = NULL; + Mdl->StartVa = NULL; + Mdl->ByteCount = Length; + Mdl->ByteOffset = Offset; + Segment->Pfn[0] = Pfn; + + if (Length < *SectorsNow * SectorSize) { + Pfn = AdapterGetNextSGEntry(TargetGetAdapter(Target), + SrbExt, + Length, + &Offset, + &Length); + Mdl->Size += sizeof(PFN_NUMBER); + Mdl->ByteCount = Mdl->ByteCount + Length; + Segment->Pfn[1] = Pfn; + } +#pragma warning(pop) + + ASSERT((Mdl->ByteCount & (SectorSize - 1)) == 0); + ASSERT3U(Mdl->ByteCount, <=, PAGE_SIZE); + ASSERT3U(*SectorsNow, ==, (Mdl->ByteCount / SectorSize)); + + Segment->Length = __min(Mdl->ByteCount, PAGE_SIZE); + Segment->Buffer = MmMapLockedPagesSpecifyCache(Mdl, KernelMode, + MmCached, NULL, FALSE, __RingPriority(Ring)); + if (!Segment->Buffer) + goto fail1; + + ASSERT3P(MmGetMdlPfnArray(Mdl)[0], ==, Segment->Pfn[0]); + ASSERT3P(MmGetMdlPfnArray(Mdl)[1], ==, Segment->Pfn[1]); + + // get a buffer + if (!BufferGet(Segment, &Segment->BufferId, &Pfn)) + goto fail2; + + // copy contents in + if (ReadOnly) { // Operation == BLKIF_OP_WRITE + BufferCopyIn(Segment->BufferId, Segment->Buffer, Segment->Length); + } + } + + // Grant segment's page + Status = GranterGet(Granter, Pfn, ReadOnly, &Segment->Grant); + if (!NT_SUCCESS(Status)) + goto fail3; + + return TRUE; + +fail3: +fail2: +fail1: + 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 + ) +{ + UCHAR Operation; + BOOLEAN ReadOnly; + ULONG Index; + __RingOperation(Cdb_OperationEx(Request->Srb), &Operation, &ReadOnly); + + Request->Operation = Operation; + Request->NrSegments = 0; + Request->FirstSector = SectorStart; + + for (Index = 0; + Index < MaxSegments && + SectorsLeft > 0; + ++Index) { + PXENVBD_SEGMENT Segment; + ULONG SectorsNow; + + Segment = RingGetSegment(Ring); + if (Segment == NULL) + goto fail1; + + InsertTailList(&Request->Segments, &Segment->Entry); + ++Request->NrSegments; + + if (!RingPrepareSegment(Ring, + Segment, + SrbExt, + ReadOnly, + SectorsLeft, + &SectorsNow)) + goto fail2; + + *SectorsDone += SectorsNow; + SectorsLeft -= SectorsNow; + } + ASSERT3U(Request->NrSegments, >, 0); + ASSERT3U(Request->NrSegments, <=, MaxSegments); + + return TRUE; + +fail2: +fail1: + return FALSE; +} + +static BOOLEAN +RingPrepareBlkifIndirect( + IN PXENVBD_RING Ring, + IN PXENVBD_REQUEST Request + ) +{ + ULONG Index; + ULONG NrSegments = 0; + + for (Index = 0; + Index < BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST && + NrSegments < Request->NrSegments; + ++Index) { + PXENVBD_INDIRECT Indirect; + + Indirect = RingGetIndirect(Ring); + if (Indirect == NULL) + goto fail1; + InsertTailList(&Request->Indirects, &Indirect->Entry); + + NrSegments += XENVBD_MAX_SEGMENTS_PER_PAGE; + } + + return TRUE; + +fail1: + return FALSE; +} + +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; + + if (MaxIndirectSegs <= BLKIF_MAX_SEGMENTS_PER_REQUEST) + return BLKIF_MAX_SEGMENTS_PER_REQUEST; // not supported + + if (SectorsLeft < BLKIF_MAX_SEGMENTS_PER_REQUEST * SectorsPerPage) + return BLKIF_MAX_SEGMENTS_PER_REQUEST; // first into a single BLKIF_OP_{READ/WRITE} + + return MaxIndirectSegs; +} + +static FORCEINLINE ULONG +RingQueueRequestList( + IN PXENVBD_RING Ring, + IN PLIST_ENTRY List + ) +{ + ULONG Count = 0; + for (;;) { + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry; + + Entry = RemoveHeadList(List); + if (Entry == List) + break; + + ++Count; + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + __RingIncBlkifOpCount(Ring, Request); + QueueAppend(&Ring->PreparedReqs, &Request->Entry); + } + return Count; +} + +static FORCEINLINE VOID +RingCancelRequestList( + IN PXENVBD_RING Ring, + IN PLIST_ENTRY List + ) +{ + for (;;) { + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry; + + Entry = RemoveHeadList(List); + if (Entry == List) + break; + + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + RingPutRequest(Ring, Request); + } +} + +static BOOLEAN +RingPrepareReadWrite( + IN PXENVBD_RING Ring, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); + ULONG64 SectorStart = Cdb_LogicalBlock(Srb); + ULONG SectorsLeft = Cdb_TransferBlock(Srb); + LIST_ENTRY List; + ULONG DebugCount; + + Srb->SrbStatus = SRB_STATUS_PENDING; + + InitializeListHead(&List); + SrbExt->Count = 0; + + while (SectorsLeft > 0) { + ULONG MaxSegments; + ULONG SectorsDone = 0; + PXENVBD_REQUEST Request; + + Request = RingGetRequest(Ring); + if (Request == NULL) + goto fail1; + InsertTailList(&List, &Request->Entry); + InterlockedIncrement(&SrbExt->Count); + + Request->Srb = Srb; + 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; + } + + DebugCount = RingQueueRequestList(Ring, &List); + if (DebugCount != (ULONG)SrbExt->Count) { + Trace("[%u] %d != %u\n", + FrontendGetTargetId(Ring->Frontend), + SrbExt->Count, + DebugCount); + } + return TRUE; + +fail3: +fail2: +fail1: + RingCancelRequestList(Ring, &List); + SrbExt->Count = 0; + Srb->SrbStatus = SRB_STATUS_ERROR; + return FALSE; +} + +static BOOLEAN +RingPrepareSyncCache( + IN PXENVBD_RING Ring, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); + PXENVBD_REQUEST Request; + LIST_ENTRY List; + UCHAR Operation; + ULONG DebugCount; + + Srb->SrbStatus = SRB_STATUS_PENDING; + + if (FrontendGetDiskInfo(Ring->Frontend)->FlushCache) + Operation = BLKIF_OP_FLUSH_DISKCACHE; + else + Operation = BLKIF_OP_WRITE_BARRIER; + + InitializeListHead(&List); + SrbExt->Count = 0; + + Request = RingGetRequest(Ring); + if (Request == NULL) + goto fail1; + InsertTailList(&List, &Request->Entry); + InterlockedIncrement(&SrbExt->Count); + + Request->Srb = Srb; + Request->Operation = Operation; + Request->FirstSector = Cdb_LogicalBlock(Srb); + + DebugCount = RingQueueRequestList(Ring, &List); + if (DebugCount != (ULONG)SrbExt->Count) { + Trace("[%u] %d != %u\n", + FrontendGetTargetId(Ring->Frontend), + SrbExt->Count, + DebugCount); + } + return TRUE; + +fail1: + RingCancelRequestList(Ring, &List); + SrbExt->Count = 0; + Srb->SrbStatus = SRB_STATUS_ERROR; + return FALSE; +} + +static BOOLEAN +RingPrepareUnmap( + IN PXENVBD_RING Ring, + IN PSCSI_REQUEST_BLOCK Srb + ) +{ + PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); + PUNMAP_LIST_HEADER Unmap = Srb->DataBuffer; + ULONG Count = _byteswap_ushort(*(PUSHORT)Unmap->BlockDescrDataLength) / sizeof(UNMAP_BLOCK_DESCRIPTOR); + ULONG Index; + LIST_ENTRY List; + ULONG DebugCount; + + Srb->SrbStatus = SRB_STATUS_PENDING; + + InitializeListHead(&List); + SrbExt->Count = 0; + + for (Index = 0; Index < Count; ++Index) { + PUNMAP_BLOCK_DESCRIPTOR Descr = &Unmap->Descriptors[Index]; + PXENVBD_REQUEST Request; + + Request = RingGetRequest(Ring); + if (Request == NULL) + goto fail1; + InsertTailList(&List, &Request->Entry); + InterlockedIncrement(&SrbExt->Count); + + Request->Srb = Srb; + Request->Operation = BLKIF_OP_DISCARD; + Request->FirstSector = _byteswap_uint64(*(PULONG64)Descr->StartingLba); + Request->NrSectors = _byteswap_ulong(*(PULONG)Descr->LbaCount); + Request->Flags = 0; + } + + DebugCount = RingQueueRequestList(Ring, &List); + if (DebugCount != (ULONG)SrbExt->Count) { + Trace("[%u] %d != %u\n", + FrontendGetTargetId(Ring->Frontend), + SrbExt->Count, + DebugCount); + } + return TRUE; + +fail1: + RingCancelRequestList(Ring, &List); + SrbExt->Count = 0; + Srb->SrbStatus = SRB_STATUS_ERROR; + return FALSE; +} + +static FORCEINLINE BOOLEAN +RingPrepareFresh( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_SRBEXT SrbExt; + PLIST_ENTRY Entry; + + Entry = QueuePop(&Ring->FreshSrbs); + if (Entry == NULL) + return FALSE; // fresh queue is empty + + SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); + + switch (Cdb_OperationEx(SrbExt->Srb)) { + case SCSIOP_READ: + case SCSIOP_WRITE: + if (RingPrepareReadWrite(Ring, SrbExt->Srb)) + return TRUE; // prepared this SRB + break; + case SCSIOP_SYNCHRONIZE_CACHE: + if (RingPrepareSyncCache(Ring, SrbExt->Srb)) + return TRUE; // prepared this SRB + break; + case SCSIOP_UNMAP: + if (RingPrepareUnmap(Ring, SrbExt->Srb)) + return TRUE; // prepared this SRB + break; + default: + ASSERT(FALSE); + break; + } + QueueUnPop(&Ring->FreshSrbs, &SrbExt->Entry); + + return FALSE; // prepare failed +} + +static 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) { + if (!Ring->Enabled) + return TRUE; + + XENBUS_EVTCHN(Send, + &Ring->EvtchnInterface, + Ring->Channel); + } + + return TRUE; +} + +static FORCEINLINE BOOLEAN +RingSubmitPrepared( + 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 (;;) { + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry; + + Entry = QueuePop(&Ring->PreparedReqs); + if (Entry == NULL) + break; + + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + + QueueAppend(&Ring->SubmittedReqs, &Request->Entry); + KeMemoryBarrier(); + + if (RingSubmit(Ring, Request)) + continue; + + QueueRemove(&Ring->SubmittedReqs, &Request->Entry); + QueueUnPop(&Ring->PreparedReqs, &Request->Entry); + return FALSE; // ring full + } + + return TRUE; +} + +static FORCEINLINE VOID +RingCompleteShutdown( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_TARGET Target; + PXENVBD_ADAPTER Adapter; + + if (QueueCount(&Ring->ShutdownSrbs) == 0) + return; + + if (QueueCount(&Ring->FreshSrbs) || + QueueCount(&Ring->PreparedReqs) || + QueueCount(&Ring->SubmittedReqs)) + return; + + Target = FrontendGetTarget(Ring->Frontend); + Adapter = TargetGetAdapter(Target); + for (;;) { + PXENVBD_SRBEXT SrbExt; + PLIST_ENTRY Entry = QueuePop(&Ring->ShutdownSrbs); + if (Entry == NULL) + break; + SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); + SrbExt->Srb->SrbStatus = SRB_STATUS_SUCCESS; + AdapterCompleteSrb(Adapter, SrbExt); + } +} + +static FORCEINLINE PCHAR +__BlkifOperationName( + IN UCHAR Operation + ) +{ + switch (Operation) { + case BLKIF_OP_READ: return "READ"; + case BLKIF_OP_WRITE: return "WRITE"; + case BLKIF_OP_WRITE_BARRIER: return "WRITE_BARRIER"; + case BLKIF_OP_FLUSH_DISKCACHE: return "FLUSH_DISKCACHE"; + case BLKIF_OP_RESERVED_1: return "RESERVED_1"; + case BLKIF_OP_DISCARD: return "DISCARD"; + case BLKIF_OP_INDIRECT: return "INDIRECT"; + default: return "<unknown>"; + } +} + +static BOOLEAN +RingSubmitRequests( + IN PXENVBD_RING Ring + ) +{ + BOOLEAN Retry = FALSE; + + for (;;) { + // submit all prepared requests (0 or more requests) + // return TRUE if submitted 0 or more requests from prepared queue + // return FALSE iff ring is full + if (!RingSubmitPrepared(Ring)) + break; + + // prepare a single SRB (into 1 or more requests) + // return TRUE if prepare succeeded + // return FALSE if prepare failed or fresh queue empty + if (!RingPrepareFresh(Ring)) + break; + + // back off, check DPC timeout and try again + Retry = TRUE; + break; + } + + // if no requests/SRBs outstanding, complete any shutdown SRBs + if (!Retry) + RingCompleteShutdown(Ring); + + return Retry; +} + +static VOID +RingCompleteResponse( + IN PXENVBD_RING Ring, + IN ULONG Tag, + IN SHORT Status + ) +{ + PXENVBD_REQUEST Request; + PSCSI_REQUEST_BLOCK Srb; + PXENVBD_SRBEXT SrbExt; + + Request = RingRequestFromTag(Ring, Tag); + if (Request == NULL) + return; + + Srb = Request->Srb; + SrbExt = GetSrbExt(Srb); + ASSERT3P(SrbExt, !=, NULL); + + switch (Status) { + case BLKIF_RSP_OKAY: + RingRequestCopyOutput(Request); + break; + + case BLKIF_RSP_EOPNOTSUPP: + // Remove appropriate feature support + FrontendRemoveFeature(Ring->Frontend, Request->Operation); + // Succeed this SRB, subsiquent SRBs will be succeeded instead of being passed to the backend. + Srb->SrbStatus = SRB_STATUS_SUCCESS; + break; + + case BLKIF_RSP_ERROR: + default: + Warning("Target[%d] : %s BLKIF_RSP_ERROR (Tag %x)\n", + FrontendGetTargetId(Ring->Frontend), + __BlkifOperationName(Request->Operation), + Tag); + Srb->SrbStatus = SRB_STATUS_ERROR; + break; + } + + RingPutRequest(Ring, Request); + + // complete srb + if (InterlockedDecrement(&SrbExt->Count) == 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); + } +} + +static BOOLEAN +RingPoll( + IN PXENVBD_RING Ring + ) +{ + 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(); - 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); + if (rsp_cons == rsp_prod || Retry) + break; - req_indirect->indirect_grefs[PageIdx] = GranterReference(Granter, Page->Grant); + while (rsp_cons != rsp_prod && !Retry) { + blkif_response_t* Response; + ULONG Tag; - 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); + Response = RING_GET_RESPONSE(&Ring->Front, rsp_cons); + ++rsp_cons; - Page->Page[SegIdx].GrantRef = GranterReference(Granter, Segment->Grant); - Page->Page[SegIdx].First = Segment->FirstSector; - Page->Page[SegIdx].Last = Segment->LastSector; - } + if (__RingPutTag(Ring, Response->id, &Tag)) { + ++Ring->Received; + RingCompleteResponse(Ring, Tag, Response->status); } - } 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; + RtlZeroMemory(Response, sizeof(union blkif_sring_entry)); - 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; - } + if (rsp_cons - Ring->Front.rsp_cons > RING_SIZE(&Ring->Front) / 4) + Retry = TRUE; } - 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; + KeMemoryBarrier(); - default: - ASSERT(FALSE); - break; + Ring->Front.rsp_cons = rsp_cons; + Ring->Shared->rsp_event = rsp_cons + 1; } - ++Ring->Submitted; + +done: + KeReleaseSpinLockFromDpcLevel(&Ring->Lock); + + return Retry; +} + +__drv_requiresIRQL(DISPATCH_LEVEL) +static BOOLEAN +RingNotifyResponses( + IN PXENVBD_RING Ring + ) +{ + BOOLEAN Retry = FALSE; + + Retry |= RingPoll(Ring); + Retry |= RingSubmitRequests(Ring); + + return Retry; } KSERVICE_ROUTINE RingInterrupt; @@ -334,7 +1459,7 @@ RingDpc( return; for (;;) { - if (!FrontendNotifyResponses(Ring->Frontend)) { + if (!RingNotifyResponses(Ring)) { XENBUS_EVTCHN(Unmask, &Ring->EvtchnInterface, Ring->Channel, @@ -425,6 +1550,51 @@ RingDebugCallback( Ring->Channel, Port); } + + XENBUS_DEBUG(Printf, + &Ring->DebugInterface, + "TARGET: BLKIF_OPs: READ=%u WRITE=%u\n", + Ring->BlkOpRead, + Ring->BlkOpWrite); + XENBUS_DEBUG(Printf, + &Ring->DebugInterface, + "TARGET: BLKIF_OPs: INDIRECT_READ=%u INDIRECT_WRITE=%u\n", + Ring->BlkOpIndirectRead, + Ring->BlkOpIndirectWrite); + XENBUS_DEBUG(Printf, + &Ring->DebugInterface, + "TARGET: BLKIF_OPs: BARRIER=%u DISCARD=%u FLUSH=%u\n", + Ring->BlkOpBarrier, + Ring->BlkOpDiscard, + Ring->BlkOpFlush); + XENBUS_DEBUG(Printf, + &Ring->DebugInterface, + "TARGET: Segments Granted=%llu Bounced=%llu\n", + Ring->SegsGranted, + Ring->SegsBounced); + + __LookasideDebug(&Ring->RequestList, + &Ring->DebugInterface, + "REQUESTs"); + __LookasideDebug(&Ring->SegmentList, + &Ring->DebugInterface, + "SEGMENTs"); + __LookasideDebug(&Ring->IndirectList, + &Ring->DebugInterface, + "INDIRECTs"); + + QueueDebugCallback(&Ring->FreshSrbs, + "Fresh ", + &Ring->DebugInterface); + QueueDebugCallback(&Ring->PreparedReqs, + "Prepared ", + &Ring->DebugInterface); + QueueDebugCallback(&Ring->SubmittedReqs, + "Submitted", + &Ring->DebugInterface); + QueueDebugCallback(&Ring->ShutdownSrbs, + "Shutdown ", + &Ring->DebugInterface); } NTSTATUS @@ -447,6 +1617,14 @@ RingCreate( KeInitializeDpc(&(*Ring)->TimerDpc, RingDpc, *Ring); KeInitializeTimer(&(*Ring)->Timer); + QueueInit(&(*Ring)->FreshSrbs); + QueueInit(&(*Ring)->PreparedReqs); + QueueInit(&(*Ring)->SubmittedReqs); + QueueInit(&(*Ring)->ShutdownSrbs); + __LookasideInit(&(*Ring)->RequestList, sizeof(XENVBD_REQUEST), REQUEST_POOL_TAG); + __LookasideInit(&(*Ring)->SegmentList, sizeof(XENVBD_SEGMENT), SEGMENT_POOL_TAG); + __LookasideInit(&(*Ring)->IndirectList, sizeof(XENVBD_INDIRECT), INDIRECT_POOL_TAG); + return STATUS_SUCCESS; fail1: @@ -459,6 +1637,14 @@ RingDestroy( IN PXENVBD_RING Ring ) { + __LookasideTerm(&Ring->IndirectList); + __LookasideTerm(&Ring->SegmentList); + __LookasideTerm(&Ring->RequestList); + RtlZeroMemory(&Ring->FreshSrbs, sizeof(XENVBD_QUEUE)); + RtlZeroMemory(&Ring->PreparedReqs, sizeof(XENVBD_QUEUE)); + RtlZeroMemory(&Ring->SubmittedReqs, sizeof(XENVBD_QUEUE)); + RtlZeroMemory(&Ring->ShutdownSrbs, sizeof(XENVBD_QUEUE)); + RtlZeroMemory(&Ring->Timer, sizeof(KTIMER)); RtlZeroMemory(&Ring->TimerDpc, sizeof(KDPC)); RtlZeroMemory(&Ring->Dpc, sizeof(KDPC)); @@ -717,9 +1903,66 @@ RingDisable( 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); + + // Abort Fresh SRBs + for (;;) { + PXENVBD_SRBEXT SrbExt; + PLIST_ENTRY Entry = QueuePop(&Ring->FreshSrbs); + if (Entry == NULL) + break; + SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); + + SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; + SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED; + AdapterCompleteSrb(Adapter, SrbExt); + } + + // Fail PreparedReqs + for (;;) { + PXENVBD_SRBEXT SrbExt; + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry = QueuePop(&Ring->PreparedReqs); + if (Entry == NULL) + break; + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + SrbExt = GetSrbExt(Request->Srb); + + SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; + RingPutRequest(Ring, Request); + + if (InterlockedDecrement(&SrbExt->Count) == 0) { + SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED + AdapterCompleteSrb(Adapter, SrbExt); + } + } + // // No new timers can be scheduled once Enabled goes to FALSE. // Cancel any existing ones. @@ -782,101 +2025,28 @@ RingDisconnect( Ring->Received = 0; } -BOOLEAN -RingPoll( +VOID +RingTrigger( 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); + if (!Ring->Enabled) + return; - return Retry; + XENBUS_EVTCHN(Trigger, + &Ring->EvtchnInterface, + Ring->Channel); } -BOOLEAN -RingSubmit( +VOID +RingQueueRequest( IN PXENVBD_RING Ring, - IN PXENVBD_REQUEST Request + IN PXENVBD_SRBEXT SrbExt ) { - 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; -} + QueueAppend(&Ring->FreshSrbs, + &SrbExt->Entry); -VOID -RingKick( - IN PXENVBD_RING Ring - ) -{ if (!Ring->Enabled) return; @@ -885,27 +2055,79 @@ RingKick( } VOID -RingTrigger( - IN PXENVBD_RING Ring +RingQueueShutdown( + IN PXENVBD_RING Ring, + IN PXENVBD_SRBEXT SrbExt ) { + QueueAppend(&Ring->ShutdownSrbs, + &SrbExt->Entry); + if (!Ring->Enabled) return; - XENBUS_EVTCHN(Trigger, - &Ring->EvtchnInterface, - Ring->Channel); + if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL)) + ++Ring->Dpcs; } VOID -RingSend( +RingReQueueRequests( IN PXENVBD_RING Ring ) { - if (!Ring->Enabled) - return; + LIST_ENTRY List; - XENBUS_EVTCHN(Send, - &Ring->EvtchnInterface, - Ring->Channel); + InitializeListHead(&List); + + // pop all submitted requests, cleanup and add associated SRB to a list + for (;;) { + PXENVBD_SRBEXT SrbExt; + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry = QueuePop(&Ring->SubmittedReqs); + if (Entry == NULL) + break; + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + SrbExt = GetSrbExt(Request->Srb); + + RingPutRequest(Ring, Request); + + if (InterlockedDecrement(&SrbExt->Count) == 0) { + InsertTailList(&List, &SrbExt->Entry); + } + } + + // pop all prepared requests, cleanup and add associated SRB to a list + for (;;) { + PXENVBD_SRBEXT SrbExt; + PXENVBD_REQUEST Request; + PLIST_ENTRY Entry = QueuePop(&Ring->PreparedReqs); + if (Entry == NULL) + break; + Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); + SrbExt = GetSrbExt(Request->Srb); + + RingPutRequest(Ring, Request); + + if (InterlockedDecrement(&SrbExt->Count) == 0) { + InsertTailList(&List, &SrbExt->Entry); + } + } + + // foreach SRB in list, put on start of FreshSrbs + for (;;) { + PXENVBD_SRBEXT SrbExt; + PLIST_ENTRY Entry = RemoveTailList(&List); + if (Entry == &List) + break; + SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); + + QueueUnPop(&Ring->FreshSrbs, &SrbExt->Entry); + } + + // now the first set of requests popped off submitted list is the next SRB + // to be popped off the fresh list + + Verbose("Target[%d] : %d Fresh SRBs\n", + FrontendGetTargetId(Ring->Frontend), + QueueCount(&Ring->FreshSrbs)); } diff --git a/src/xenvbd/ring.h b/src/xenvbd/ring.h index 3ac1c71..a39d317 100755 --- a/src/xenvbd/ring.h +++ b/src/xenvbd/ring.h @@ -74,29 +74,25 @@ RingDisconnect( IN PXENVBD_RING Ring ); -extern BOOLEAN -RingPoll( +extern VOID +RingTrigger( IN PXENVBD_RING Ring ); -extern BOOLEAN -RingSubmit( - IN PXENVBD_RING Ring, - IN PXENVBD_REQUEST Request - ); - extern VOID -RingKick( - IN PXENVBD_RING Ring +RingQueueRequest( + IN PXENVBD_RING Ring, + IN PXENVBD_SRBEXT SrbExt ); extern VOID -RingTrigger( - IN PXENVBD_RING Ring +RingQueueShutdown( + IN PXENVBD_RING Ring, + IN PXENVBD_SRBEXT SrbExt ); extern VOID -RingSend( +RingReQueueRequests( IN PXENVBD_RING Ring ); diff --git a/src/xenvbd/target.c b/src/xenvbd/target.c index c0fa4e9..2e30860 100644 --- a/src/xenvbd/target.c +++ b/src/xenvbd/target.c @@ -51,15 +51,6 @@ #define TARGET_SIGNATURE 'odpX' -typedef struct _XENVBD_LOOKASIDE { - KEVENT Empty; - LONG Used; - LONG Max; - ULONG Failed; - ULONG Size; - NPAGED_LOOKASIDE_LIST List; -} XENVBD_LOOKASIDE, *PXENVBD_LOOKASIDE; - struct _XENVBD_TARGET { ULONG Signature; PXENVBD_ADAPTER Adapter; @@ -76,48 +67,16 @@ struct _XENVBD_TARGET { PXENBUS_DEBUG_CALLBACK DebugCallback; PXENBUS_SUSPEND_CALLBACK SuspendCallback; - // State - LONG Paused; - // Eject BOOLEAN WrittenEjected; BOOLEAN EjectRequested; BOOLEAN EjectPending; BOOLEAN Missing; const CHAR* Reason; - - // SRBs - XENVBD_LOOKASIDE RequestList; - XENVBD_LOOKASIDE SegmentList; - XENVBD_LOOKASIDE IndirectList; - XENVBD_QUEUE FreshSrbs; - XENVBD_QUEUE PreparedReqs; - XENVBD_QUEUE SubmittedReqs; - XENVBD_QUEUE ShutdownSrbs; - ULONG NextTag; - - // Stats - SRB Counts by BLKIF_OP_ - ULONG BlkOpRead; - ULONG BlkOpWrite; - ULONG BlkOpIndirectRead; - ULONG BlkOpIndirectWrite; - ULONG BlkOpBarrier; - ULONG BlkOpDiscard; - ULONG BlkOpFlush; - // Stats - Failures - ULONG FailedMaps; - ULONG FailedBounces; - ULONG FailedGrants; - // Stats - Segments - ULONG64 SegsGranted; - ULONG64 SegsBounced; }; //============================================================================= #define TARGET_POOL_TAG 'odPX' -#define REQUEST_POOL_TAG 'qeRX' -#define SEGMENT_POOL_TAG 'geSX' -#define INDIRECT_POOL_TAG 'dnIX' __checkReturn __drv_allocatesMem(mem) @@ -142,89 +101,6 @@ __TargetFree( } //============================================================================= -// Lookasides -static FORCEINLINE VOID -__LookasideInit( - IN OUT PXENVBD_LOOKASIDE Lookaside, - IN ULONG Size, - IN ULONG Tag - ) -{ - RtlZeroMemory(Lookaside, sizeof(XENVBD_LOOKASIDE)); - Lookaside->Size = Size; - KeInitializeEvent(&Lookaside->Empty, SynchronizationEvent, TRUE); - ExInitializeNPagedLookasideList(&Lookaside->List, NULL, NULL, 0, - Size, Tag, 0); -} - -static FORCEINLINE VOID -__LookasideTerm( - IN PXENVBD_LOOKASIDE Lookaside - ) -{ - ASSERT3U(Lookaside->Used, ==, 0); - ExDeleteNPagedLookasideList(&Lookaside->List); - RtlZeroMemory(Lookaside, sizeof(XENVBD_LOOKASIDE)); -} - -static FORCEINLINE PVOID -__LookasideAlloc( - IN PXENVBD_LOOKASIDE Lookaside - ) -{ - LONG Result; - PVOID Buffer; - - Buffer = ExAllocateFromNPagedLookasideList(&Lookaside->List); - if (Buffer == NULL) { - ++Lookaside->Failed; - return NULL; - } - - RtlZeroMemory(Buffer, Lookaside->Size); - Result = InterlockedIncrement(&Lookaside->Used); - ASSERT3S(Result, >, 0); - if (Result > Lookaside->Max) - Lookaside->Max = Result; - KeClearEvent(&Lookaside->Empty); - - return Buffer; -} - -static FORCEINLINE VOID -__LookasideFree( - IN PXENVBD_LOOKASIDE Lookaside, - IN PVOID Buffer - ) -{ - LONG Result; - - ExFreeToNPagedLookasideList(&Lookaside->List, Buffer); - Result = InterlockedDecrement(&Lookaside->Used); - ASSERT3S(Result, >=, 0); - - if (Result == 0) { - KeSetEvent(&Lookaside->Empty, IO_NO_INCREMENT, FALSE); - } -} - -static FORCEINLINE VOID -__LookasideDebug( - IN PXENVBD_LOOKASIDE Lookaside, - IN PXENBUS_DEBUG_INTERFACE Debug, - IN PCHAR Name - ) -{ - XENBUS_DEBUG(Printf, Debug, - "LOOKASIDE: %s: %u / %u (%u failed)\n", - Name, Lookaside->Used, - Lookaside->Max, Lookaside->Failed); - - Lookaside->Max = Lookaside->Used; - Lookaside->Failed = 0; -} - -//============================================================================= // Debug static FORCEINLINE PCHAR __PnpStateName( @@ -337,1011 +213,6 @@ TargetSetDeviceObject( Target->DeviceObject = DeviceObject; } -static FORCEINLINE BOOLEAN -TargetIsPaused( - IN PXENVBD_TARGET Target - ) -{ - BOOLEAN Paused; - KIRQL Irql; - - KeAcquireSpinLock(&Target->Lock, &Irql); - Paused = (Target->Paused > 0); - KeReleaseSpinLock(&Target->Lock, Irql); - - return Paused; -} - -static FORCEINLINE ULONG -TargetSectorSize( - __in PXENVBD_TARGET Target - ) -{ - return FrontendGetDiskInfo(Target->Frontend)->SectorSize; -} - -//============================================================================= -static PXENVBD_INDIRECT -TargetGetIndirect( - IN PXENVBD_TARGET Target - ) -{ - PXENVBD_INDIRECT Indirect; - NTSTATUS status; - PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); - - Indirect = __LookasideAlloc(&Target->IndirectList); - if (Indirect == NULL) - goto fail1; - - RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); - - Indirect->Mdl = __AllocatePage(); - if (Indirect->Mdl == NULL) - goto fail2; - - Indirect->Page = MmGetSystemAddressForMdlSafe(Indirect->Mdl, - NormalPagePriority); - - status = GranterGet(Granter, - MmGetMdlPfnArray(Indirect->Mdl)[0], - TRUE, - &Indirect->Grant); - if (!NT_SUCCESS(status)) - goto fail3; - - return Indirect; - -fail3: - __FreePage(Indirect->Mdl); -fail2: - __LookasideFree(&Target->IndirectList, Indirect); -fail1: - return NULL; -} - -static VOID -TargetPutIndirect( - IN PXENVBD_TARGET Target, - IN PXENVBD_INDIRECT Indirect - ) -{ - PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); - - if (Indirect->Grant) - GranterPut(Granter, Indirect->Grant); - if (Indirect->Page) - __FreePage(Indirect->Mdl); - - RtlZeroMemory(Indirect, sizeof(XENVBD_INDIRECT)); - __LookasideFree(&Target->IndirectList, Indirect); -} - -static PXENVBD_SEGMENT -TargetGetSegment( - IN PXENVBD_TARGET Target - ) -{ - PXENVBD_SEGMENT Segment; - - Segment = __LookasideAlloc(&Target->SegmentList); - if (Segment == NULL) - goto fail1; - - RtlZeroMemory(Segment, sizeof(XENVBD_SEGMENT)); - return Segment; - -fail1: - return NULL; -} - -static VOID -TargetPutSegment( - IN PXENVBD_TARGET Target, - IN PXENVBD_SEGMENT Segment - ) -{ - PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); - - if (Segment->Grant) - GranterPut(Granter, Segment->Grant); - - if (Segment->BufferId) - BufferPut(Segment->BufferId); - - if (Segment->Buffer) - MmUnmapLockedPages(Segment->Buffer, &Segment->Mdl); - - RtlZeroMemory(Segment, sizeof(XENVBD_SEGMENT)); - __LookasideFree(&Target->SegmentList, Segment); -} - -static PXENVBD_REQUEST -TargetGetRequest( - IN PXENVBD_TARGET Target - ) -{ - PXENVBD_REQUEST Request; - - Request = __LookasideAlloc(&Target->RequestList); - if (Request == NULL) - goto fail1; - - RtlZeroMemory(Request, sizeof(XENVBD_REQUEST)); - Request->Id = (ULONG)InterlockedIncrement((PLONG)&Target->NextTag); - InitializeListHead(&Request->Segments); - InitializeListHead(&Request->Indirects); - - return Request; - -fail1: - return NULL; -} - -static VOID -TargetPutRequest( - IN PXENVBD_TARGET Target, - IN PXENVBD_REQUEST Request - ) -{ - PLIST_ENTRY Entry; - - for (;;) { - PXENVBD_SEGMENT Segment; - - Entry = RemoveHeadList(&Request->Segments); - if (Entry == &Request->Segments) - break; - Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); - TargetPutSegment(Target, Segment); - } - - for (;;) { - PXENVBD_INDIRECT Indirect; - - Entry = RemoveHeadList(&Request->Indirects); - if (Entry == &Request->Indirects) - break; - Indirect = CONTAINING_RECORD(Entry, XENVBD_INDIRECT, Entry); - TargetPutIndirect(Target, Indirect); - } - - RtlZeroMemory(Request, sizeof(XENVBD_REQUEST)); - __LookasideFree(&Target->RequestList, Request); -} - -static FORCEINLINE PXENVBD_REQUEST -TargetRequestFromTag( - IN PXENVBD_TARGET Target, - IN ULONG Tag - ) -{ - KIRQL Irql; - PLIST_ENTRY Entry; - PXENVBD_QUEUE Queue = &Target->SubmittedReqs; - - KeAcquireSpinLock(&Queue->Lock, &Irql); - - for (Entry = Queue->List.Flink; Entry != &Queue->List; Entry = Entry->Flink) { - PXENVBD_REQUEST Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - if (Request->Id == Tag) { - RemoveEntryList(&Request->Entry); - --Queue->Current; - KeReleaseSpinLock(&Queue->Lock, Irql); - return Request; - } - } - - KeReleaseSpinLock(&Queue->Lock, Irql); - Warning("Target[%d] : Tag %x not found in submitted list (%u items)\n", - TargetGetTargetId(Target), Tag, QueueCount(Queue)); - return NULL; -} - -static FORCEINLINE VOID -__TargetIncBlkifOpCount( - __in PXENVBD_TARGET Target, - __in PXENVBD_REQUEST Request - ) -{ - switch (Request->Operation) { - case BLKIF_OP_READ: - if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) - ++Target->BlkOpIndirectRead; - else - ++Target->BlkOpRead; - break; - case BLKIF_OP_WRITE: - if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) - ++Target->BlkOpIndirectWrite; - else - ++Target->BlkOpWrite; - break; - case BLKIF_OP_WRITE_BARRIER: - ++Target->BlkOpBarrier; - break; - case BLKIF_OP_DISCARD: - ++Target->BlkOpDiscard; - break; - case BLKIF_OP_FLUSH_DISKCACHE: - ++Target->BlkOpFlush; - break; - default: - ASSERT(FALSE); - break; - } -} - -static FORCEINLINE ULONG -__SectorsPerPage( - __in ULONG SectorSize - ) -{ - ASSERT3U(SectorSize, !=, 0); - return PAGE_SIZE / SectorSize; -} - -static FORCEINLINE VOID -__Operation( - __in UCHAR CdbOp, - __out PUCHAR RingOp, - __out PBOOLEAN ReadOnly - ) -{ - switch (CdbOp) { - case SCSIOP_READ: - *RingOp = BLKIF_OP_READ; - *ReadOnly = FALSE; - break; - case SCSIOP_WRITE: - *RingOp = BLKIF_OP_WRITE; - *ReadOnly = TRUE; - break; - default: - ASSERT(FALSE); - } -} - -static FORCEINLINE MM_PAGE_PRIORITY -__TargetPriority( - __in PXENVBD_TARGET Target - ) -{ - PXENVBD_CAPS Caps = FrontendGetCaps(Target->Frontend); - if (!(Caps->Paging || - Caps->Hibernation || - Caps->DumpFile)) - return NormalPagePriority; - - return HighPagePriority; -} - -static FORCEINLINE VOID -RequestCopyOutput( - __in PXENVBD_REQUEST Request - ) -{ - PLIST_ENTRY Entry; - - if (Request->Operation != BLKIF_OP_READ) - return; - - for (Entry = Request->Segments.Flink; - Entry != &Request->Segments; - Entry = Entry->Flink) { - PXENVBD_SEGMENT Segment = CONTAINING_RECORD(Entry, XENVBD_SEGMENT, Entry); - - if (Segment->BufferId) - BufferCopyOut(Segment->BufferId, Segment->Buffer, Segment->Length); - } -} - -static BOOLEAN -PrepareSegment( - IN PXENVBD_TARGET Target, - IN PXENVBD_SEGMENT Segment, - IN PXENVBD_SRBEXT SrbExt, - IN BOOLEAN ReadOnly, - IN ULONG SectorsLeft, - OUT PULONG SectorsNow - ) -{ - PFN_NUMBER Pfn; - ULONG Offset; - ULONG Length; - NTSTATUS Status; - PXENVBD_GRANTER Granter = FrontendGetGranter(Target->Frontend); - const ULONG SectorSize = TargetSectorSize(Target); - const ULONG SectorsPerPage = __SectorsPerPage(SectorSize); - - Pfn = AdapterGetNextSGEntry(TargetGetAdapter(Target), - SrbExt, - 0, - &Offset, - &Length); - if ((Offset & (SectorSize - 1)) == 0 && - (Length & (SectorSize - 1)) == 0) { - ++Target->SegsGranted; - // 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->BufferId = NULL; // granted, ensure its null - Segment->Buffer = NULL; // granted, ensure its null - Segment->Length = 0; // granted, ensure its 0 - - ASSERT3U((Length / SectorSize), ==, *SectorsNow); - } else { - PMDL Mdl; - - ++Target->SegsBounced; - // get first sector, last sector and count - Segment->FirstSector = 0; - *SectorsNow = __min(SectorsLeft, SectorsPerPage); - Segment->LastSector = (UCHAR)(*SectorsNow - 1); - - // map SGList to Virtual Address. Populates Segment->Buffer and Segment->Length -#pragma warning(push) -#pragma warning(disable:28145) - Mdl = &Segment->Mdl; - Mdl->Next = NULL; - Mdl->Size = (SHORT)(sizeof(MDL) + sizeof(PFN_NUMBER)); - Mdl->MdlFlags = MDL_PAGES_LOCKED; - Mdl->Process = NULL; - Mdl->MappedSystemVa = NULL; - Mdl->StartVa = NULL; - Mdl->ByteCount = Length; - Mdl->ByteOffset = Offset; - Segment->Pfn[0] = Pfn; - - if (Length < *SectorsNow * SectorSize) { - Pfn = AdapterGetNextSGEntry(TargetGetAdapter(Target), - SrbExt, - Length, - &Offset, - &Length); - Mdl->Size += sizeof(PFN_NUMBER); - Mdl->ByteCount = Mdl->ByteCount + Length; - Segment->Pfn[1] = Pfn; - } -#pragma warning(pop) - - ASSERT((Mdl->ByteCount & (SectorSize - 1)) == 0); - ASSERT3U(Mdl->ByteCount, <=, PAGE_SIZE); - ASSERT3U(*SectorsNow, ==, (Mdl->ByteCount / SectorSize)); - - Segment->Length = __min(Mdl->ByteCount, PAGE_SIZE); - Segment->Buffer = MmMapLockedPagesSpecifyCache(Mdl, KernelMode, - MmCached, NULL, FALSE, __TargetPriority(Target)); - if (!Segment->Buffer) { - ++Target->FailedMaps; - goto fail1; - } - - ASSERT3P(MmGetMdlPfnArray(Mdl)[0], ==, Segment->Pfn[0]); - ASSERT3P(MmGetMdlPfnArray(Mdl)[1], ==, Segment->Pfn[1]); - - // get a buffer - if (!BufferGet(Segment, &Segment->BufferId, &Pfn)) { - ++Target->FailedBounces; - goto fail2; - } - - // copy contents in - if (ReadOnly) { // Operation == BLKIF_OP_WRITE - BufferCopyIn(Segment->BufferId, Segment->Buffer, Segment->Length); - } - } - - // Grant segment's page - Status = GranterGet(Granter, Pfn, ReadOnly, &Segment->Grant); - if (!NT_SUCCESS(Status)) { - ++Target->FailedGrants; - goto fail3; - } - - return TRUE; - -fail3: -fail2: -fail1: - return FALSE; -} - -static BOOLEAN -PrepareBlkifReadWrite( - IN PXENVBD_TARGET Target, - IN PXENVBD_REQUEST Request, - IN PXENVBD_SRBEXT SrbExt, - IN ULONG MaxSegments, - IN ULONG64 SectorStart, - IN ULONG SectorsLeft, - OUT PULONG SectorsDone - ) -{ - UCHAR Operation; - BOOLEAN ReadOnly; - ULONG Index; - __Operation(Cdb_OperationEx(Request->Srb), &Operation, &ReadOnly); - - Request->Operation = Operation; - Request->NrSegments = 0; - Request->FirstSector = SectorStart; - - for (Index = 0; - Index < MaxSegments && - SectorsLeft > 0; - ++Index) { - PXENVBD_SEGMENT Segment; - ULONG SectorsNow; - - Segment = TargetGetSegment(Target); - if (Segment == NULL) - goto fail1; - - InsertTailList(&Request->Segments, &Segment->Entry); - ++Request->NrSegments; - - if (!PrepareSegment(Target, - Segment, - SrbExt, - ReadOnly, - SectorsLeft, - &SectorsNow)) - goto fail2; - - *SectorsDone += SectorsNow; - SectorsLeft -= SectorsNow; - } - ASSERT3U(Request->NrSegments, >, 0); - ASSERT3U(Request->NrSegments, <=, MaxSegments); - - return TRUE; - -fail2: -fail1: - return FALSE; -} - -static BOOLEAN -PrepareBlkifIndirect( - IN PXENVBD_TARGET Target, - IN PXENVBD_REQUEST Request - ) -{ - ULONG Index; - ULONG NrSegments = 0; - - for (Index = 0; - Index < BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST && - NrSegments < Request->NrSegments; - ++Index) { - PXENVBD_INDIRECT Indirect; - - Indirect = TargetGetIndirect(Target); - if (Indirect == NULL) - goto fail1; - InsertTailList(&Request->Indirects, &Indirect->Entry); - - NrSegments += XENVBD_MAX_SEGMENTS_PER_PAGE; - } - - return TRUE; - -fail1: - return FALSE; -} - -static FORCEINLINE ULONG -UseIndirect( - IN PXENVBD_TARGET Target, - IN ULONG SectorsLeft - ) -{ - const ULONG SectorsPerPage = __SectorsPerPage(TargetSectorSize(Target)); - const ULONG MaxIndirectSegs = FrontendGetFeatures(Target->Frontend)->Indirect; - - if (MaxIndirectSegs <= BLKIF_MAX_SEGMENTS_PER_REQUEST) - return BLKIF_MAX_SEGMENTS_PER_REQUEST; // not supported - - if (SectorsLeft < BLKIF_MAX_SEGMENTS_PER_REQUEST * SectorsPerPage) - return BLKIF_MAX_SEGMENTS_PER_REQUEST; // first into a single BLKIF_OP_{READ/WRITE} - - return MaxIndirectSegs; -} - -static FORCEINLINE ULONG -TargetQueueRequestList( - IN PXENVBD_TARGET Target, - IN PLIST_ENTRY List - ) -{ - ULONG Count = 0; - for (;;) { - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry; - - Entry = RemoveHeadList(List); - if (Entry == List) - break; - - ++Count; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - __TargetIncBlkifOpCount(Target, Request); - QueueAppend(&Target->PreparedReqs, &Request->Entry); - } - return Count; -} - -static FORCEINLINE VOID -TargetCancelRequestList( - IN PXENVBD_TARGET Target, - IN PLIST_ENTRY List - ) -{ - for (;;) { - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry; - - Entry = RemoveHeadList(List); - if (Entry == List) - break; - - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - TargetPutRequest(Target, Request); - } -} - -__checkReturn -static BOOLEAN -PrepareReadWrite( - __in PXENVBD_TARGET Target, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); - ULONG64 SectorStart = Cdb_LogicalBlock(Srb); - ULONG SectorsLeft = Cdb_TransferBlock(Srb); - LIST_ENTRY List; - ULONG DebugCount; - - Srb->SrbStatus = SRB_STATUS_PENDING; - - InitializeListHead(&List); - SrbExt->Count = 0; - - while (SectorsLeft > 0) { - ULONG MaxSegments; - ULONG SectorsDone = 0; - PXENVBD_REQUEST Request; - - Request = TargetGetRequest(Target); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->Entry); - InterlockedIncrement(&SrbExt->Count); - - Request->Srb = Srb; - MaxSegments = UseIndirect(Target, SectorsLeft); - - if (!PrepareBlkifReadWrite(Target, - Request, - SrbExt, - MaxSegments, - SectorStart, - SectorsLeft, - &SectorsDone)) - goto fail2; - - if (MaxSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { - if (!PrepareBlkifIndirect(Target, Request)) - goto fail3; - } - - SectorsLeft -= SectorsDone; - SectorStart += SectorsDone; - } - - DebugCount = TargetQueueRequestList(Target, &List); - if (DebugCount != (ULONG)SrbExt->Count) { - Trace("[%u] %d != %u\n", TargetGetTargetId(Target), SrbExt->Count, DebugCount); - } - return TRUE; - -fail3: -fail2: -fail1: - TargetCancelRequestList(Target, &List); - SrbExt->Count = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; -} - -__checkReturn -static BOOLEAN -PrepareSyncCache( - __in PXENVBD_TARGET Target, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); - PXENVBD_REQUEST Request; - LIST_ENTRY List; - UCHAR Operation; - ULONG DebugCount; - - Srb->SrbStatus = SRB_STATUS_PENDING; - - if (FrontendGetDiskInfo(Target->Frontend)->FlushCache) - Operation = BLKIF_OP_FLUSH_DISKCACHE; - else - Operation = BLKIF_OP_WRITE_BARRIER; - - InitializeListHead(&List); - SrbExt->Count = 0; - - Request = TargetGetRequest(Target); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->Entry); - InterlockedIncrement(&SrbExt->Count); - - Request->Srb = Srb; - Request->Operation = Operation; - Request->FirstSector = Cdb_LogicalBlock(Srb); - - DebugCount = TargetQueueRequestList(Target, &List); - if (DebugCount != (ULONG)SrbExt->Count) { - Trace("[%u] %d != %u\n", TargetGetTargetId(Target), SrbExt->Count, DebugCount); - } - return TRUE; - -fail1: - TargetCancelRequestList(Target, &List); - SrbExt->Count = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; -} - -__checkReturn -static BOOLEAN -PrepareUnmap( - __in PXENVBD_TARGET Target, - __in PSCSI_REQUEST_BLOCK Srb - ) -{ - PXENVBD_SRBEXT SrbExt = GetSrbExt(Srb); - PUNMAP_LIST_HEADER Unmap = Srb->DataBuffer; - ULONG Count = _byteswap_ushort(*(PUSHORT)Unmap->BlockDescrDataLength) / sizeof(UNMAP_BLOCK_DESCRIPTOR); - ULONG Index; - LIST_ENTRY List; - ULONG DebugCount; - - Srb->SrbStatus = SRB_STATUS_PENDING; - - InitializeListHead(&List); - SrbExt->Count = 0; - - for (Index = 0; Index < Count; ++Index) { - PUNMAP_BLOCK_DESCRIPTOR Descr = &Unmap->Descriptors[Index]; - PXENVBD_REQUEST Request; - - Request = TargetGetRequest(Target); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->Entry); - InterlockedIncrement(&SrbExt->Count); - - Request->Srb = Srb; - Request->Operation = BLKIF_OP_DISCARD; - Request->FirstSector = _byteswap_uint64(*(PULONG64)Descr->StartingLba); - Request->NrSectors = _byteswap_ulong(*(PULONG)Descr->LbaCount); - Request->Flags = 0; - } - - DebugCount = TargetQueueRequestList(Target, &List); - if (DebugCount != (ULONG)SrbExt->Count) { - Trace("[%u] %d != %u\n", TargetGetTargetId(Target), SrbExt->Count, DebugCount); - } - return TRUE; - -fail1: - TargetCancelRequestList(Target, &List); - SrbExt->Count = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; -} - -//============================================================================= -// Queue-Related -static FORCEINLINE VOID -__TargetPauseDataPath( - __in PXENVBD_TARGET Target, - __in BOOLEAN Timeout - ) -{ - KIRQL Irql; - ULONG Requests; - ULONG Count = 0; - PXENVBD_RING Ring = FrontendGetRing(Target->Frontend); - - KeAcquireSpinLock(&Target->Lock, &Irql); - ++Target->Paused; - KeReleaseSpinLock(&Target->Lock, Irql); - - Requests = QueueCount(&Target->SubmittedReqs); - KeMemoryBarrier(); - - Verbose("Target[%d] : Waiting for %d Submitted requests\n", TargetGetTargetId(Target), Requests); - - // poll ring and send event channel notification every 1ms (for up to 3 minutes) - while (QueueCount(&Target->SubmittedReqs)) { - if (Timeout && Count > 180000) - break; - KeRaiseIrql(DISPATCH_LEVEL, &Irql); - RingPoll(Ring); - KeLowerIrql(Irql); - RingSend(Ring); // let backend know it needs to do some work - StorPortStallExecution(1000); // 1000 micro-seconds - ++Count; - } - - Verbose("Target[%d] : %u/%u Submitted requests left (%u iterrations)\n", - TargetGetTargetId(Target), QueueCount(&Target->SubmittedReqs), Requests, Count); - - // Abort Fresh SRBs - for (;;) { - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY Entry = QueuePop(&Target->FreshSrbs); - if (Entry == NULL) - break; - SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); - - Verbose("Target[%d] : FreshSrb 0x%p -> SCSI_ABORTED\n", TargetGetTargetId(Target), SrbExt->Srb); - SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; - SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED; - AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt); - } - - // Fail PreparedReqs - for (;;) { - PXENVBD_SRBEXT SrbExt; - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry = QueuePop(&Target->PreparedReqs); - if (Entry == NULL) - break; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - SrbExt = GetSrbExt(Request->Srb); - - Verbose("Target[%d] : PreparedReq 0x%p -> FAILED\n", TargetGetTargetId(Target), Request); - - SrbExt->Srb->SrbStatus = SRB_STATUS_ABORTED; - TargetPutRequest(Target, Request); - - if (InterlockedDecrement(&SrbExt->Count) == 0) { - SrbExt->Srb->ScsiStatus = 0x40; // SCSI_ABORTED - AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt); - } - } -} - -static FORCEINLINE VOID -__TargetUnpauseDataPath( - __in PXENVBD_TARGET Target - ) -{ - KIRQL Irql; - - KeAcquireSpinLock(&Target->Lock, &Irql); - --Target->Paused; - KeReleaseSpinLock(&Target->Lock, Irql); -} - -static FORCEINLINE BOOLEAN -TargetPrepareFresh( - IN PXENVBD_TARGET Target - ) -{ - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY Entry; - - Entry = QueuePop(&Target->FreshSrbs); - if (Entry == NULL) - return FALSE; // fresh queue is empty - - SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); - - switch (Cdb_OperationEx(SrbExt->Srb)) { - case SCSIOP_READ: - case SCSIOP_WRITE: - if (PrepareReadWrite(Target, SrbExt->Srb)) - return TRUE; // prepared this SRB - break; - case SCSIOP_SYNCHRONIZE_CACHE: - if (PrepareSyncCache(Target, SrbExt->Srb)) - return TRUE; // prepared this SRB - break; - case SCSIOP_UNMAP: - if (PrepareUnmap(Target, SrbExt->Srb)) - return TRUE; // prepared this SRB - break; - default: - ASSERT(FALSE); - break; - } - QueueUnPop(&Target->FreshSrbs, &SrbExt->Entry); - - return FALSE; // prepare failed -} - -static FORCEINLINE BOOLEAN -TargetSubmitPrepared( - __in PXENVBD_TARGET Target - ) -{ - PXENVBD_RING Ring = FrontendGetRing(Target->Frontend); - if (TargetIsPaused(Target)) { - if (QueueCount(&Target->PreparedReqs)) - Warning("Target[%d] : Paused, not submitting new requests (%u)\n", - TargetGetTargetId(Target), - QueueCount(&Target->PreparedReqs)); - return FALSE; - } - - for (;;) { - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry; - - Entry = QueuePop(&Target->PreparedReqs); - if (Entry == NULL) - break; - - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - - QueueAppend(&Target->SubmittedReqs, &Request->Entry); - KeMemoryBarrier(); - - if (RingSubmit(Ring, Request)) - continue; - - QueueRemove(&Target->SubmittedReqs, &Request->Entry); - QueueUnPop(&Target->PreparedReqs, &Request->Entry); - return FALSE; // ring full - } - - return TRUE; -} - -static FORCEINLINE VOID -TargetCompleteShutdown( - __in PXENVBD_TARGET Target - ) -{ - if (QueueCount(&Target->ShutdownSrbs) == 0) - return; - - if (QueueCount(&Target->FreshSrbs) || - QueueCount(&Target->PreparedReqs) || - QueueCount(&Target->SubmittedReqs)) - return; - - for (;;) { - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY Entry = QueuePop(&Target->ShutdownSrbs); - if (Entry == NULL) - break; - SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); - SrbExt->Srb->SrbStatus = SRB_STATUS_SUCCESS; - AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt); - } -} - -static FORCEINLINE PCHAR -BlkifOperationName( - IN UCHAR Operation - ) -{ - switch (Operation) { - case BLKIF_OP_READ: return "READ"; - case BLKIF_OP_WRITE: return "WRITE"; - case BLKIF_OP_WRITE_BARRIER: return "WRITE_BARRIER"; - case BLKIF_OP_FLUSH_DISKCACHE: return "FLUSH_DISKCACHE"; - case BLKIF_OP_RESERVED_1: return "RESERVED_1"; - case BLKIF_OP_DISCARD: return "DISCARD"; - case BLKIF_OP_INDIRECT: return "INDIRECT"; - default: return "<unknown>"; - } -} - -BOOLEAN -TargetSubmitRequests( - IN PXENVBD_TARGET Target - ) -{ - BOOLEAN Retry = FALSE; - - for (;;) { - // submit all prepared requests (0 or more requests) - // return TRUE if submitted 0 or more requests from prepared queue - // return FALSE iff ring is full - if (!TargetSubmitPrepared(Target)) - break; - - // prepare a single SRB (into 1 or more requests) - // return TRUE if prepare succeeded - // return FALSE if prepare failed or fresh queue empty - if (!TargetPrepareFresh(Target)) - break; - - // back off, check DPC timeout and try again - Retry = TRUE; - break; - } - - // if no requests/SRBs outstanding, complete any shutdown SRBs - if (!Retry) - TargetCompleteShutdown(Target); - - return Retry; -} - -VOID -TargetCompleteResponse( - IN PXENVBD_TARGET Target, - IN ULONG Tag, - IN SHORT Status - ) -{ - PXENVBD_REQUEST Request; - PSCSI_REQUEST_BLOCK Srb; - PXENVBD_SRBEXT SrbExt; - - Request = TargetRequestFromTag(Target, Tag); - if (Request == NULL) - return; - - Srb = Request->Srb; - SrbExt = GetSrbExt(Srb); - ASSERT3P(SrbExt, !=, NULL); - - switch (Status) { - case BLKIF_RSP_OKAY: - RequestCopyOutput(Request); - break; - - case BLKIF_RSP_EOPNOTSUPP: - // Remove appropriate feature support - FrontendRemoveFeature(Target->Frontend, Request->Operation); - // Succeed this SRB, subsiquent SRBs will be succeeded instead of being passed to the backend. - Srb->SrbStatus = SRB_STATUS_SUCCESS; - break; - - case BLKIF_RSP_ERROR: - default: - Warning("Target[%d] : %s BLKIF_RSP_ERROR (Tag %x)\n", - TargetGetTargetId(Target), BlkifOperationName(Request->Operation), Tag); - Srb->SrbStatus = SRB_STATUS_ERROR; - break; - } - - TargetPutRequest(Target, Request); - - // complete srb - if (InterlockedDecrement(&SrbExt->Count) == 0) { - if (Srb->SrbStatus == SRB_STATUS_PENDING) { - // SRB has not hit a failure condition (BLKIF_RSP_ERROR | BLKIF_RSP_EOPNOTSUPP) - // from any of its responses. SRB must have succeeded - Srb->SrbStatus = SRB_STATUS_SUCCESS; - Srb->ScsiStatus = 0x00; // SCSI_GOOD - } else { - // Srb->SrbStatus has already been set by 1 or more requests with Status != BLKIF_RSP_OKAY - Srb->ScsiStatus = 0x40; // SCSI_ABORTED - } - - AdapterCompleteSrb(TargetGetAdapter(Target), SrbExt); - } -} - //============================================================================= // SRBs __checkReturn @@ -1407,9 +278,7 @@ TargetReadWrite( return TRUE; // Complete now } - QueueAppend(&Target->FreshSrbs, &SrbExt->Entry); - RingKick(Ring); - + RingQueueRequest(Ring, SrbExt); return FALSE; } @@ -1437,9 +306,7 @@ TargetSyncCache( return TRUE; } - QueueAppend(&Target->FreshSrbs, &SrbExt->Entry); - RingKick(Ring); - + RingQueueRequest(Ring, SrbExt); return FALSE; } @@ -1466,9 +333,7 @@ TargetUnmap( return TRUE; } - QueueAppend(&Target->FreshSrbs, &SrbExt->Entry); - RingKick(Ring); - + RingQueueRequest(Ring, SrbExt); return FALSE; } @@ -1872,15 +737,7 @@ TargetReset( { Verbose("[%u] =====>\n", TargetGetTargetId(Target)); - __TargetPauseDataPath(Target, TRUE); - - if (QueueCount(&Target->SubmittedReqs)) { - Error("Target[%d] : backend has %u outstanding requests after a TargetReset\n", - TargetGetTargetId(Target), - QueueCount(&Target->SubmittedReqs)); - } - - __TargetUnpauseDataPath(Target); + FrontendReset(Target->Frontend); Verbose("[%u] <=====\n", TargetGetTargetId(Target)); } @@ -1891,8 +748,7 @@ TargetFlush( IN PXENVBD_SRBEXT SrbExt ) { - QueueAppend(&Target->ShutdownSrbs, &SrbExt->Entry); - RingKick(FrontendGetRing(Target->Frontend)); + RingQueueShutdown(FrontendGetRing(Target->Frontend), SrbExt); } VOID @@ -1901,8 +757,7 @@ TargetShutdown( IN PXENVBD_SRBEXT SrbExt ) { - QueueAppend(&Target->ShutdownSrbs, &SrbExt->Entry); - RingKick(FrontendGetRing(Target->Frontend)); + RingQueueShutdown(FrontendGetRing(Target->Frontend), SrbExt); } VOID @@ -2156,58 +1011,8 @@ TargetDebugCallback( "TARGET: %s\n", Target->Missing ? Target->Reason : "Not Missing"); - XENBUS_DEBUG(Printf, - &Target->DebugInterface, - "TARGET: BLKIF_OPs: READ=%u WRITE=%u\n", - Target->BlkOpRead, Target->BlkOpWrite); - XENBUS_DEBUG(Printf, - &Target->DebugInterface, - "TARGET: BLKIF_OPs: INDIRECT_READ=%u INDIRECT_WRITE=%u\n", - Target->BlkOpIndirectRead, Target->BlkOpIndirectWrite); - XENBUS_DEBUG(Printf, - &Target->DebugInterface, - "TARGET: BLKIF_OPs: BARRIER=%u DISCARD=%u FLUSH=%u\n", - Target->BlkOpBarrier, Target->BlkOpDiscard, Target->BlkOpFlush); - XENBUS_DEBUG(Printf, - &Target->DebugInterface, - "TARGET: Failed: Maps=%u Bounces=%u Grants=%u\n", - Target->FailedMaps, Target->FailedBounces, Target->FailedGrants); - XENBUS_DEBUG(Printf, - &Target->DebugInterface, - "TARGET: Segments Granted=%llu Bounced=%llu\n", - Target->SegsGranted, Target->SegsBounced); - - __LookasideDebug(&Target->RequestList, - &Target->DebugInterface, - "REQUESTs"); - __LookasideDebug(&Target->SegmentList, - &Target->DebugInterface, - "SEGMENTs"); - __LookasideDebug(&Target->IndirectList, - &Target->DebugInterface, - "INDIRECTs"); - - QueueDebugCallback(&Target->FreshSrbs, - "Fresh ", - &Target->DebugInterface); - QueueDebugCallback(&Target->PreparedReqs, - "Prepared ", - &Target->DebugInterface); - QueueDebugCallback(&Target->SubmittedReqs, - "Submitted", - &Target->DebugInterface); - QueueDebugCallback(&Target->ShutdownSrbs, - "Shutdown ", - &Target->DebugInterface); - FrontendDebugCallback(Target->Frontend, &Target->DebugInterface); - - Target->BlkOpRead = Target->BlkOpWrite = 0; - Target->BlkOpIndirectRead = Target->BlkOpIndirectWrite = 0; - Target->BlkOpBarrier = Target->BlkOpDiscard = Target->BlkOpFlush = 0; - Target->FailedMaps = Target->FailedBounces = Target->FailedGrants = 0; - Target->SegsGranted = Target->SegsBounced = 0; } static DECLSPEC_NOINLINE VOID @@ -2216,61 +1021,8 @@ TargetSuspendCallback( ) { PXENVBD_TARGET Target = Argument; - LIST_ENTRY List; - - InitializeListHead(&List); - - // pop all submitted requests, cleanup and add associated SRB to a list - for (;;) { - PXENVBD_SRBEXT SrbExt; - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry = QueuePop(&Target->SubmittedReqs); - if (Entry == NULL) - break; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - SrbExt = GetSrbExt(Request->Srb); - - TargetPutRequest(Target, Request); - - if (InterlockedDecrement(&SrbExt->Count) == 0) { - InsertTailList(&List, &SrbExt->Entry); - } - } - - // pop all prepared requests, cleanup and add associated SRB to a list - for (;;) { - PXENVBD_SRBEXT SrbExt; - PXENVBD_REQUEST Request; - PLIST_ENTRY Entry = QueuePop(&Target->PreparedReqs); - if (Entry == NULL) - break; - Request = CONTAINING_RECORD(Entry, XENVBD_REQUEST, Entry); - SrbExt = GetSrbExt(Request->Srb); - - TargetPutRequest(Target, Request); - - if (InterlockedDecrement(&SrbExt->Count) == 0) { - InsertTailList(&List, &SrbExt->Entry); - } - } - - // foreach SRB in list, put on start of FreshSrbs - for (;;) { - PXENVBD_SRBEXT SrbExt; - PLIST_ENTRY Entry = RemoveTailList(&List); - if (Entry == &List) - break; - SrbExt = CONTAINING_RECORD(Entry, XENVBD_SRBEXT, Entry); - QueueUnPop(&Target->FreshSrbs, &SrbExt->Entry); - } - - // now the first set of requests popped off submitted list is the next SRB - // to be popped off the fresh list - - Verbose("Target[%d] : %d Fresh SRBs\n", - TargetGetTargetId(Target), - QueueCount(&Target->FreshSrbs)); + RingReQueueRequests(FrontendGetRing(Target->Frontend)); Verbose("Target[%d] : %s (%s)\n", TargetGetTargetId(Target), @@ -2332,8 +1084,6 @@ TargetD3ToD0( if (!NT_SUCCESS(status)) goto fail6; - __TargetUnpauseDataPath(Target); - return STATUS_SUCCESS; fail6: @@ -2388,8 +1138,6 @@ TargetD0ToD3( Verbose("Target[%d] : D0->D3\n", TargetId); - __TargetPauseDataPath(Target, FALSE); - (VOID) FrontendSetState(Target->Frontend, XENVBD_CLOSED); FrontendD0ToD3(Target->Frontend); @@ -2471,18 +1219,10 @@ TargetCreate( Target->Signature = TARGET_SIGNATURE; Target->Adapter = Adapter; Target->DeviceObject = NULL; // filled in later - Target->Paused = 1; // Paused until D3->D0 transition Target->DevicePnpState = Present; Target->DevicePowerState = PowerDeviceD3; KeInitializeSpinLock(&Target->Lock); - QueueInit(&Target->FreshSrbs); - QueueInit(&Target->PreparedReqs); - QueueInit(&Target->SubmittedReqs); - QueueInit(&Target->ShutdownSrbs); - __LookasideInit(&Target->RequestList, sizeof(XENVBD_REQUEST), REQUEST_POOL_TAG); - __LookasideInit(&Target->SegmentList, sizeof(XENVBD_SEGMENT), SEGMENT_POOL_TAG); - __LookasideInit(&Target->IndirectList, sizeof(XENVBD_INDIRECT), INDIRECT_POOL_TAG); status = FrontendCreate(Target, DeviceId, TargetId, &Target->Frontend); if (!NT_SUCCESS(status)) @@ -2504,9 +1244,6 @@ fail3: fail2: Error("Fail2\n"); - __LookasideTerm(&Target->IndirectList); - __LookasideTerm(&Target->SegmentList); - __LookasideTerm(&Target->RequestList); __TargetFree(Target); fail1: @@ -2530,10 +1267,6 @@ TargetDestroy( FrontendDestroy(Target->Frontend); Target->Frontend = NULL; - __LookasideTerm(&Target->IndirectList); - __LookasideTerm(&Target->SegmentList); - __LookasideTerm(&Target->RequestList); - RtlZeroMemory(Target, sizeof(XENVBD_TARGET)); __TargetFree(Target); diff --git a/src/xenvbd/target.h b/src/xenvbd/target.h index b790eb4..dd360f5 100644 --- a/src/xenvbd/target.h +++ b/src/xenvbd/target.h @@ -93,18 +93,6 @@ TargetSetDeviceObject( IN PDEVICE_OBJECT DeviceObject ); -extern BOOLEAN -TargetSubmitRequests( - IN PXENVBD_TARGET Target - ); - -extern VOID -TargetCompleteResponse( - IN PXENVBD_TARGET Target, - IN ULONG Tag, - IN SHORT Status - ); - extern VOID TargetPrepareIo( IN PXENVBD_TARGET Target, -- 2.8.3 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |