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
XenBusReadUint64(IN XENBUS_PROTOCOL * This,IN CONST CHAR8 * Node,IN BOOLEAN FromBackend,OUT UINT64 * ValuePtr)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
XenPvBlockFree(IN XEN_BLOCK_FRONT_DEVICE * Dev)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
XenPvBlkWaitForBackendState(IN XEN_BLOCK_FRONT_DEVICE * Dev,IN XenbusState ExpectedState,OUT XenbusState * LastStatePtr OPTIONAL)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
XenPvBlockFrontInitialization(IN XENBUS_PROTOCOL * XenBusIo,IN CONST CHAR8 * NodeName,OUT XEN_BLOCK_FRONT_DEVICE ** DevPtr)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
XenPvBlockFrontShutdown(IN XEN_BLOCK_FRONT_DEVICE * Dev)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
XenPvBlockWaitSlot(IN XEN_BLOCK_FRONT_DEVICE * Dev)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
XenPvBlockAsyncIo(IN OUT XEN_BLOCK_FRONT_IO * IoData,IN BOOLEAN IsWrite)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
XenPvBlockIo(IN OUT XEN_BLOCK_FRONT_IO * IoData,IN BOOLEAN IsWrite)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
XenPvBlockPushOperation(IN XEN_BLOCK_FRONT_DEVICE * Dev,IN UINT8 Operation,IN UINT64 Id)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
XenPvBlockSync(IN XEN_BLOCK_FRONT_DEVICE * Dev)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
XenPvBlockAsyncIoPoll(IN XEN_BLOCK_FRONT_DEVICE * Dev)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