Home | History | Annotate | Download | only in XenPvBlkDxe
      1 /** @file
      2   Minimal block driver for Mini-OS.
      3 
      4   Copyright (c) 2007-2008 Samuel Thibault.
      5   Copyright (C) 2014, Citrix Ltd.
      6   Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
      7 
      8   Redistribution and use in source and binary forms, with or without
      9   modification, are permitted provided that the following conditions
     10   are met:
     11   1. Redistributions of source code must retain the above copyright
     12      notice, this list of conditions and the following disclaimer.
     13   2. Redistributions in binary form must reproduce the above copyright
     14      notice, this list of conditions and the following disclaimer in the
     15      documentation and/or other materials provided with the distribution.
     16 
     17   THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     18   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20   ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
     21   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27   SUCH DAMAGE.
     28 **/
     29 
     30 #include <Library/PrintLib.h>
     31 #include <Library/DebugLib.h>
     32 
     33 #include "BlockFront.h"
     34 
     35 #include <IndustryStandard/Xen/io/protocols.h>
     36 #include <IndustryStandard/Xen/io/xenbus.h>
     37 
     38 /**
     39   Helper to read an integer from XenStore.
     40 
     41   If the number overflows according to the range defined by UINT64,
     42   then ASSERT().
     43 
     44   @param This         A pointer to a XENBUS_PROTOCOL instance.
     45   @param Node         The XenStore node to read from.
     46   @param FromBackend  Read frontend or backend value.
     47   @param ValuePtr     Where to put the value.
     48 
     49   @retval XENSTORE_STATUS_SUCCESS  If succefull, will update ValuePtr.
     50   @return                          Any other return value indicate the error,
     51                                    ValuePtr is not updated in this case.
     52 **/
     53 STATIC
     54 XENSTORE_STATUS
     55 XenBusReadUint64 (
     56   IN  XENBUS_PROTOCOL *This,
     57   IN  CONST CHAR8     *Node,
     58   IN  BOOLEAN         FromBackend,
     59   OUT UINT64          *ValuePtr
     60   )
     61 {
     62   XENSTORE_STATUS Status;
     63   CHAR8 *Ptr;
     64 
     65   if (!FromBackend) {
     66     Status = This->XsRead (This, XST_NIL, Node, (VOID**)&Ptr);
     67   } else {
     68     Status = This->XsBackendRead (This, XST_NIL, Node, (VOID**)&Ptr);
     69   }
     70   if (Status != XENSTORE_STATUS_SUCCESS) {
     71     return Status;
     72   }
     73   // AsciiStrDecimalToUint64 will ASSERT if Ptr overflow UINT64.
     74   *ValuePtr = AsciiStrDecimalToUint64 (Ptr);
     75   FreePool (Ptr);
     76   return Status;
     77 }
     78 
     79 /**
     80   Free an instance of XEN_BLOCK_FRONT_DEVICE.
     81 
     82   @param Dev  The instance to free.
     83 **/
     84 STATIC
     85 VOID
     86 XenPvBlockFree (
     87   IN XEN_BLOCK_FRONT_DEVICE *Dev
     88   )
     89 {
     90   XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
     91 
     92   if (Dev->RingRef != 0) {
     93     XenBusIo->GrantEndAccess (XenBusIo, Dev->RingRef);
     94   }
     95   if (Dev->Ring.sring != NULL) {
     96     FreePages (Dev->Ring.sring, 1);
     97   }
     98   if (Dev->EventChannel != 0) {
     99     XenBusIo->EventChannelClose (XenBusIo, Dev->EventChannel);
    100   }
    101   FreePool (Dev);
    102 }
    103 
    104 /**
    105   Wait until until the backend has reached the ExpectedState.
    106 
    107   @param Dev            A XEN_BLOCK_FRONT_DEVICE instance.
    108   @param ExpectedState  The backend state expected.
    109   @param LastStatePtr   An optional pointer where to right the final state.
    110 
    111   @return Return XENSTORE_STATUS_SUCCESS if the new backend state is ExpectedState
    112           or return an error otherwise.
    113 **/
    114 STATIC
    115 XENSTORE_STATUS
    116 XenPvBlkWaitForBackendState (
    117   IN  XEN_BLOCK_FRONT_DEVICE *Dev,
    118   IN  XenbusState            ExpectedState,
    119   OUT XenbusState            *LastStatePtr OPTIONAL
    120   )
    121 {
    122   XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
    123   XenbusState State;
    124   UINT64 Value;
    125   XENSTORE_STATUS Status = XENSTORE_STATUS_SUCCESS;
    126 
    127   while (TRUE) {
    128     Status = XenBusReadUint64 (XenBusIo, "state", TRUE, &Value);
    129     if (Status != XENSTORE_STATUS_SUCCESS) {
    130       return Status;
    131     }
    132     if (Value > XenbusStateReconfigured) {
    133       //
    134       // Value is not a State value.
    135       //
    136       return XENSTORE_STATUS_EIO;
    137     }
    138     State = Value;
    139     if (State == ExpectedState) {
    140       break;
    141     } else if (State > ExpectedState) {
    142       Status = XENSTORE_STATUS_FAIL;
    143       break;
    144     }
    145     DEBUG ((EFI_D_INFO,
    146             "XenPvBlk: waiting backend state %d, current: %d\n",
    147             ExpectedState, State));
    148     XenBusIo->WaitForWatch (XenBusIo, Dev->StateWatchToken);
    149   }
    150 
    151   if (LastStatePtr != NULL) {
    152     *LastStatePtr = State;
    153   }
    154 
    155   return Status;
    156 }
    157 
    158 EFI_STATUS
    159 XenPvBlockFrontInitialization (
    160   IN  XENBUS_PROTOCOL         *XenBusIo,
    161   IN  CONST CHAR8             *NodeName,
    162   OUT XEN_BLOCK_FRONT_DEVICE  **DevPtr
    163   )
    164 {
    165   XENSTORE_TRANSACTION Transaction;
    166   CHAR8 *DeviceType;
    167   blkif_sring_t *SharedRing;
    168   XENSTORE_STATUS Status;
    169   XEN_BLOCK_FRONT_DEVICE *Dev;
    170   XenbusState State;
    171   UINT64 Value;
    172   CHAR8 *Params;
    173 
    174   ASSERT (NodeName != NULL);
    175 
    176   Dev = AllocateZeroPool (sizeof (XEN_BLOCK_FRONT_DEVICE));
    177   Dev->Signature = XEN_BLOCK_FRONT_SIGNATURE;
    178   Dev->NodeName = NodeName;
    179   Dev->XenBusIo = XenBusIo;
    180   Dev->DeviceId = XenBusIo->DeviceId;
    181 
    182   XenBusIo->XsRead (XenBusIo, XST_NIL, "device-type", (VOID**)&DeviceType);
    183   if (AsciiStrCmp (DeviceType, "cdrom") == 0) {
    184     Dev->MediaInfo.CdRom = TRUE;
    185   } else {
    186     Dev->MediaInfo.CdRom = FALSE;
    187   }
    188   FreePool (DeviceType);
    189 
    190   if (Dev->MediaInfo.CdRom) {
    191     Status = XenBusIo->XsBackendRead (XenBusIo, XST_NIL, "params", (VOID**)&Params);
    192     if (Status != XENSTORE_STATUS_SUCCESS) {
    193       DEBUG ((EFI_D_ERROR, "%a: Failed to read params (%d)\n", __FUNCTION__, Status));
    194       goto Error;
    195     }
    196     if (AsciiStrLen (Params) == 0 || AsciiStrCmp (Params, "aio:") == 0) {
    197       FreePool (Params);
    198       DEBUG ((EFI_D_INFO, "%a: Empty cdrom\n", __FUNCTION__));
    199       goto Error;
    200     }
    201     FreePool (Params);
    202   }
    203 
    204   Status = XenBusReadUint64 (XenBusIo, "backend-id", FALSE, &Value);
    205   if (Status != XENSTORE_STATUS_SUCCESS || Value > MAX_UINT16) {
    206     DEBUG ((EFI_D_ERROR, "XenPvBlk: Failed to get backend-id (%d)\n",
    207             Status));
    208     goto Error;
    209   }
    210   Dev->DomainId = (domid_t)Value;
    211   XenBusIo->EventChannelAllocate (XenBusIo, Dev->DomainId, &Dev->EventChannel);
    212 
    213   SharedRing = (blkif_sring_t*) AllocatePages (1);
    214   SHARED_RING_INIT (SharedRing);
    215   FRONT_RING_INIT (&Dev->Ring, SharedRing, EFI_PAGE_SIZE);
    216   XenBusIo->GrantAccess (XenBusIo,
    217                          Dev->DomainId,
    218                          (INTN) SharedRing >> EFI_PAGE_SHIFT,
    219                          FALSE,
    220                          &Dev->RingRef);
    221 
    222 Again:
    223   Status = XenBusIo->XsTransactionStart (XenBusIo, &Transaction);
    224   if (Status != XENSTORE_STATUS_SUCCESS) {
    225     DEBUG ((EFI_D_WARN, "XenPvBlk: Failed to start transaction, %d\n", Status));
    226     goto Error;
    227   }
    228 
    229   Status = XenBusIo->XsPrintf (XenBusIo, &Transaction, NodeName, "ring-ref", "%d",
    230                                Dev->RingRef);
    231   if (Status != XENSTORE_STATUS_SUCCESS) {
    232     DEBUG ((EFI_D_ERROR, "XenPvBlk: Failed to write ring-ref.\n"));
    233     goto AbortTransaction;
    234   }
    235   Status = XenBusIo->XsPrintf (XenBusIo, &Transaction, NodeName,
    236                                "event-channel", "%d", Dev->EventChannel);
    237   if (Status != XENSTORE_STATUS_SUCCESS) {
    238     DEBUG ((EFI_D_ERROR, "XenPvBlk: Failed to write event-channel.\n"));
    239     goto AbortTransaction;
    240   }
    241   Status = XenBusIo->XsPrintf (XenBusIo, &Transaction, NodeName,
    242                                "protocol", "%a", XEN_IO_PROTO_ABI_NATIVE);
    243   if (Status != XENSTORE_STATUS_SUCCESS) {
    244     DEBUG ((EFI_D_ERROR, "XenPvBlk: Failed to write protocol.\n"));
    245     goto AbortTransaction;
    246   }
    247 
    248   Status = XenBusIo->SetState (XenBusIo, &Transaction, XenbusStateConnected);
    249   if (Status != XENSTORE_STATUS_SUCCESS) {
    250     DEBUG ((EFI_D_ERROR, "XenPvBlk: Failed to switch state.\n"));
    251     goto AbortTransaction;
    252   }
    253 
    254   Status = XenBusIo->XsTransactionEnd (XenBusIo, &Transaction, FALSE);
    255   if (Status == XENSTORE_STATUS_EAGAIN) {
    256     goto Again;
    257   }
    258 
    259   XenBusIo->RegisterWatchBackend (XenBusIo, "state", &Dev->StateWatchToken);
    260 
    261   //
    262   // Waiting for backend
    263   //
    264   Status = XenPvBlkWaitForBackendState (Dev, XenbusStateConnected, &State);
    265   if (Status != XENSTORE_STATUS_SUCCESS) {
    266     DEBUG ((EFI_D_ERROR,
    267             "XenPvBlk: backend for %a/%d not available, rc=%d state=%d\n",
    268             XenBusIo->Type, XenBusIo->DeviceId, Status, State));
    269     goto Error2;
    270   }
    271 
    272   Status = XenBusReadUint64 (XenBusIo, "info", TRUE, &Value);
    273   if (Status != XENSTORE_STATUS_SUCCESS || Value > MAX_UINT32) {
    274     goto Error2;
    275   }
    276   Dev->MediaInfo.VDiskInfo = (UINT32)Value;
    277   if (Dev->MediaInfo.VDiskInfo & VDISK_READONLY) {
    278     Dev->MediaInfo.ReadWrite = FALSE;
    279   } else {
    280     Dev->MediaInfo.ReadWrite = TRUE;
    281   }
    282 
    283   Status = XenBusReadUint64 (XenBusIo, "sectors", TRUE, &Dev->MediaInfo.Sectors);
    284   if (Status != XENSTORE_STATUS_SUCCESS) {
    285     goto Error2;
    286   }
    287 
    288   Status = XenBusReadUint64 (XenBusIo, "sector-size", TRUE, &Value);
    289   if (Status != XENSTORE_STATUS_SUCCESS || Value > MAX_UINT32) {
    290     goto Error2;
    291   }
    292   if ((UINT32)Value % 512 != 0) {
    293     //
    294     // This is not supported by the driver.
    295     //
    296     DEBUG ((EFI_D_ERROR, "XenPvBlk: Unsupported sector-size value %Lu, "
    297             "it must be a multiple of 512\n", Value));
    298     goto Error2;
    299   }
    300   Dev->MediaInfo.SectorSize = (UINT32)Value;
    301 
    302   // Default value
    303   Value = 0;
    304   XenBusReadUint64 (XenBusIo, "feature-barrier", TRUE, &Value);
    305   if (Value == 1) {
    306     Dev->MediaInfo.FeatureBarrier = TRUE;
    307   } else {
    308     Dev->MediaInfo.FeatureBarrier = FALSE;
    309   }
    310 
    311   // Default value
    312   Value = 0;
    313   XenBusReadUint64 (XenBusIo, "feature-flush-cache", TRUE, &Value);
    314   if (Value == 1) {
    315     Dev->MediaInfo.FeatureFlushCache = TRUE;
    316   } else {
    317     Dev->MediaInfo.FeatureFlushCache = FALSE;
    318   }
    319 
    320   DEBUG ((EFI_D_INFO, "XenPvBlk: New disk with %ld sectors of %d bytes\n",
    321           Dev->MediaInfo.Sectors, Dev->MediaInfo.SectorSize));
    322 
    323   *DevPtr = Dev;
    324   return EFI_SUCCESS;
    325 
    326 Error2:
    327   XenBusIo->UnregisterWatch (XenBusIo, Dev->StateWatchToken);
    328   XenBusIo->XsRemove (XenBusIo, XST_NIL, "ring-ref");
    329   XenBusIo->XsRemove (XenBusIo, XST_NIL, "event-channel");
    330   XenBusIo->XsRemove (XenBusIo, XST_NIL, "protocol");
    331   goto Error;
    332 AbortTransaction:
    333   XenBusIo->XsTransactionEnd (XenBusIo, &Transaction, TRUE);
    334 Error:
    335   XenPvBlockFree (Dev);
    336   return EFI_DEVICE_ERROR;
    337 }
    338 
    339 VOID
    340 XenPvBlockFrontShutdown (
    341   IN XEN_BLOCK_FRONT_DEVICE *Dev
    342   )
    343 {
    344   XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
    345   XENSTORE_STATUS Status;
    346   UINT64 Value;
    347 
    348   XenPvBlockSync (Dev);
    349 
    350   Status = XenBusIo->SetState (XenBusIo, XST_NIL, XenbusStateClosing);
    351   if (Status != XENSTORE_STATUS_SUCCESS) {
    352     DEBUG ((EFI_D_ERROR,
    353             "XenPvBlk: error while changing state to Closing: %d\n",
    354             Status));
    355     goto Close;
    356   }
    357 
    358   Status = XenPvBlkWaitForBackendState (Dev, XenbusStateClosing, NULL);
    359   if (Status != XENSTORE_STATUS_SUCCESS) {
    360     DEBUG ((EFI_D_ERROR,
    361             "XenPvBlk: error while waiting for closing backend state: %d\n",
    362             Status));
    363     goto Close;
    364   }
    365 
    366   Status = XenBusIo->SetState (XenBusIo, XST_NIL, XenbusStateClosed);
    367   if (Status != XENSTORE_STATUS_SUCCESS) {
    368     DEBUG ((EFI_D_ERROR,
    369             "XenPvBlk: error while changing state to Closed: %d\n",
    370             Status));
    371     goto Close;
    372   }
    373 
    374   Status = XenPvBlkWaitForBackendState (Dev, XenbusStateClosed, NULL);
    375   if (Status != XENSTORE_STATUS_SUCCESS) {
    376     DEBUG ((EFI_D_ERROR,
    377             "XenPvBlk: error while waiting for closed backend state: %d\n",
    378             Status));
    379     goto Close;
    380   }
    381 
    382   Status = XenBusIo->SetState (XenBusIo, XST_NIL, XenbusStateInitialising);
    383   if (Status != XENSTORE_STATUS_SUCCESS) {
    384     DEBUG ((EFI_D_ERROR,
    385             "XenPvBlk: error while changing state to initialising: %d\n",
    386             Status));
    387     goto Close;
    388   }
    389 
    390   while (TRUE) {
    391     Status = XenBusReadUint64 (XenBusIo, "state", TRUE, &Value);
    392     if (Status != XENSTORE_STATUS_SUCCESS) {
    393       DEBUG ((EFI_D_ERROR,
    394               "XenPvBlk: error while waiting for new backend state: %d\n",
    395               Status));
    396       goto Close;
    397     }
    398     if (Value <= XenbusStateInitWait || Value >= XenbusStateClosed) {
    399       break;
    400     }
    401     DEBUG ((EFI_D_INFO,
    402             "XenPvBlk: waiting backend state %d, current: %Lu\n",
    403             XenbusStateInitWait, Value));
    404     XenBusIo->WaitForWatch (XenBusIo, Dev->StateWatchToken);
    405   }
    406 
    407 Close:
    408   XenBusIo->UnregisterWatch (XenBusIo, Dev->StateWatchToken);
    409   XenBusIo->XsRemove (XenBusIo, XST_NIL, "ring-ref");
    410   XenBusIo->XsRemove (XenBusIo, XST_NIL, "event-channel");
    411   XenBusIo->XsRemove (XenBusIo, XST_NIL, "protocol");
    412 
    413   XenPvBlockFree (Dev);
    414 }
    415 
    416 STATIC
    417 VOID
    418 XenPvBlockWaitSlot (
    419   IN XEN_BLOCK_FRONT_DEVICE *Dev
    420   )
    421 {
    422   /* Wait for a slot */
    423   if (RING_FULL (&Dev->Ring)) {
    424     while (TRUE) {
    425       XenPvBlockAsyncIoPoll (Dev);
    426       if (!RING_FULL (&Dev->Ring)) {
    427         break;
    428       }
    429       /* Really no slot, could wait for an event on Dev->EventChannel. */
    430     }
    431   }
    432 }
    433 
    434 VOID
    435 XenPvBlockAsyncIo (
    436   IN OUT XEN_BLOCK_FRONT_IO *IoData,
    437   IN     BOOLEAN            IsWrite
    438   )
    439 {
    440   XEN_BLOCK_FRONT_DEVICE *Dev = IoData->Dev;
    441   XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
    442   blkif_request_t *Request;
    443   RING_IDX RingIndex;
    444   BOOLEAN Notify;
    445   INT32 NumSegments, Index;
    446   UINTN Start, End;
    447 
    448   // Can't io at non-sector-aligned location
    449   ASSERT(!(IoData->Sector & ((Dev->MediaInfo.SectorSize / 512) - 1)));
    450   // Can't io non-sector-sized amounts
    451   ASSERT(!(IoData->Size & (Dev->MediaInfo.SectorSize - 1)));
    452   // Can't io non-sector-aligned buffer
    453   ASSERT(!((UINTN) IoData->Buffer & (Dev->MediaInfo.SectorSize - 1)));
    454 
    455   Start = (UINTN) IoData->Buffer & ~EFI_PAGE_MASK;
    456   End = ((UINTN) IoData->Buffer + IoData->Size + EFI_PAGE_SIZE - 1) & ~EFI_PAGE_MASK;
    457   IoData->NumRef = NumSegments = (INT32)((End - Start) / EFI_PAGE_SIZE);
    458 
    459   ASSERT (NumSegments <= BLKIF_MAX_SEGMENTS_PER_REQUEST);
    460 
    461   XenPvBlockWaitSlot (Dev);
    462   RingIndex = Dev->Ring.req_prod_pvt;
    463   Request = RING_GET_REQUEST (&Dev->Ring, RingIndex);
    464 
    465   Request->operation = IsWrite ? BLKIF_OP_WRITE : BLKIF_OP_READ;
    466   Request->nr_segments = (UINT8)NumSegments;
    467   Request->handle = Dev->DeviceId;
    468   Request->id = (UINTN) IoData;
    469   Request->sector_number = IoData->Sector;
    470 
    471   for (Index = 0; Index < NumSegments; Index++) {
    472     Request->seg[Index].first_sect = 0;
    473     Request->seg[Index].last_sect = EFI_PAGE_SIZE / 512 - 1;
    474   }
    475   Request->seg[0].first_sect = (UINT8)(((UINTN) IoData->Buffer & EFI_PAGE_MASK) / 512);
    476   Request->seg[NumSegments - 1].last_sect =
    477       (UINT8)((((UINTN) IoData->Buffer + IoData->Size - 1) & EFI_PAGE_MASK) / 512);
    478   for (Index = 0; Index < NumSegments; Index++) {
    479     UINTN Data = Start + Index * EFI_PAGE_SIZE;
    480     XenBusIo->GrantAccess (XenBusIo, Dev->DomainId,
    481                            Data >> EFI_PAGE_SHIFT, IsWrite,
    482                            &Request->seg[Index].gref);
    483     IoData->GrantRef[Index] = Request->seg[Index].gref;
    484   }
    485 
    486   Dev->Ring.req_prod_pvt = RingIndex + 1;
    487 
    488   MemoryFence ();
    489   RING_PUSH_REQUESTS_AND_CHECK_NOTIFY (&Dev->Ring, Notify);
    490 
    491   if (Notify) {
    492     UINT32 ReturnCode;
    493     ReturnCode = XenBusIo->EventChannelNotify (XenBusIo, Dev->EventChannel);
    494     if (ReturnCode != 0) {
    495       DEBUG ((EFI_D_ERROR,
    496               "XenPvBlk: Unexpected return value from EventChannelNotify: %d\n",
    497               ReturnCode));
    498     }
    499   }
    500 }
    501 
    502 EFI_STATUS
    503 XenPvBlockIo (
    504   IN OUT XEN_BLOCK_FRONT_IO *IoData,
    505   IN     BOOLEAN            IsWrite
    506   )
    507 {
    508   //
    509   // Status value that correspond to an IO in progress.
    510   //
    511   IoData->Status = EFI_ALREADY_STARTED;
    512   XenPvBlockAsyncIo (IoData, IsWrite);
    513 
    514   while (IoData->Status == EFI_ALREADY_STARTED) {
    515     XenPvBlockAsyncIoPoll (IoData->Dev);
    516   }
    517 
    518   return IoData->Status;
    519 }
    520 
    521 STATIC
    522 VOID
    523 XenPvBlockPushOperation (
    524   IN XEN_BLOCK_FRONT_DEVICE *Dev,
    525   IN UINT8                  Operation,
    526   IN UINT64                 Id
    527   )
    528 {
    529   INT32 Index;
    530   blkif_request_t *Request;
    531   BOOLEAN Notify;
    532 
    533   XenPvBlockWaitSlot (Dev);
    534   Index = Dev->Ring.req_prod_pvt;
    535   Request = RING_GET_REQUEST(&Dev->Ring, Index);
    536   Request->operation = Operation;
    537   Request->nr_segments = 0;
    538   Request->handle = Dev->DeviceId;
    539   Request->id = Id;
    540   /* Not needed anyway, but the backend will check it */
    541   Request->sector_number = 0;
    542   Dev->Ring.req_prod_pvt = Index + 1;
    543   MemoryFence ();
    544   RING_PUSH_REQUESTS_AND_CHECK_NOTIFY (&Dev->Ring, Notify);
    545   if (Notify) {
    546     XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
    547     UINT32 ReturnCode;
    548     ReturnCode = XenBusIo->EventChannelNotify (XenBusIo, Dev->EventChannel);
    549     if (ReturnCode != 0) {
    550       DEBUG ((EFI_D_ERROR,
    551               "XenPvBlk: Unexpected return value from EventChannelNotify: %d\n",
    552               ReturnCode));
    553     }
    554   }
    555 }
    556 
    557 VOID
    558 XenPvBlockSync (
    559   IN XEN_BLOCK_FRONT_DEVICE *Dev
    560   )
    561 {
    562   if (Dev->MediaInfo.ReadWrite) {
    563     if (Dev->MediaInfo.FeatureBarrier) {
    564       XenPvBlockPushOperation (Dev, BLKIF_OP_WRITE_BARRIER, 0);
    565     }
    566 
    567     if (Dev->MediaInfo.FeatureFlushCache) {
    568       XenPvBlockPushOperation (Dev, BLKIF_OP_FLUSH_DISKCACHE, 0);
    569     }
    570   }
    571 
    572   /* Note: This won't finish if another thread enqueues requests.  */
    573   while (TRUE) {
    574     XenPvBlockAsyncIoPoll (Dev);
    575     if (RING_FREE_REQUESTS (&Dev->Ring) == RING_SIZE (&Dev->Ring)) {
    576       break;
    577     }
    578   }
    579 }
    580 
    581 VOID
    582 XenPvBlockAsyncIoPoll (
    583   IN XEN_BLOCK_FRONT_DEVICE *Dev
    584   )
    585 {
    586   RING_IDX ProducerIndex, ConsumerIndex;
    587   blkif_response_t *Response;
    588   INT32 More;
    589 
    590   do {
    591     ProducerIndex = Dev->Ring.sring->rsp_prod;
    592     /* Ensure we see queued responses up to 'ProducerIndex'. */
    593     MemoryFence ();
    594     ConsumerIndex = Dev->Ring.rsp_cons;
    595 
    596     while (ConsumerIndex != ProducerIndex) {
    597       XEN_BLOCK_FRONT_IO *IoData = NULL;
    598       INT16 Status;
    599 
    600       Response = RING_GET_RESPONSE (&Dev->Ring, ConsumerIndex);
    601 
    602       IoData = (VOID *) (UINTN) Response->id;
    603       Status = Response->status;
    604 
    605       switch (Response->operation) {
    606       case BLKIF_OP_READ:
    607       case BLKIF_OP_WRITE:
    608         {
    609           INT32 Index;
    610 
    611           if (Status != BLKIF_RSP_OKAY) {
    612             DEBUG ((EFI_D_ERROR,
    613                     "XenPvBlk: "
    614                     "%a error %d on %a at sector %Lx, num bytes %Lx\n",
    615                     Response->operation == BLKIF_OP_READ ? "read" : "write",
    616                     Status, IoData->Dev->NodeName,
    617                     (UINT64)IoData->Sector,
    618                     (UINT64)IoData->Size));
    619           }
    620 
    621           for (Index = 0; Index < IoData->NumRef; Index++) {
    622             Dev->XenBusIo->GrantEndAccess (Dev->XenBusIo, IoData->GrantRef[Index]);
    623           }
    624 
    625           break;
    626         }
    627 
    628       case BLKIF_OP_WRITE_BARRIER:
    629         if (Status != BLKIF_RSP_OKAY) {
    630           DEBUG ((EFI_D_ERROR, "XenPvBlk: write barrier error %d\n", Status));
    631         }
    632         break;
    633       case BLKIF_OP_FLUSH_DISKCACHE:
    634         if (Status != BLKIF_RSP_OKAY) {
    635           DEBUG ((EFI_D_ERROR, "XenPvBlk: flush error %d\n", Status));
    636         }
    637         break;
    638 
    639       default:
    640         DEBUG ((EFI_D_ERROR,
    641                 "XenPvBlk: unrecognized block operation %d response (status %d)\n",
    642                 Response->operation, Status));
    643         break;
    644       }
    645 
    646       Dev->Ring.rsp_cons = ++ConsumerIndex;
    647       if (IoData != NULL) {
    648         IoData->Status = Status ? EFI_DEVICE_ERROR : EFI_SUCCESS;
    649       }
    650       if (Dev->Ring.rsp_cons != ConsumerIndex) {
    651         /* We reentered, we must not continue here */
    652         break;
    653       }
    654     }
    655 
    656     RING_FINAL_CHECK_FOR_RESPONSES (&Dev->Ring, More);
    657   } while (More != 0);
    658 }
    659