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