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