[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [RFC PATCH 4/6] Add initial multi-queue support
Create a queue per CPU, up-to the lower limit specified by xenstore and registry override. Requests are queued on the same processor's DPC as StartIo runs on. It is assumed that any request dispatched to the backend on a particular queue will always be completed on the same queue. Signed-off-by: owensm <owen.smith@xxxxxxxxxx> --- src/xenvbd/protocol.c | 2100 ++++++++++++++++++++++++++++--------------------- 1 file changed, 1222 insertions(+), 878 deletions(-) diff --git a/src/xenvbd/protocol.c b/src/xenvbd/protocol.c index 39767eb..8aa6ec8 100644 --- a/src/xenvbd/protocol.c +++ b/src/xenvbd/protocol.c @@ -56,15 +56,10 @@ #define XENVBD_MAX_PROTOCOL_PAGE_ORDER (4) #define XENVBD_MAX_PROTOCOL_PAGES (1 << XENVBD_MAX_PROTOCOL_PAGE_ORDER) -struct _XENVBD_PROTOCOL { - PXENVBD_FRONTEND Frontend; - BOOLEAN Connected; - BOOLEAN Enabled; - - XENBUS_CACHE_INTERFACE CacheInterface; - XENBUS_STORE_INTERFACE StoreInterface; - XENBUS_EVTCHN_INTERFACE EvtchnInterface; - XENBUS_DEBUG_INTERFACE DebugInterface; +typedef struct _XENVBD_RING { + PXENVBD_PROTOCOL Protocol; + ULONG Index; + PCHAR Path; PXENBUS_DEBUG_CALLBACK DebugCallback; @@ -72,14 +67,10 @@ struct _XENVBD_PROTOCOL { PMDL Mdl; blkif_sring_t* Shared; blkif_front_ring_t Front; - ULONG Order; PVOID Grants[XENVBD_MAX_PROTOCOL_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; @@ -95,6 +86,29 @@ struct _XENVBD_PROTOCOL { ULONG BlkOpBarrier; ULONG BlkOpDiscard; ULONG BlkOpFlush; +} XENVBD_RING, *PXENVBD_RING; + +struct _XENVBD_PROTOCOL { + PXENVBD_FRONTEND Frontend; + BOOLEAN Connected; + BOOLEAN Enabled; + + XENBUS_CACHE_INTERFACE CacheInterface; + XENBUS_STORE_INTERFACE StoreInterface; + XENBUS_EVTCHN_INTERFACE EvtchnInterface; + XENBUS_DEBUG_INTERFACE DebugInterface; + + PXENBUS_DEBUG_CALLBACK DebugCallback; + KSPIN_LOCK Lock; + + PXENBUS_CACHE RequestCache; + PXENBUS_CACHE SegmentCache; + PXENBUS_CACHE IndirectCache; + + ULONG Order; + ULONG NumQueues; + PXENVBD_RING *Rings; + ULONG64 SegsGranted; ULONG64 SegsBounced; }; @@ -138,12 +152,13 @@ xen_wmb() } static FORCEINLINE VOID -__ProtocolInsert( - IN PXENVBD_PROTOCOL Protocol, +__RingInsert( + IN PXENVBD_RING Ring, IN PXENVBD_REQUEST Request, IN blkif_request_t* req ) { + PXENVBD_PROTOCOL Protocol = Ring->Protocol; PXENVBD_GRANTER Granter = FrontendGetGranter(Protocol->Frontend); switch (Request->Operation) { @@ -234,7 +249,7 @@ __ProtocolInsert( ASSERT(FALSE); break; } - ++Protocol->Submitted; + ++Ring->Submitted; } static PXENVBD_INDIRECT @@ -400,15 +415,16 @@ ProtocolPutRequest( } static FORCEINLINE PXENVBD_REQUEST -ProtocolFindRequest( - IN PXENVBD_PROTOCOL Protocol, +RingFindRequest( + IN PXENVBD_RING Ring, IN ULONG64 Id ) { KIRQL Irql; PLIST_ENTRY ListEntry; PXENVBD_REQUEST Request; - PXENVBD_QUEUE Queue = &Protocol->SubmittedReqs; + PXENVBD_QUEUE Queue = &Ring->SubmittedReqs; + PXENVBD_PROTOCOL Protocol = Ring->Protocol; KeAcquireSpinLock(&Queue->Lock, &Irql); @@ -425,40 +441,41 @@ ProtocolFindRequest( } KeReleaseSpinLock(&Queue->Lock, Irql); - Warning("Target[%d] : Tag %llx not found in submitted list (%u items)\n", + Warning("Target[%d][%u] : Tag %llx not found in submitted list (%u items)\n", FrontendGetTargetId(Protocol->Frontend), + Ring->Index, Id, QueueCount(Queue)); return NULL; } static FORCEINLINE VOID -__ProtocolIncBlkifOpCount( - IN PXENVBD_PROTOCOL Protocol, +__RingIncBlkifOpCount( + IN PXENVBD_RING Ring, IN PXENVBD_REQUEST Request ) { switch (Request->Operation) { case BLKIF_OP_READ: if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) - ++Protocol->BlkOpIndirectRead; + ++Ring->BlkOpIndirectRead; else - ++Protocol->BlkOpRead; + ++Ring->BlkOpRead; break; case BLKIF_OP_WRITE: if (Request->NrSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) - ++Protocol->BlkOpIndirectWrite; + ++Ring->BlkOpIndirectWrite; else - ++Protocol->BlkOpWrite; + ++Ring->BlkOpWrite; break; case BLKIF_OP_WRITE_BARRIER: - ++Protocol->BlkOpBarrier; + ++Ring->BlkOpBarrier; break; case BLKIF_OP_DISCARD: - ++Protocol->BlkOpDiscard; + ++Ring->BlkOpDiscard; break; case BLKIF_OP_FLUSH_DISKCACHE: - ++Protocol->BlkOpFlush; + ++Ring->BlkOpFlush; break; default: ASSERT(FALSE); @@ -467,7 +484,7 @@ __ProtocolIncBlkifOpCount( } static FORCEINLINE ULONG -__ProtocolSectorsPerPage( +__SectorsPerPage( IN ULONG SectorSize ) { @@ -476,7 +493,7 @@ __ProtocolSectorsPerPage( } static FORCEINLINE VOID -__ProtocolOperation( +__Operation( IN UCHAR CdbOp, OUT PUCHAR ProtocolOp, OUT PBOOLEAN ReadOnly @@ -496,22 +513,8 @@ __ProtocolOperation( } } -static FORCEINLINE MM_PAGE_PRIORITY -__ProtocolPriority( - IN PXENVBD_PROTOCOL Protocol - ) -{ - PXENVBD_CAPS Caps = FrontendGetCaps(Protocol->Frontend); - if (!(Caps->Paging || - Caps->Hibernation || - Caps->DumpFile)) - return NormalPagePriority; - - return HighPagePriority; -} - static FORCEINLINE VOID -ProtocolRequestCopyOutput( +__RequestCopyOutput( IN PXENVBD_REQUEST Request ) { @@ -534,532 +537,136 @@ ProtocolRequestCopyOutput( } } -static BOOLEAN -ProtocolPrepareSegment( - IN PXENVBD_PROTOCOL Protocol, - IN PXENVBD_SEGMENT Segment, - IN PXENVBD_SRBEXT SrbExt, - IN BOOLEAN ReadOnly, - IN ULONG SectorsLeft, - OUT PULONG SectorsNow +static FORCEINLINE VOID +RingQueueRequestList( + IN PXENVBD_RING Ring, + IN PLIST_ENTRY List ) { - PFN_NUMBER Pfn; - ULONG Offset; - ULONG Length; - NTSTATUS Status; - PXENVBD_GRANTER Granter = FrontendGetGranter(Protocol->Frontend); - const ULONG SectorSize = FrontendGetDiskInfo(Protocol->Frontend)->SectorSize; - const ULONG SectorsPerPage = __ProtocolSectorsPerPage(SectorSize); - PXENVBD_TARGET Target = FrontendGetTarget(Protocol->Frontend); - PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target); - - Pfn = AdapterGetNextSGEntry(Adapter, - SrbExt, - 0, - &Offset, - &Length); - if ((Offset & (SectorSize - 1)) == 0 && - (Length & (SectorSize - 1)) == 0) { - ++Protocol->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); - - ASSERT3U((Length / SectorSize), ==, *SectorsNow); - } else { - PXENVBD_BOUNCE Bounce; - PMDL Mdl; - - ++Protocol->SegsBounced; - // get first sector, last sector and count - Segment->FirstSector = 0; - *SectorsNow = __min(SectorsLeft, SectorsPerPage); - Segment->LastSector = (UCHAR)(*SectorsNow - 1); - - Bounce = AdapterGetBounce(Adapter); - if (Bounce == NULL) - goto fail1; - Segment->Bounce = Bounce; - -#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; - - if (Length < *SectorsNow * SectorSize) { - Pfn = AdapterGetNextSGEntry(Adapter, - SrbExt, - Length, - &Offset, - &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)); - - Bounce->SourcePtr = MmMapLockedPagesSpecifyCache(Mdl, - KernelMode, - MmCached, - NULL, - FALSE, - __ProtocolPriority(Protocol)); - if (Bounce->SourcePtr == NULL) - goto fail2; - - ASSERT3P(MmGetMdlPfnArray(Mdl)[0], ==, Bounce->SourcePfn[0]); - ASSERT3P(MmGetMdlPfnArray(Mdl)[1], ==, Bounce->SourcePfn[1]); + for (;;) { + PXENVBD_REQUEST Request; + PLIST_ENTRY ListEntry; - // copy contents in - if (ReadOnly) { // Operation == BLKIF_OP_WRITE - RtlCopyMemory(Bounce->BouncePtr, - Bounce->SourcePtr, - MmGetMdlByteCount(&Bounce->SourceMdl)); - } + ListEntry = RemoveHeadList(List); + if (ListEntry == List) + break; - Pfn = MmGetMdlPfnArray(Bounce->BounceMdl)[0]; + Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); + __RingIncBlkifOpCount(Ring, Request); + QueueAppend(&Ring->PreparedReqs, &Request->ListEntry); } - - // 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 -ProtocolPrepareBlkifReadWrite( - IN PXENVBD_PROTOCOL Protocol, - IN PXENVBD_REQUEST Request, - IN PXENVBD_SRBEXT SrbExt, - IN ULONG MaxSegments, - IN ULONG64 SectorStart, - IN ULONG SectorsLeft, - OUT PULONG SectorsDone +RingSubmit( + IN PXENVBD_RING Ring, + IN PXENVBD_REQUEST Request ) { - PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; - UCHAR Operation; - BOOLEAN ReadOnly; - ULONG Index; - __ProtocolOperation(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 = ProtocolGetSegment(Protocol); - if (Segment == NULL) - goto fail1; - - InsertTailList(&Request->Segments, &Segment->ListEntry); - ++Request->NrSegments; - - if (!ProtocolPrepareSegment(Protocol, - Segment, - SrbExt, - ReadOnly, - SectorsLeft, - &SectorsNow)) - goto fail2; + KIRQL Irql; + blkif_request_t* req; + BOOLEAN Notify; + PXENVBD_PROTOCOL Protocol; - *SectorsDone += SectorsNow; - SectorsLeft -= SectorsNow; + KeAcquireSpinLock(&Ring->Lock, &Irql); + if (RING_FULL(&Ring->Front)) { + KeReleaseSpinLock(&Ring->Lock, Irql); + return FALSE; } - ASSERT3U(Request->NrSegments, >, 0); - ASSERT3U(Request->NrSegments, <=, MaxSegments); - - return TRUE; - -fail2: -fail1: - return FALSE; -} -static BOOLEAN -ProtocolPrepareBlkifIndirect( - IN PXENVBD_PROTOCOL Protocol, - IN PXENVBD_REQUEST Request - ) -{ - ULONG Index; - ULONG NrSegments = 0; + req = RING_GET_REQUEST(&Ring->Front, Ring->Front.req_prod_pvt); + __RingInsert(Ring, Request, req); + KeMemoryBarrier(); + ++Ring->Front.req_prod_pvt; - for (Index = 0; - Index < BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST && - NrSegments < Request->NrSegments; - ++Index) { - PXENVBD_INDIRECT Indirect; + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&Ring->Front, Notify); + KeReleaseSpinLock(&Ring->Lock, Irql); - Indirect = ProtocolGetIndirect(Protocol); - if (Indirect == NULL) - goto fail1; - InsertTailList(&Request->Indirects, &Indirect->ListEntry); + if (Notify) { + Protocol = Ring->Protocol; + if (!Protocol->Enabled) + return TRUE; - NrSegments += XENVBD_MAX_SEGMENTS_PER_PAGE; + XENBUS_EVTCHN(Send, + &Protocol->EvtchnInterface, + Ring->Channel); } return TRUE; - -fail1: - return FALSE; } -static FORCEINLINE ULONG -ProtocolUseIndirect( - IN PXENVBD_PROTOCOL Protocol, - IN ULONG SectorsLeft +static FORCEINLINE BOOLEAN +RingSubmitRequests( + IN PXENVBD_RING Ring ) { - const ULONG SectorsPerPage = __ProtocolSectorsPerPage(FrontendGetDiskInfo(Protocol->Frontend)->SectorSize); - const ULONG MaxIndirectSegs = FrontendGetFeatures(Protocol->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} + PXENVBD_PROTOCOL Protocol = Ring->Protocol; - return MaxIndirectSegs; -} + if (!Protocol->Enabled) { + if (QueueCount(&Ring->PreparedReqs)) + Warning("Target[%d][%u] : Paused, not submitting new requests (%u)\n", + FrontendGetTargetId(Protocol->Frontend), + Ring->Index, + QueueCount(&Ring->PreparedReqs)); + return FALSE; + } -static FORCEINLINE VOID -ProtocolQueueRequestList( - IN PXENVBD_PROTOCOL Protocol, - IN PLIST_ENTRY List - ) -{ for (;;) { PXENVBD_REQUEST Request; PLIST_ENTRY ListEntry; - ListEntry = RemoveHeadList(List); - if (ListEntry == List) + ListEntry = QueuePop(&Ring->PreparedReqs); + if (ListEntry == NULL) break; Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); - __ProtocolIncBlkifOpCount(Protocol, Request); - QueueAppend(&Protocol->PreparedReqs, &Request->ListEntry); + + QueueAppend(&Ring->SubmittedReqs, &Request->ListEntry); + KeMemoryBarrier(); + + if (RingSubmit(Ring, Request)) + continue; + + QueueRemove(&Ring->SubmittedReqs, &Request->ListEntry); + QueueUnPop(&Ring->PreparedReqs, &Request->ListEntry); + break; } + + return QueueCount(&Ring->PreparedReqs) != 0; } static FORCEINLINE VOID -ProtocolCancelRequestList( - IN PXENVBD_PROTOCOL Protocol, - IN PLIST_ENTRY List +RingCompleteShutdown( + IN PXENVBD_RING Ring ) { + PXENVBD_PROTOCOL Protocol; + PXENVBD_TARGET Target; + PXENVBD_ADAPTER Adapter; + + if (QueueCount(&Ring->ShutdownSrbs) == 0) + return; + + if (QueueCount(&Ring->PreparedReqs) || + QueueCount(&Ring->SubmittedReqs)) + return; + + Protocol = Ring->Protocol; + Target = FrontendGetTarget(Protocol->Frontend); + Adapter = TargetGetAdapter(Target); for (;;) { - PXENVBD_REQUEST Request; - PLIST_ENTRY ListEntry; + PXENVBD_SRBEXT SrbExt; + PSCSI_REQUEST_BLOCK Srb; + PLIST_ENTRY ListEntry; - ListEntry = RemoveHeadList(List); - if (ListEntry == List) + ListEntry = QueuePop(&Ring->ShutdownSrbs); + if (ListEntry == NULL) break; - - Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); - ProtocolPutRequest(Protocol, Request); - } -} - -static BOOLEAN -ProtocolPrepareReadWrite( - IN PXENVBD_PROTOCOL Protocol, - IN PXENVBD_SRBEXT SrbExt - ) -{ - PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; - ULONG64 SectorStart = Cdb_LogicalBlock(Srb); - ULONG SectorsLeft = Cdb_TransferBlock(Srb); - LIST_ENTRY List; - - Srb->SrbStatus = SRB_STATUS_PENDING; - - InitializeListHead(&List); - SrbExt->RequestCount = 0; - - while (SectorsLeft > 0) { - ULONG MaxSegments; - ULONG SectorsDone = 0; - PXENVBD_REQUEST Request; - - Request = ProtocolGetRequest(Protocol); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->ListEntry); - InterlockedIncrement(&SrbExt->RequestCount); - - Request->SrbExt = SrbExt; - MaxSegments = ProtocolUseIndirect(Protocol, SectorsLeft); - - if (!ProtocolPrepareBlkifReadWrite(Protocol, - Request, - SrbExt, - MaxSegments, - SectorStart, - SectorsLeft, - &SectorsDone)) - goto fail2; - - if (MaxSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { - if (!ProtocolPrepareBlkifIndirect(Protocol, Request)) - goto fail3; - } - - SectorsLeft -= SectorsDone; - SectorStart += SectorsDone; - } - - ProtocolQueueRequestList(Protocol, &List); - return TRUE; - -fail3: -fail2: -fail1: - ProtocolCancelRequestList(Protocol, &List); - SrbExt->RequestCount = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; -} - -static BOOLEAN -ProtocolPrepareSyncCache( - IN PXENVBD_PROTOCOL Protocol, - IN PXENVBD_SRBEXT SrbExt - ) -{ - PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; - PXENVBD_REQUEST Request; - LIST_ENTRY List; - UCHAR Operation; - - Srb->SrbStatus = SRB_STATUS_PENDING; - - if (FrontendGetDiskInfo(Protocol->Frontend)->FlushCache) - Operation = BLKIF_OP_FLUSH_DISKCACHE; - else - Operation = BLKIF_OP_WRITE_BARRIER; - - InitializeListHead(&List); - SrbExt->RequestCount = 0; - - Request = ProtocolGetRequest(Protocol); - if (Request == NULL) - goto fail1; - InsertTailList(&List, &Request->ListEntry); - InterlockedIncrement(&SrbExt->RequestCount); - - Request->SrbExt = SrbExt; - Request->Operation = Operation; - Request->FirstSector = Cdb_LogicalBlock(Srb); - - ProtocolQueueRequestList(Protocol, &List); - return TRUE; - -fail1: - ProtocolCancelRequestList(Protocol, &List); - SrbExt->RequestCount = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; -} - -static BOOLEAN -ProtocolPrepareUnmap( - IN PXENVBD_PROTOCOL Protocol, - 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 = ProtocolGetRequest(Protocol); - 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; - } - - ProtocolQueueRequestList(Protocol, &List); - return TRUE; - -fail1: - ProtocolCancelRequestList(Protocol, &List); - SrbExt->RequestCount = 0; - Srb->SrbStatus = SRB_STATUS_ERROR; - return FALSE; -} - -static FORCEINLINE BOOLEAN -ProtocolPrepareRequest( - IN PXENVBD_PROTOCOL Protocol, - IN PXENVBD_SRBEXT SrbExt - ) -{ - switch (Cdb_OperationEx(SrbExt->Srb)) { - case SCSIOP_READ: - case SCSIOP_WRITE: - return ProtocolPrepareReadWrite(Protocol, SrbExt); - - case SCSIOP_SYNCHRONIZE_CACHE: - return ProtocolPrepareSyncCache(Protocol, SrbExt); - - case SCSIOP_UNMAP: - return ProtocolPrepareUnmap(Protocol, SrbExt); - - default: - ASSERT(FALSE); - return FALSE; - } -} - -static BOOLEAN -ProtocolSubmit( - IN PXENVBD_PROTOCOL Protocol, - IN PXENVBD_REQUEST Request - ) -{ - KIRQL Irql; - blkif_request_t* req; - BOOLEAN Notify; - - KeAcquireSpinLock(&Protocol->Lock, &Irql); - if (RING_FULL(&Protocol->Front)) { - KeReleaseSpinLock(&Protocol->Lock, Irql); - return FALSE; - } - - req = RING_GET_REQUEST(&Protocol->Front, Protocol->Front.req_prod_pvt); - __ProtocolInsert(Protocol, Request, req); - KeMemoryBarrier(); - ++Protocol->Front.req_prod_pvt; - - RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&Protocol->Front, Notify); - KeReleaseSpinLock(&Protocol->Lock, Irql); - - if (Notify) { - if (!Protocol->Enabled) - return TRUE; - - XENBUS_EVTCHN(Send, - &Protocol->EvtchnInterface, - Protocol->Channel); - } - - return TRUE; -} - -static FORCEINLINE BOOLEAN -ProtocolSubmitRequests( - IN PXENVBD_PROTOCOL Protocol - ) -{ - if (!Protocol->Enabled) { - if (QueueCount(&Protocol->PreparedReqs)) - Warning("Target[%d] : Paused, not submitting new requests (%u)\n", - FrontendGetTargetId(Protocol->Frontend), - QueueCount(&Protocol->PreparedReqs)); - return FALSE; - } - - for (;;) { - PXENVBD_REQUEST Request; - PLIST_ENTRY ListEntry; - - ListEntry = QueuePop(&Protocol->PreparedReqs); - if (ListEntry == NULL) - break; - - Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); - - QueueAppend(&Protocol->SubmittedReqs, &Request->ListEntry); - KeMemoryBarrier(); - - if (ProtocolSubmit(Protocol, Request)) - continue; - - QueueRemove(&Protocol->SubmittedReqs, &Request->ListEntry); - QueueUnPop(&Protocol->PreparedReqs, &Request->ListEntry); - break; - } - - return QueueCount(&Protocol->PreparedReqs) != 0; -} - -static FORCEINLINE VOID -ProtocolCompleteShutdown( - IN PXENVBD_PROTOCOL Protocol - ) -{ - PXENVBD_TARGET Target; - PXENVBD_ADAPTER Adapter; - - if (QueueCount(&Protocol->ShutdownSrbs) == 0) - return; - - if (QueueCount(&Protocol->PreparedReqs) || - QueueCount(&Protocol->SubmittedReqs)) - return; - - Target = FrontendGetTarget(Protocol->Frontend); - Adapter = TargetGetAdapter(Target); - for (;;) { - PXENVBD_SRBEXT SrbExt; - PSCSI_REQUEST_BLOCK Srb; - PLIST_ENTRY ListEntry; - - ListEntry = QueuePop(&Protocol->ShutdownSrbs); - if (ListEntry == NULL) - break; - SrbExt = CONTAINING_RECORD(ListEntry, XENVBD_SRBEXT, ListEntry); - Srb = SrbExt->Srb; - - Srb->SrbStatus = SRB_STATUS_SUCCESS; - AdapterCompleteSrb(Adapter, SrbExt); + SrbExt = CONTAINING_RECORD(ListEntry, XENVBD_SRBEXT, ListEntry); + Srb = SrbExt->Srb; + + Srb->SrbStatus = SRB_STATUS_SUCCESS; + AdapterCompleteSrb(Adapter, SrbExt); } } @@ -1081,8 +688,8 @@ __BlkifOperationName( } static VOID -ProtocolCompleteResponse( - IN PXENVBD_PROTOCOL Protocol, +RingCompleteResponse( + IN PXENVBD_RING Ring, IN ULONG64 Id, IN SHORT Status ) @@ -1090,8 +697,9 @@ ProtocolCompleteResponse( PXENVBD_REQUEST Request; PSCSI_REQUEST_BLOCK Srb; PXENVBD_SRBEXT SrbExt; + PXENVBD_PROTOCOL Protocol = Ring->Protocol; - Request = ProtocolFindRequest(Protocol, Id); + Request = RingFindRequest(Ring, Id); if (Request == NULL) return; @@ -1100,7 +708,7 @@ ProtocolCompleteResponse( switch (Status) { case BLKIF_RSP_OKAY: - ProtocolRequestCopyOutput(Request); + __RequestCopyOutput(Request); break; case BLKIF_RSP_EOPNOTSUPP: @@ -1112,8 +720,9 @@ ProtocolCompleteResponse( case BLKIF_RSP_ERROR: default: - Warning("Target[%d] : %s BLKIF_RSP_ERROR (Tag %llx)\n", + Warning("Target[%d][%u] : %s BLKIF_RSP_ERROR (Tag %llx)\n", FrontendGetTargetId(Protocol->Frontend), + Ring->Index, __BlkifOperationName(Request->Operation), Id); Srb->SrbStatus = SRB_STATUS_ERROR; @@ -1142,14 +751,15 @@ ProtocolCompleteResponse( } static BOOLEAN -ProtocolPoll( - IN PXENVBD_PROTOCOL Protocol +RingPoll( + IN PXENVBD_RING Ring ) { + PXENVBD_PROTOCOL Protocol = Ring->Protocol; BOOLEAN Retry = FALSE; ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL); - KeAcquireSpinLockAtDpcLevel(&Protocol->Lock); + KeAcquireSpinLockAtDpcLevel(&Ring->Lock); // Guard against this locked region being called after the // lock on FrontendSetState @@ -1162,8 +772,8 @@ ProtocolPoll( KeMemoryBarrier(); - rsp_prod = Protocol->Shared->rsp_prod; - rsp_cons = Protocol->Front.rsp_cons; + rsp_prod = Ring->Shared->rsp_prod; + rsp_cons = Ring->Front.rsp_cons; KeMemoryBarrier(); @@ -1173,105 +783,1018 @@ ProtocolPoll( while (rsp_cons != rsp_prod && !Retry) { blkif_response_t* rsp; - rsp = RING_GET_RESPONSE(&Protocol->Front, rsp_cons); + rsp = RING_GET_RESPONSE(&Ring->Front, rsp_cons); ++rsp_cons; - ++Protocol->Received; + ++Ring->Received; - ProtocolCompleteResponse(Protocol, rsp->id, rsp->status); + RingCompleteResponse(Ring, rsp->id, rsp->status); RtlZeroMemory(rsp, sizeof(union blkif_sring_entry)); - if (rsp_cons - Protocol->Front.rsp_cons > RING_SIZE(&Protocol->Front) / 4) + if (rsp_cons - Ring->Front.rsp_cons > RING_SIZE(&Ring->Front) / 4) Retry = TRUE; } KeMemoryBarrier(); - Protocol->Front.rsp_cons = rsp_cons; - Protocol->Shared->rsp_event = rsp_cons + 1; + Ring->Front.rsp_cons = rsp_cons; + Ring->Shared->rsp_event = rsp_cons + 1; } done: - KeReleaseSpinLockFromDpcLevel(&Protocol->Lock); + KeReleaseSpinLockFromDpcLevel(&Ring->Lock); return Retry; } __drv_requiresIRQL(DISPATCH_LEVEL) static BOOLEAN -ProtocolNotifyResponses( - IN PXENVBD_PROTOCOL Protocol +RingNotifyResponses( + IN PXENVBD_RING Ring ) { + PXENVBD_PROTOCOL Protocol = Ring->Protocol; BOOLEAN Retry = FALSE; if (!Protocol->Enabled) return FALSE; - Retry |= ProtocolPoll(Protocol); - Retry |= ProtocolSubmitRequests(Protocol); + Retry |= RingPoll(Ring); + Retry |= RingSubmitRequests(Ring); - ProtocolCompleteShutdown(Protocol); + RingCompleteShutdown(Ring); return Retry; } -KSERVICE_ROUTINE ProtocolInterrupt; +KSERVICE_ROUTINE RingInterrupt; BOOLEAN -ProtocolInterrupt( +RingInterrupt( IN PKINTERRUPT Interrupt, IN PVOID Context ) { - PXENVBD_PROTOCOL Protocol = Context; + PXENVBD_RING Ring = Context; + PXENVBD_PROTOCOL Protocol; UNREFERENCED_PARAMETER(Interrupt); + ASSERT(Ring != NULL); + Protocol = Ring->Protocol; ASSERT(Protocol != NULL); - ++Protocol->Events; + ++Ring->Events; if (!Protocol->Connected) return TRUE; - if (KeInsertQueueDpc(&Protocol->Dpc, NULL, NULL)) - ++Protocol->Dpcs; + if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL)) + ++Ring->Dpcs; return TRUE; } -KDEFERRED_ROUTINE ProtocolDpc; +KDEFERRED_ROUTINE RingDpc; VOID -ProtocolDpc( +RingDpc( __in PKDPC Dpc, __in_opt PVOID Context, __in_opt PVOID Arg1, __in_opt PVOID Arg2 ) { - PXENVBD_PROTOCOL Protocol = Context; + PXENVBD_RING Ring = Context; + PXENVBD_PROTOCOL Protocol; UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(Arg1); UNREFERENCED_PARAMETER(Arg2); + ASSERT(Ring != NULL); + Protocol = Ring->Protocol; ASSERT(Protocol != NULL); for (;;) { KIRQL Irql; BOOLEAN Retry; - KeRaiseIrql(DISPATCH_LEVEL, &Irql); - Retry = ProtocolNotifyResponses(Protocol); - KeLowerIrql(Irql); + KeRaiseIrql(DISPATCH_LEVEL, &Irql); + Retry = RingNotifyResponses(Ring); + KeLowerIrql(Irql); + + if (!Retry) + break; + } + + XENBUS_EVTCHN(Unmask, + &Protocol->EvtchnInterface, + Ring->Channel, + FALSE); +} + +static DECLSPEC_NOINLINE VOID +RingDebugCallback( + IN PVOID Argument, + IN BOOLEAN Crashing + ) +{ + PXENVBD_RING Ring = Argument; + PXENVBD_PROTOCOL Protocol = Ring->Protocol; + PXENVBD_GRANTER Granter = FrontendGetGranter(Protocol->Frontend); + ULONG Index; + + UNREFERENCED_PARAMETER(Crashing); + + XENBUS_DEBUG(Printf, + &Protocol->DebugInterface, + "Submitted: %u Received: %u\n", + Ring->Submitted, + Ring->Received); + + XENBUS_DEBUG(Printf, + &Protocol->DebugInterface, + "Events: %u Dpcs: %u\n", + Ring->Events, + Ring->Dpcs); + + XENBUS_DEBUG(Printf, + &Protocol->DebugInterface, + "Shared : 0x%p\n", + Ring->Shared); + + if (Ring->Shared) { + XENBUS_DEBUG(Printf, + &Protocol->DebugInterface, + "Shared: %d / %d - %d / %d\n", + Ring->Shared->req_prod, + Ring->Shared->req_event, + Ring->Shared->rsp_prod, + Ring->Shared->rsp_event); + } + + XENBUS_DEBUG(Printf, + &Protocol->DebugInterface, + "Front: %d / %d (%d)\n", + Ring->Front.req_prod_pvt, + Ring->Front.rsp_cons, + Ring->Front.nr_ents); + + for (Index = 0; Index < (1ul << Protocol->Order); ++Index) { + XENBUS_DEBUG(Printf, + &Protocol->DebugInterface, + "Grants[%-2d]: 0x%p (%u)\n", + Index, + Ring->Grants[Index], + GranterReference(Granter, Ring->Grants[Index])); + } + + if (Ring->Channel) { + ULONG Port = XENBUS_EVTCHN(GetPort, + &Protocol->EvtchnInterface, + Ring->Channel); + + XENBUS_DEBUG(Printf, + &Protocol->DebugInterface, + "Channel : %p (%d)\n", + Ring->Channel, + Port); + } + + XENBUS_DEBUG(Printf, + &Protocol->DebugInterface, + "BLKIF_OPs: READ=%u WRITE=%u\n", + Ring->BlkOpRead, + Ring->BlkOpWrite); + XENBUS_DEBUG(Printf, + &Protocol->DebugInterface, + "BLKIF_OPs: INDIRECT_READ=%u INDIRECT_WRITE=%u\n", + Ring->BlkOpIndirectRead, + Ring->BlkOpIndirectWrite); + XENBUS_DEBUG(Printf, + &Protocol->DebugInterface, + "BLKIF_OPs: BARRIER=%u DISCARD=%u FLUSH=%u\n", + Ring->BlkOpBarrier, + Ring->BlkOpDiscard, + Ring->BlkOpFlush); + + QueueDebugCallback(&Ring->PreparedReqs, + "Prepared ", + &Protocol->DebugInterface); + QueueDebugCallback(&Ring->SubmittedReqs, + "Submitted", + &Protocol->DebugInterface); + QueueDebugCallback(&Ring->ShutdownSrbs, + "Shutdown ", + &Protocol->DebugInterface); +} + +static NTSTATUS +RingCreate( + IN PXENVBD_PROTOCOL Protocol, + IN ULONG Index, + OUT PXENVBD_RING *Ring + ) +{ + PXENVBD_FRONTEND Frontend = Protocol->Frontend; + PROCESSOR_NUMBER ProcNumber; + ULONG Length; + NTSTATUS status; + + *Ring = __ProtocolAllocate(sizeof(XENVBD_RING)); + + status = STATUS_NO_MEMORY; + if (*Ring == NULL) + goto fail1; + + (*Ring)->Protocol = Protocol; + (*Ring)->Index = Index; + + Length = 1 + (ULONG)strlen(FrontendGetFrontendPath(Frontend)) + (ULONG)strlen("queue-xx"); + + (*Ring)->Path = __ProtocolAllocate(sizeof(CHAR) * Length); + + status = STATUS_NO_MEMORY; + if ((*Ring)->Path == NULL) + goto fail2; + + status = RtlStringCchPrintfA((*Ring)->Path, + Length, + "%s/queue-%u", + FrontendGetFrontendPath(Frontend), + Index); + if (!NT_SUCCESS(status)) + goto fail3; + + KeInitializeSpinLock(&(*Ring)->Lock); + + KeInitializeThreadedDpc(&(*Ring)->Dpc, RingDpc, *Ring); + KeSetImportanceDpc(&(*Ring)->Dpc, MediumHighImportance); + + status = KeGetProcessorNumberFromIndex(Index, &ProcNumber); + ASSERT(NT_SUCCESS(status)); + + KeSetTargetProcessorDpcEx(&(*Ring)->Dpc, &ProcNumber); + + QueueInit(&(*Ring)->PreparedReqs); + QueueInit(&(*Ring)->SubmittedReqs); + QueueInit(&(*Ring)->ShutdownSrbs); + + return STATUS_SUCCESS; + +fail3: + Error("fail3\n"); + __ProtocolFree((*Ring)->Path); + (*Ring)->Path = NULL; +fail2: + Error("fail2\n"); + (*Ring)->Index = 0; + (*Ring)->Protocol = NULL; + + ASSERT(IsZeroMemory(*Ring, sizeof(XENVBD_RING))); + __ProtocolFree(*Ring); +fail1: + Error("fail1 (%08x)\n", status); + *Ring = NULL; + return status; +} + +static VOID +RingDestroy( + IN PXENVBD_RING Ring + ) +{ + RtlZeroMemory(&Ring->PreparedReqs, sizeof(XENVBD_QUEUE)); + RtlZeroMemory(&Ring->SubmittedReqs, sizeof(XENVBD_QUEUE)); + RtlZeroMemory(&Ring->ShutdownSrbs, sizeof(XENVBD_QUEUE)); + + RtlZeroMemory(&Ring->Dpc, sizeof(KDPC)); + RtlZeroMemory(&Ring->Lock, sizeof(KSPIN_LOCK)); + + Ring->BlkOpRead = 0; + Ring->BlkOpWrite = 0; + Ring->BlkOpIndirectRead = 0; + Ring->BlkOpIndirectWrite = 0; + Ring->BlkOpBarrier = 0; + Ring->BlkOpDiscard = 0; + Ring->BlkOpFlush = 0; + + __ProtocolFree(Ring->Path); + Ring->Path = NULL; + + Ring->Index = 0; + Ring->Protocol = NULL; + + ASSERT(IsZeroMemory(Ring, sizeof(XENVBD_RING))); + __ProtocolFree(Ring); +} + +static NTSTATUS +RingConnect( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_PROTOCOL Protocol = Ring->Protocol; + PXENVBD_GRANTER Granter = FrontendGetGranter(Protocol->Frontend); + CHAR Name[MAX_NAME_LEN + 1]; + ULONG Index; + NTSTATUS status; + + Ring->Mdl = __AllocatePages(1 << Protocol->Order); + + status = STATUS_NO_MEMORY; + if (Ring->Mdl == NULL) + goto fail1; + + 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 << Protocol->Order); +#pragma warning(pop) + + for (Index = 0; Index < (1ul << Protocol->Order); ++Index) { + status = GranterGet(Granter, + MmGetMdlPfnArray(Ring->Mdl)[Index], + FALSE, + &Ring->Grants[Index]); + if (!NT_SUCCESS(status)) + goto fail2; + } + + Ring->Channel = XENBUS_EVTCHN(Open, + &Protocol->EvtchnInterface, + XENBUS_EVTCHN_TYPE_UNBOUND, + RingInterrupt, + Ring, + FrontendGetBackendDomain(Protocol->Frontend), + TRUE); + status = STATUS_NO_MEMORY; + if (Ring->Channel == NULL) + goto fail3; + + XENBUS_EVTCHN(Unmask, + &Protocol->EvtchnInterface, + Ring->Channel, + FALSE); + + status = RtlStringCchPrintfA(Name, + MAX_NAME_LEN, + __MODULE__"%s", + Ring->Path); + if (!NT_SUCCESS(status)) + goto fail4; + + status = XENBUS_DEBUG(Register, + &Protocol->DebugInterface, + Name, + RingDebugCallback, + Ring, + &Ring->DebugCallback); + if (!NT_SUCCESS(status)) + goto fail5; + + return STATUS_SUCCESS; + +fail5: + Error("fail5\n"); +fail4: + Error("fail4\n"); + XENBUS_EVTCHN(Close, + &Protocol->EvtchnInterface, + Ring->Channel); + Ring->Channel = NULL; +fail3: + Error("fail3\n"); +fail2: + Error("fail2\n"); + for (Index = 0; Index < (1ul << Protocol->Order); ++Index) { + if (Ring->Grants[Index] == NULL) + continue; + + GranterPut(Granter, Ring->Grants[Index]); + Ring->Grants[Index] = NULL; + } + + RtlZeroMemory(&Ring->Front, sizeof(blkif_front_ring_t)); + + __FreePages(Ring->Mdl); + Ring->Shared = NULL; + Ring->Mdl = NULL; +fail1: + Error("fail1 (%08x)\n", status); + return status; +} + +static NTSTATUS +RingStoreWrite( + IN PXENVBD_RING Ring, + IN PVOID Transaction + ) +{ + PXENVBD_PROTOCOL Protocol = Ring->Protocol; + PXENVBD_GRANTER Granter = FrontendGetGranter(Protocol->Frontend); + PCHAR Path; + ULONG Port; + NTSTATUS status; + + if (FrontendGetMultiQueueMaxQueues(Protocol->Frontend) > 1) + Path = Ring->Path; + else + Path = FrontendGetFrontendPath(Protocol->Frontend); + + if (Protocol->Order == 0) { + status = XENBUS_STORE(Printf, + &Protocol->StoreInterface, + Transaction, + Path, + "ring-ref", + "%u", + GranterReference(Granter, Ring->Grants[0])); + if (!NT_SUCCESS(status)) + return status; + } + else { + ULONG Index; + + for (Index = 0; Index < (1ul << Protocol->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, + &Protocol->StoreInterface, + Transaction, + Path, + Name, + "%u", + GranterReference(Granter, Ring->Grants[Index])); + if (!NT_SUCCESS(status)) + return status; + } + } + + Port = XENBUS_EVTCHN(GetPort, + &Protocol->EvtchnInterface, + Ring->Channel); + + status = XENBUS_STORE(Printf, + &Protocol->StoreInterface, + Transaction, + Path, + "event-channel", + "%u", + Port); + if (!NT_SUCCESS(status)) + return status; + + return STATUS_SUCCESS; +} + +static VOID +RingDisconnect( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_PROTOCOL Protocol = Ring->Protocol; + PXENVBD_GRANTER Granter = FrontendGetGranter(Protocol->Frontend); + ULONG Index; + + ASSERT3U(Ring->Submitted, == , Ring->Received); + + XENBUS_DEBUG(Deregister, + &Protocol->DebugInterface, + Ring->DebugCallback); + Ring->DebugCallback = NULL; + + XENBUS_EVTCHN(Close, + &Protocol->EvtchnInterface, + Ring->Channel); + Ring->Channel = NULL; + + for (Index = 0; Index < (1ul << Protocol->Order); ++Index) { + if (Ring->Grants[Index] == NULL) + continue; + + GranterPut(Granter, Ring->Grants[Index]); + Ring->Grants[Index] = NULL; + } + + RtlZeroMemory(&Ring->Front, sizeof(blkif_front_ring_t)); + + __FreePages(Ring->Mdl); + Ring->Shared = NULL; + Ring->Mdl = NULL; + Ring->Events = 0; + Ring->Dpcs = 0; + Ring->Submitted = 0; + Ring->Received = 0; +} + +static VOID +RingEnable( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_PROTOCOL Protocol = Ring->Protocol; + + XENBUS_EVTCHN(Trigger, + &Protocol->EvtchnInterface, + Ring->Channel); +} + +static VOID +RingDisable( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_PROTOCOL Protocol = Ring->Protocol; + ULONG Count; + KIRQL Irql; + PXENVBD_TARGET Target = FrontendGetTarget(Protocol->Frontend); + PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target); + + // 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, + &Protocol->EvtchnInterface, + Ring->Channel); + StorPortStallExecution(1000); // 1000 micro-seconds + ++Count; + } + + Verbose("Target[%d][%u] : %u Submitted requests left (%u iterrations)\n", + FrontendGetTargetId(Protocol->Frontend), + Ring->Index, + 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 + + ProtocolPutRequest(Protocol, Request); + + if (InterlockedDecrement(&SrbExt->RequestCount) == 0) + AdapterCompleteSrb(Adapter, SrbExt); + } +} + +static VOID +RingTrigger( + IN PXENVBD_RING Ring + ) +{ + PXENVBD_PROTOCOL Protocol = Ring->Protocol; + + XENBUS_EVTCHN(Trigger, + &Protocol->EvtchnInterface, + Ring->Channel); +} + +static FORCEINLINE MM_PAGE_PRIORITY +__ProtocolPriority( + IN PXENVBD_PROTOCOL Protocol + ) +{ + PXENVBD_CAPS Caps = FrontendGetCaps(Protocol->Frontend); + if (!(Caps->Paging || + Caps->Hibernation || + Caps->DumpFile)) + return NormalPagePriority; + + return HighPagePriority; +} + +static BOOLEAN +ProtocolPrepareSegment( + IN PXENVBD_PROTOCOL Protocol, + 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(Protocol->Frontend); + const ULONG SectorSize = FrontendGetDiskInfo(Protocol->Frontend)->SectorSize; + const ULONG SectorsPerPage = __SectorsPerPage(SectorSize); + PXENVBD_TARGET Target = FrontendGetTarget(Protocol->Frontend); + PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target); + + Pfn = AdapterGetNextSGEntry(Adapter, + SrbExt, + 0, + &Offset, + &Length); + if ((Offset & (SectorSize - 1)) == 0 && + (Length & (SectorSize - 1)) == 0) { + ++Protocol->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); + + ASSERT3U((Length / SectorSize), == , *SectorsNow); + } + else { + PXENVBD_BOUNCE Bounce; + PMDL Mdl; + + ++Protocol->SegsBounced; + // get first sector, last sector and count + Segment->FirstSector = 0; + *SectorsNow = __min(SectorsLeft, SectorsPerPage); + Segment->LastSector = (UCHAR)(*SectorsNow - 1); + + Bounce = AdapterGetBounce(Adapter); + if (Bounce == NULL) + goto fail1; + Segment->Bounce = Bounce; + +#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; + + if (Length < *SectorsNow * SectorSize) { + Pfn = AdapterGetNextSGEntry(Adapter, + SrbExt, + Length, + &Offset, + &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)); + + Bounce->SourcePtr = MmMapLockedPagesSpecifyCache(Mdl, + KernelMode, + MmCached, + NULL, + FALSE, + __ProtocolPriority(Protocol)); + if (Bounce->SourcePtr == NULL) + goto fail2; + + ASSERT3P(MmGetMdlPfnArray(Mdl)[0], == , Bounce->SourcePfn[0]); + ASSERT3P(MmGetMdlPfnArray(Mdl)[1], == , Bounce->SourcePfn[1]); + + // copy contents in + if (ReadOnly) { // Operation == BLKIF_OP_WRITE + RtlCopyMemory(Bounce->BouncePtr, + Bounce->SourcePtr, + MmGetMdlByteCount(&Bounce->SourceMdl)); + } + + Pfn = MmGetMdlPfnArray(Bounce->BounceMdl)[0]; + } + + // 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 +ProtocolPrepareBlkifReadWrite( + IN PXENVBD_PROTOCOL Protocol, + IN PXENVBD_REQUEST Request, + IN PXENVBD_SRBEXT SrbExt, + IN ULONG MaxSegments, + IN ULONG64 SectorStart, + IN ULONG SectorsLeft, + OUT PULONG SectorsDone + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + UCHAR Operation; + BOOLEAN ReadOnly; + ULONG Index; + __Operation(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 = ProtocolGetSegment(Protocol); + if (Segment == NULL) + goto fail1; + + InsertTailList(&Request->Segments, &Segment->ListEntry); + ++Request->NrSegments; + + if (!ProtocolPrepareSegment(Protocol, + 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 +ProtocolPrepareBlkifIndirect( + IN PXENVBD_PROTOCOL Protocol, + 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 = ProtocolGetIndirect(Protocol); + if (Indirect == NULL) + goto fail1; + InsertTailList(&Request->Indirects, &Indirect->ListEntry); + + NrSegments += XENVBD_MAX_SEGMENTS_PER_PAGE; + } + + return TRUE; + +fail1: + return FALSE; +} + +static FORCEINLINE ULONG +ProtocolUseIndirect( + IN PXENVBD_PROTOCOL Protocol, + IN ULONG SectorsLeft + ) +{ + const ULONG SectorsPerPage = __SectorsPerPage(FrontendGetDiskInfo(Protocol->Frontend)->SectorSize); + const ULONG MaxIndirectSegs = FrontendGetFeatures(Protocol->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 VOID +ProtocolCancelRequestList( + IN PXENVBD_PROTOCOL Protocol, + IN PLIST_ENTRY List + ) +{ + for (;;) { + PXENVBD_REQUEST Request; + PLIST_ENTRY ListEntry; + + ListEntry = RemoveHeadList(List); + if (ListEntry == List) + break; + + Request = CONTAINING_RECORD(ListEntry, XENVBD_REQUEST, ListEntry); + ProtocolPutRequest(Protocol, Request); + } +} + +static BOOLEAN +ProtocolPrepareReadWrite( + IN PXENVBD_PROTOCOL Protocol, + IN PXENVBD_SRBEXT SrbExt, + IN PLIST_ENTRY List + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + ULONG64 SectorStart = Cdb_LogicalBlock(Srb); + ULONG SectorsLeft = Cdb_TransferBlock(Srb); + + Srb->SrbStatus = SRB_STATUS_PENDING; + + SrbExt->RequestCount = 0; + + while (SectorsLeft > 0) { + ULONG MaxSegments; + ULONG SectorsDone = 0; + PXENVBD_REQUEST Request; + + Request = ProtocolGetRequest(Protocol); + if (Request == NULL) + goto fail1; + InsertTailList(List, &Request->ListEntry); + InterlockedIncrement(&SrbExt->RequestCount); + + Request->SrbExt = SrbExt; + MaxSegments = ProtocolUseIndirect(Protocol, SectorsLeft); + + if (!ProtocolPrepareBlkifReadWrite(Protocol, + Request, + SrbExt, + MaxSegments, + SectorStart, + SectorsLeft, + &SectorsDone)) + goto fail2; + + if (MaxSegments > BLKIF_MAX_SEGMENTS_PER_REQUEST) { + if (!ProtocolPrepareBlkifIndirect(Protocol, Request)) + goto fail3; + } + + SectorsLeft -= SectorsDone; + SectorStart += SectorsDone; + } + + return TRUE; + +fail3: +fail2: +fail1: + ProtocolCancelRequestList(Protocol, List); + SrbExt->RequestCount = 0; + Srb->SrbStatus = SRB_STATUS_ERROR; + return FALSE; +} + +static BOOLEAN +ProtocolPrepareSyncCache( + IN PXENVBD_PROTOCOL Protocol, + IN PXENVBD_SRBEXT SrbExt, + IN PLIST_ENTRY List + ) +{ + PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PXENVBD_REQUEST Request; + UCHAR Operation; + + Srb->SrbStatus = SRB_STATUS_PENDING; + + if (FrontendGetDiskInfo(Protocol->Frontend)->FlushCache) + Operation = BLKIF_OP_FLUSH_DISKCACHE; + else + Operation = BLKIF_OP_WRITE_BARRIER; + + SrbExt->RequestCount = 0; + + Request = ProtocolGetRequest(Protocol); + if (Request == NULL) + goto fail1; + InsertTailList(List, &Request->ListEntry); + InterlockedIncrement(&SrbExt->RequestCount); + + Request->SrbExt = SrbExt; + Request->Operation = Operation; + Request->FirstSector = Cdb_LogicalBlock(Srb); + + return TRUE; + +fail1: + ProtocolCancelRequestList(Protocol, List); + SrbExt->RequestCount = 0; + Srb->SrbStatus = SRB_STATUS_ERROR; + return FALSE; +} + +static BOOLEAN +ProtocolPrepareUnmap( + IN PXENVBD_PROTOCOL Protocol, + IN PXENVBD_SRBEXT SrbExt, + IN PLIST_ENTRY List + ) +{ + 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; + + Srb->SrbStatus = SRB_STATUS_PENDING; + + SrbExt->RequestCount = 0; + + for (Index = 0; Index < Count; ++Index) { + PUNMAP_BLOCK_DESCRIPTOR Descr = &Unmap->Descriptors[Index]; + PXENVBD_REQUEST Request; + + Request = ProtocolGetRequest(Protocol); + 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; + } + + return TRUE; + +fail1: + ProtocolCancelRequestList(Protocol, List); + SrbExt->RequestCount = 0; + Srb->SrbStatus = SRB_STATUS_ERROR; + return FALSE; +} + +static FORCEINLINE BOOLEAN +ProtocolPrepareRequest( + IN PXENVBD_PROTOCOL Protocol, + IN PXENVBD_SRBEXT SrbExt, + IN PLIST_ENTRY List + ) +{ + switch (Cdb_OperationEx(SrbExt->Srb)) { + case SCSIOP_READ: + case SCSIOP_WRITE: + return ProtocolPrepareReadWrite(Protocol, + SrbExt, + List); + + case SCSIOP_SYNCHRONIZE_CACHE: + return ProtocolPrepareSyncCache(Protocol, + SrbExt, + List); + + case SCSIOP_UNMAP: + return ProtocolPrepareUnmap(Protocol, + SrbExt, + List); - if (!Retry) - break; + default: + ASSERT(FALSE); + return FALSE; } - - XENBUS_EVTCHN(Unmask, - &Protocol->EvtchnInterface, - Protocol->Channel, - FALSE); } static DECLSPEC_NOINLINE VOID @@ -1281,102 +1804,19 @@ ProtocolDebugCallback( ) { PXENVBD_PROTOCOL Protocol = Argument; - PXENVBD_GRANTER Granter = FrontendGetGranter(Protocol->Frontend); - ULONG Index; UNREFERENCED_PARAMETER(Crashing); - XENBUS_DEBUG(Printf, - &Protocol->DebugInterface, - "Submitted: %u Received: %u\n", - Protocol->Submitted, - Protocol->Received); - - XENBUS_DEBUG(Printf, - &Protocol->DebugInterface, - "Events: %u Dpcs: %u\n", - Protocol->Events, - Protocol->Dpcs); - - XENBUS_DEBUG(Printf, - &Protocol->DebugInterface, - "Shared : 0x%p\n", - Protocol->Shared); - - if (Protocol->Shared) { - XENBUS_DEBUG(Printf, - &Protocol->DebugInterface, - "Shared: %d / %d - %d / %d\n", - Protocol->Shared->req_prod, - Protocol->Shared->req_event, - Protocol->Shared->rsp_prod, - Protocol->Shared->rsp_event); - } - - XENBUS_DEBUG(Printf, - &Protocol->DebugInterface, - "Front: %d / %d (%d)\n", - Protocol->Front.req_prod_pvt, - Protocol->Front.rsp_cons, - Protocol->Front.nr_ents); - XENBUS_DEBUG(Printf, &Protocol->DebugInterface, "Order: %d\n", Protocol->Order); - for (Index = 0; Index < (1ul << Protocol->Order); ++Index) { - XENBUS_DEBUG(Printf, - &Protocol->DebugInterface, - "Grants[%-2d]: 0x%p (%u)\n", - Index, - Protocol->Grants[Index], - GranterReference(Granter, Protocol->Grants[Index])); - } - - if (Protocol->Channel) { - ULONG Port = XENBUS_EVTCHN(GetPort, - &Protocol->EvtchnInterface, - Protocol->Channel); - - XENBUS_DEBUG(Printf, - &Protocol->DebugInterface, - "Channel : %p (%d)\n", - Protocol->Channel, - Port); - } - - XENBUS_DEBUG(Printf, - &Protocol->DebugInterface, - "BLKIF_OPs: READ=%u WRITE=%u\n", - Protocol->BlkOpRead, - Protocol->BlkOpWrite); - XENBUS_DEBUG(Printf, - &Protocol->DebugInterface, - "BLKIF_OPs: INDIRECT_READ=%u INDIRECT_WRITE=%u\n", - Protocol->BlkOpIndirectRead, - Protocol->BlkOpIndirectWrite); - XENBUS_DEBUG(Printf, - &Protocol->DebugInterface, - "BLKIF_OPs: BARRIER=%u DISCARD=%u FLUSH=%u\n", - Protocol->BlkOpBarrier, - Protocol->BlkOpDiscard, - Protocol->BlkOpFlush); XENBUS_DEBUG(Printf, &Protocol->DebugInterface, "Segments Granted=%llu Bounced=%llu\n", Protocol->SegsGranted, Protocol->SegsBounced); - - QueueDebugCallback(&Protocol->PreparedReqs, - "Prepared ", - &Protocol->DebugInterface); - QueueDebugCallback(&Protocol->SubmittedReqs, - "Submitted", - &Protocol->DebugInterface); - QueueDebugCallback(&Protocol->ShutdownSrbs, - "Shutdown ", - &Protocol->DebugInterface); } static DECLSPEC_NOINLINE VOID @@ -1391,7 +1831,7 @@ ProtocolAcquireLock( static DECLSPEC_NOINLINE VOID ProtocolReleaseLock( IN PVOID Argument - ) +) { PXENVBD_PROTOCOL Protocol = Argument; KeReleaseSpinLockFromDpcLevel(&Protocol->Lock); @@ -1426,7 +1866,7 @@ static DECLSPEC_NOINLINE NTSTATUS ProtocolSegmentCtor( IN PVOID Argument, IN PVOID Object - ) +) { UNREFERENCED_PARAMETER(Argument); UNREFERENCED_PARAMETER(Object); @@ -1488,12 +1928,13 @@ ProtocolIndirectDtor( NTSTATUS ProtocolCreate( IN PXENVBD_FRONTEND Frontend, - OUT PXENVBD_PROTOCOL* Protocol + OUT PXENVBD_PROTOCOL* Protocol ) { PXENVBD_TARGET Target = FrontendGetTarget(Frontend); PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target); CHAR Name[MAX_NAME_LEN]; + ULONG Index; NTSTATUS status; *Protocol = __ProtocolAllocate(sizeof(XENVBD_PROTOCOL)); @@ -1504,12 +1945,6 @@ ProtocolCreate( (*Protocol)->Frontend = Frontend; KeInitializeSpinLock(&(*Protocol)->Lock); - KeInitializeThreadedDpc(&(*Protocol)->Dpc, ProtocolDpc, *Protocol); - KeSetImportanceDpc(&(*Protocol)->Dpc, MediumHighImportance); - - QueueInit(&(*Protocol)->PreparedReqs); - QueueInit(&(*Protocol)->SubmittedReqs); - QueueInit(&(*Protocol)->ShutdownSrbs); AdapterGetCacheInterface(Adapter, &(*Protocol)->CacheInterface); @@ -1580,8 +2015,41 @@ ProtocolCreate( if (!NT_SUCCESS(status)) goto fail8; + (*Protocol)->NumQueues = FrontendGetMultiQueueMaxQueues(Frontend); + if ((*Protocol)->NumQueues == 0) + (*Protocol)->NumQueues = 1; + (*Protocol)->Rings = __ProtocolAllocate(sizeof(PXENVBD_RING) * (*Protocol)->NumQueues); + + status = STATUS_NO_MEMORY; + if ((*Protocol)->Rings == NULL) + goto fail9; + + for (Index = 0; Index < (*Protocol)->NumQueues; ++Index) { + status = RingCreate(*Protocol, + Index, + &(*Protocol)->Rings[Index]); + if (!NT_SUCCESS(status)) + goto fail10; + } + return STATUS_SUCCESS; +fail10: + Error("fail10\n"); + for (Index = 0; Index < (*Protocol)->NumQueues; ++Index) { + if ((*Protocol)->Rings[Index]) + RingDestroy((*Protocol)->Rings[Index]); + (*Protocol)->Rings[Index] = NULL; + } + __ProtocolFree((*Protocol)->Rings); + (*Protocol)->Rings = NULL; +fail9: + Error("fail9\n"); + (*Protocol)->NumQueues = 0; + XENBUS_CACHE(Destroy, + &(*Protocol)->CacheInterface, + (*Protocol)->IndirectCache); + (*Protocol)->IndirectCache = NULL; fail8: Error("fail8\n"); fail7: @@ -1608,13 +2076,8 @@ fail2: Error("fail2\n"); RtlZeroMemory(&(*Protocol)->CacheInterface, - sizeof (XENBUS_CACHE_INTERFACE)); + sizeof(XENBUS_CACHE_INTERFACE)); - RtlZeroMemory(&(*Protocol)->PreparedReqs, sizeof(XENVBD_QUEUE)); - RtlZeroMemory(&(*Protocol)->SubmittedReqs, sizeof(XENVBD_QUEUE)); - RtlZeroMemory(&(*Protocol)->ShutdownSrbs, sizeof(XENVBD_QUEUE)); - - RtlZeroMemory(&(*Protocol)->Dpc, sizeof(KDPC)); RtlZeroMemory(&(*Protocol)->Lock, sizeof(KSPIN_LOCK)); (*Protocol)->Frontend = NULL; @@ -1631,6 +2094,19 @@ ProtocolDestroy( IN PXENVBD_PROTOCOL Protocol ) { + ULONG Index; + + for (Index = 0; Index < Protocol->NumQueues; ++Index) { + if (Protocol->Rings[Index]) + RingDestroy(Protocol->Rings[Index]); + Protocol->Rings[Index] = 0; + } + + __ProtocolFree(Protocol->Rings); + Protocol->Rings = NULL; + + Protocol->NumQueues = 0; + XENBUS_CACHE(Destroy, &Protocol->CacheInterface, Protocol->IndirectCache); @@ -1650,26 +2126,14 @@ ProtocolDestroy( &Protocol->CacheInterface); RtlZeroMemory(&Protocol->CacheInterface, - sizeof (XENBUS_CACHE_INTERFACE)); + sizeof(XENBUS_CACHE_INTERFACE)); - RtlZeroMemory(&Protocol->PreparedReqs, sizeof(XENVBD_QUEUE)); - RtlZeroMemory(&Protocol->SubmittedReqs, sizeof(XENVBD_QUEUE)); - RtlZeroMemory(&Protocol->ShutdownSrbs, sizeof(XENVBD_QUEUE)); + Protocol->SegsGranted = 0; + Protocol->SegsBounced = 0; - RtlZeroMemory(&Protocol->Dpc, sizeof(KDPC)); RtlZeroMemory(&Protocol->Lock, sizeof(KSPIN_LOCK)); Protocol->Frontend = NULL; - Protocol->BlkOpRead = 0; - Protocol->BlkOpWrite = 0; - Protocol->BlkOpIndirectRead = 0; - Protocol->BlkOpIndirectWrite = 0; - Protocol->BlkOpBarrier = 0; - Protocol->BlkOpDiscard = 0; - Protocol->BlkOpFlush = 0; - Protocol->SegsGranted = 0; - Protocol->SegsBounced = 0; - ASSERT(IsZeroMemory(Protocol, sizeof(XENVBD_PROTOCOL))); __ProtocolFree(Protocol); } @@ -1681,7 +2145,6 @@ ProtocolConnect( { PXENVBD_TARGET Target = FrontendGetTarget(Protocol->Frontend); PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target); - PXENVBD_GRANTER Granter = FrontendGetGranter(Protocol->Frontend); PCHAR Buffer; ULONG Index; NTSTATUS status; @@ -1730,48 +2193,12 @@ ProtocolConnect( Protocol->Order = 0; } - Protocol->Mdl = __AllocatePages(1 << Protocol->Order); - - status = STATUS_NO_MEMORY; - if (Protocol->Mdl == NULL) - goto fail4; - - Protocol->Shared = MmGetSystemAddressForMdlSafe(Protocol->Mdl, - NormalPagePriority); - ASSERT(Protocol->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(Protocol->Shared); - FRONT_RING_INIT(&Protocol->Front, Protocol->Shared, PAGE_SIZE << Protocol->Order); -#pragma warning(pop) - - for (Index = 0; Index < (1ul << Protocol->Order); ++Index) { - status = GranterGet(Granter, - MmGetMdlPfnArray(Protocol->Mdl)[Index], - FALSE, - &Protocol->Grants[Index]); + for (Index = 0; Index < Protocol->NumQueues; ++Index) { + status = RingConnect(Protocol->Rings[Index]); if (!NT_SUCCESS(status)) - goto fail5; + goto fail4; } - Protocol->Channel = XENBUS_EVTCHN(Open, - &Protocol->EvtchnInterface, - XENBUS_EVTCHN_TYPE_UNBOUND, - ProtocolInterrupt, - Protocol, - FrontendGetBackendDomain(Protocol->Frontend), - TRUE); - status = STATUS_NO_MEMORY; - if (Protocol->Channel == NULL) - goto fail6; - - XENBUS_EVTCHN(Unmask, - &Protocol->EvtchnInterface, - Protocol->Channel, - FALSE); - status = XENBUS_DEBUG(Register, &Protocol->DebugInterface, __MODULE__"|PROTOCOL", @@ -1779,38 +2206,20 @@ ProtocolConnect( Protocol, &Protocol->DebugCallback); if (!NT_SUCCESS(status)) - goto fail7; + goto fail5; Protocol->Connected = TRUE; return STATUS_SUCCESS; -fail7: - Error("fail7\n"); - XENBUS_EVTCHN(Close, - &Protocol->EvtchnInterface, - Protocol->Channel); - Protocol->Channel = NULL; -fail6: - Error("fail6\n"); fail5: Error("fail5\n"); - for (Index = 0; Index < (1ul << Protocol->Order); ++Index) { - if (Protocol->Grants[Index] == NULL) - continue; - - GranterPut(Granter, Protocol->Grants[Index]); - Protocol->Grants[Index] = NULL; - } - - RtlZeroMemory(&Protocol->Front, sizeof(blkif_front_ring_t)); - - __FreePages(Protocol->Mdl); - Protocol->Shared = NULL; - Protocol->Mdl = NULL; - - Protocol->Order = 0; + Index = Protocol->NumQueues; fail4: Error("fail4\n"); + while (Index-- != 0) { + RingDisconnect(Protocol->Rings[Index]); + } + Protocol->Order = 0; XENBUS_DEBUG(Release, &Protocol->DebugInterface); fail3: Error("fail3\n"); @@ -1834,26 +2243,20 @@ fail1: NTSTATUS ProtocolStoreWrite( IN PXENVBD_PROTOCOL Protocol, - IN PVOID Transaction + IN PVOID Transaction ) { - PXENVBD_GRANTER Granter = FrontendGetGranter(Protocol->Frontend); - ULONG Port; - NTSTATUS status; + ULONG Index; + NTSTATUS status; - if (Protocol->Order == 0) { - status = XENBUS_STORE(Printf, - &Protocol->StoreInterface, - Transaction, - FrontendGetFrontendPath(Protocol->Frontend), - "ring-ref", - "%u", - GranterReference(Granter, Protocol->Grants[0])); + for (Index = 0; Index < Protocol->NumQueues; ++Index) { + status = RingStoreWrite(Protocol->Rings[Index], + Transaction); if (!NT_SUCCESS(status)) return status; - } else { - ULONG Index; + } + if (Protocol->Order != 0) { status = XENBUS_STORE(Printf, &Protocol->StoreInterface, Transaction, @@ -1863,49 +2266,24 @@ ProtocolStoreWrite( Protocol->Order); if (!NT_SUCCESS(status)) return status; - - for (Index = 0; Index < (1ul << Protocol->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, - &Protocol->StoreInterface, - Transaction, - FrontendGetFrontendPath(Protocol->Frontend), - Name, - "%u", - GranterReference(Granter, Protocol->Grants[Index])); - if (!NT_SUCCESS(status)) - return status; - } } status = XENBUS_STORE(Printf, &Protocol->StoreInterface, Transaction, FrontendGetFrontendPath(Protocol->Frontend), - "protocol", - XEN_IO_PROTO_ABI); + "multi-queue-num-queues", + "%u", + Protocol->NumQueues); if (!NT_SUCCESS(status)) return status; - Port = XENBUS_EVTCHN(GetPort, - &Protocol->EvtchnInterface, - Protocol->Channel); - status = XENBUS_STORE(Printf, &Protocol->StoreInterface, Transaction, FrontendGetFrontendPath(Protocol->Frontend), - "event-channel", - "%u", - Port); + "protocol", + XEN_IO_PROTO_ABI); if (!NT_SUCCESS(status)) return status; @@ -1917,12 +2295,13 @@ ProtocolEnable( IN PXENVBD_PROTOCOL Protocol ) { + ULONG Index; + ASSERT(Protocol->Enabled == FALSE); Protocol->Enabled = TRUE; - XENBUS_EVTCHN(Trigger, - &Protocol->EvtchnInterface, - Protocol->Channel); + for (Index = 0; Index < Protocol->NumQueues; ++Index) + RingEnable(Protocol->Rings[Index]); } VOID @@ -1930,56 +2309,13 @@ ProtocolDisable( IN PXENVBD_PROTOCOL Protocol ) { - ULONG Count; - KIRQL Irql; - PXENVBD_TARGET Target = FrontendGetTarget(Protocol->Frontend); - PXENVBD_ADAPTER Adapter = TargetGetAdapter(Target); + ULONG Index; ASSERT(Protocol->Enabled == TRUE); Protocol->Enabled = FALSE; - // poll ring and send event channel notification every 1ms (for up to 3 minutes) - Count = 0; - while (QueueCount(&Protocol->SubmittedReqs)) { - if (Count > 180000) - break; - KeRaiseIrql(DISPATCH_LEVEL, &Irql); - ProtocolPoll(Protocol); - KeLowerIrql(Irql); - XENBUS_EVTCHN(Send, - &Protocol->EvtchnInterface, - Protocol->Channel); - StorPortStallExecution(1000); // 1000 micro-seconds - ++Count; - } - - Verbose("Target[%d] : %u Submitted requests left (%u iterrations)\n", - FrontendGetTargetId(Protocol->Frontend), - QueueCount(&Protocol->SubmittedReqs), - Count); - - // Fail PreparedReqs - for (;;) { - PXENVBD_SRBEXT SrbExt; - PSCSI_REQUEST_BLOCK Srb; - PXENVBD_REQUEST Request; - PLIST_ENTRY ListEntry; - - ListEntry = QueuePop(&Protocol->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 - - ProtocolPutRequest(Protocol, Request); - - if (InterlockedDecrement(&SrbExt->RequestCount) == 0) - AdapterCompleteSrb(Adapter, SrbExt); - } + for (Index = 0; Index < Protocol->NumQueues; ++Index) + RingDisable(Protocol->Rings[Index]); } VOID @@ -1987,10 +2323,8 @@ ProtocolDisconnect( IN PXENVBD_PROTOCOL Protocol ) { - PXENVBD_GRANTER Granter = FrontendGetGranter(Protocol->Frontend); ULONG Index; - ASSERT3U(Protocol->Submitted, ==, Protocol->Received); ASSERT(Protocol->Connected); Protocol->Connected = FALSE; @@ -1999,24 +2333,8 @@ ProtocolDisconnect( Protocol->DebugCallback); Protocol->DebugCallback = NULL; - XENBUS_EVTCHN(Close, - &Protocol->EvtchnInterface, - Protocol->Channel); - Protocol->Channel = NULL; - - for (Index = 0; Index < (1ul << Protocol->Order); ++Index) { - if (Protocol->Grants[Index] == NULL) - continue; - - GranterPut(Granter, Protocol->Grants[Index]); - Protocol->Grants[Index] = NULL; - } - - RtlZeroMemory(&Protocol->Front, sizeof(blkif_front_ring_t)); - - __FreePages(Protocol->Mdl); - Protocol->Shared = NULL; - Protocol->Mdl = NULL; + for (Index = 0; Index < Protocol->NumQueues; ++Index) + RingDisconnect(Protocol->Rings[Index]); Protocol->Order = 0; @@ -2030,11 +2348,6 @@ ProtocolDisconnect( sizeof(XENBUS_EVTCHN_INTERFACE)); RtlZeroMemory(&Protocol->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); - - Protocol->Events = 0; - Protocol->Dpcs = 0; - Protocol->Submitted = 0; - Protocol->Received = 0; } VOID @@ -2042,12 +2355,29 @@ ProtocolTrigger( IN PXENVBD_PROTOCOL Protocol ) { + ULONG Index; + if (!Protocol->Enabled) return; - XENBUS_EVTCHN(Trigger, - &Protocol->EvtchnInterface, - Protocol->Channel); + for (Index = 0; Index < Protocol->NumQueues; ++Index) + RingTrigger(Protocol->Rings[Index]); +} + +static FORCEINLINE PXENVBD_RING +__ProtocolGetRing( + IN PXENVBD_PROTOCOL Protocol + ) +{ + ULONG Index; + + if (Protocol->NumQueues == 0) + return Protocol->Rings[0]; + + Index = KeGetCurrentProcessorNumberEx(NULL) % Protocol->NumQueues; + ASSERT(Index < Protocol->NumQueues); + + return Protocol->Rings[Index]; } BOOLEAN @@ -2057,17 +2387,26 @@ ProtocolQueueRequest( ) { PSCSI_REQUEST_BLOCK Srb = SrbExt->Srb; + PXENVBD_RING Ring; + LIST_ENTRY List; + + InitializeListHead(&List); if (!Protocol->Enabled) goto fail1; - if (!ProtocolPrepareRequest(Protocol, SrbExt)) + if (!ProtocolPrepareRequest(Protocol, SrbExt, &List)) goto fail2; - if (ProtocolSubmitRequests(Protocol)) { + Ring = __ProtocolGetRing(Protocol); + ASSERT(Ring != NULL); + + RingQueueRequestList(Ring, &List); + + if (RingSubmitRequests(Ring)) { // more prepared-reqs to submit - if (KeInsertQueueDpc(&Protocol->Dpc, NULL, NULL)) - ++Protocol->Dpcs; + if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL)) + ++Ring->Dpcs; } return TRUE; @@ -2081,15 +2420,20 @@ fail1: VOID ProtocolQueueShutdown( IN PXENVBD_PROTOCOL Protocol, - IN PXENVBD_SRBEXT SrbExt + IN PXENVBD_SRBEXT SrbExt ) { - QueueAppend(&Protocol->ShutdownSrbs, + PXENVBD_RING Ring; + + Ring = __ProtocolGetRing(Protocol); + ASSERT(Ring != NULL); + + QueueAppend(&Ring->ShutdownSrbs, &SrbExt->ListEntry); if (!Protocol->Enabled) return; - if (KeInsertQueueDpc(&Protocol->Dpc, NULL, NULL)) - ++Protocol->Dpcs; + if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL)) + ++Ring->Dpcs; } -- 2.16.2.windows.1 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |