[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [win-pv-devel] [RFC PATCH 4/6] Add initial multi-queue support



> -----Original Message-----
> From: win-pv-devel [mailto:win-pv-devel-bounces@xxxxxxxxxxxxxxxxxxxx] On
> Behalf Of owensm
> Sent: 03 May 2018 12:03
> To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> Cc: Owen Smith <owen.smith@xxxxxxxxxx>
> Subject: [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.
> 

We need to expose the fact we have multiple underlying queues to the stack 
otherwise we're going to have to maintain a total ordering on SRBs to avoid the 
possibility of writes to a block getting re-ordered ahead of reads from the 
same block, or vice versa.

  Paul

> 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
_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/win-pv-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.