blob: afaa95983b5d48837bea6ab1dd060833c2edcd49 [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/** @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**/
53STATIC
54XENSTORE_STATUS
55XenBusReadUint64 (
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**/
84STATIC
85VOID
86XenPvBlockFree (
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**/
114STATIC
115XENSTORE_STATUS
116XenPvBlkWaitForBackendState (
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
158EFI_STATUS
159XenPvBlockFrontInitialization (
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
173 ASSERT (NodeName != NULL);
174
175 Dev = AllocateZeroPool (sizeof (XEN_BLOCK_FRONT_DEVICE));
176 Dev->Signature = XEN_BLOCK_FRONT_SIGNATURE;
177 Dev->NodeName = NodeName;
178 Dev->XenBusIo = XenBusIo;
179 Dev->DeviceId = XenBusIo->DeviceId;
180
181 XenBusIo->XsRead (XenBusIo, XST_NIL, "device-type", (VOID**)&DeviceType);
182 if (AsciiStrCmp (DeviceType, "cdrom") == 0) {
183 Dev->MediaInfo.CdRom = TRUE;
184 } else {
185 Dev->MediaInfo.CdRom = FALSE;
186 }
187 FreePool (DeviceType);
188
189 Status = XenBusReadUint64 (XenBusIo, "backend-id", FALSE, &Value);
190 if (Status != XENSTORE_STATUS_SUCCESS || Value > MAX_UINT16) {
191 DEBUG ((EFI_D_ERROR, "XenPvBlk: Failed to get backend-id (%d)\n",
192 Status));
193 goto Error;
194 }
195 Dev->DomainId = (domid_t)Value;
196 XenBusIo->EventChannelAllocate (XenBusIo, Dev->DomainId, &Dev->EventChannel);
197
198 SharedRing = (blkif_sring_t*) AllocatePages (1);
199 SHARED_RING_INIT (SharedRing);
200 FRONT_RING_INIT (&Dev->Ring, SharedRing, EFI_PAGE_SIZE);
201 XenBusIo->GrantAccess (XenBusIo,
202 Dev->DomainId,
203 (INTN) SharedRing >> EFI_PAGE_SHIFT,
204 FALSE,
205 &Dev->RingRef);
206
207Again:
208 Status = XenBusIo->XsTransactionStart (XenBusIo, &Transaction);
209 if (Status != XENSTORE_STATUS_SUCCESS) {
210 DEBUG ((EFI_D_WARN, "XenPvBlk: Failed to start transaction, %d\n", Status));
211 goto Error;
212 }
213
214 Status = XenBusIo->XsPrintf (XenBusIo, &Transaction, NodeName, "ring-ref", "%d",
215 Dev->RingRef);
216 if (Status != XENSTORE_STATUS_SUCCESS) {
217 DEBUG ((EFI_D_ERROR, "XenPvBlk: Failed to write ring-ref.\n"));
218 goto AbortTransaction;
219 }
220 Status = XenBusIo->XsPrintf (XenBusIo, &Transaction, NodeName,
221 "event-channel", "%d", Dev->EventChannel);
222 if (Status != XENSTORE_STATUS_SUCCESS) {
223 DEBUG ((EFI_D_ERROR, "XenPvBlk: Failed to write event-channel.\n"));
224 goto AbortTransaction;
225 }
226 Status = XenBusIo->XsPrintf (XenBusIo, &Transaction, NodeName,
227 "protocol", "%a", XEN_IO_PROTO_ABI_NATIVE);
228 if (Status != XENSTORE_STATUS_SUCCESS) {
229 DEBUG ((EFI_D_ERROR, "XenPvBlk: Failed to write protocol.\n"));
230 goto AbortTransaction;
231 }
232
233 Status = XenBusIo->SetState (XenBusIo, &Transaction, XenbusStateConnected);
234 if (Status != XENSTORE_STATUS_SUCCESS) {
235 DEBUG ((EFI_D_ERROR, "XenPvBlk: Failed to switch state.\n"));
236 goto AbortTransaction;
237 }
238
239 Status = XenBusIo->XsTransactionEnd (XenBusIo, &Transaction, FALSE);
240 if (Status == XENSTORE_STATUS_EAGAIN) {
241 goto Again;
242 }
243
244 XenBusIo->RegisterWatchBackend (XenBusIo, "state", &Dev->StateWatchToken);
245
246 //
247 // Waiting for backend
248 //
249 Status = XenPvBlkWaitForBackendState (Dev, XenbusStateConnected, &State);
250 if (Status != XENSTORE_STATUS_SUCCESS) {
251 DEBUG ((EFI_D_ERROR,
252 "XenPvBlk: backend for %a/%d not available, rc=%d state=%d\n",
253 XenBusIo->Type, XenBusIo->DeviceId, Status, State));
254 goto Error2;
255 }
256
257 Status = XenBusReadUint64 (XenBusIo, "info", TRUE, &Value);
258 if (Status != XENSTORE_STATUS_SUCCESS || Value > MAX_UINT32) {
259 goto Error2;
260 }
261 Dev->MediaInfo.VDiskInfo = (UINT32)Value;
262 if (Dev->MediaInfo.VDiskInfo & VDISK_READONLY) {
263 Dev->MediaInfo.ReadWrite = FALSE;
264 } else {
265 Dev->MediaInfo.ReadWrite = TRUE;
266 }
267
268 Status = XenBusReadUint64 (XenBusIo, "sectors", TRUE, &Dev->MediaInfo.Sectors);
269 if (Status != XENSTORE_STATUS_SUCCESS) {
270 goto Error2;
271 }
272
273 Status = XenBusReadUint64 (XenBusIo, "sector-size", TRUE, &Value);
274 if (Status != XENSTORE_STATUS_SUCCESS || Value > MAX_UINT32) {
275 goto Error2;
276 }
277 if ((UINT32)Value % 512 != 0) {
278 //
279 // This is not supported by the driver.
280 //
281 DEBUG ((EFI_D_ERROR, "XenPvBlk: Unsupported sector-size value %d, "
282 "it must be a multiple of 512\n", Value));
283 goto Error2;
284 }
285 Dev->MediaInfo.SectorSize = (UINT32)Value;
286
287 // Default value
288 Value = 0;
289 XenBusReadUint64 (XenBusIo, "feature-barrier", TRUE, &Value);
290 if (Value == 1) {
291 Dev->MediaInfo.FeatureBarrier = TRUE;
292 } else {
293 Dev->MediaInfo.FeatureBarrier = FALSE;
294 }
295
296 // Default value
297 Value = 0;
298 XenBusReadUint64 (XenBusIo, "feature-flush-cache", TRUE, &Value);
299 if (Value == 1) {
300 Dev->MediaInfo.FeatureFlushCache = TRUE;
301 } else {
302 Dev->MediaInfo.FeatureFlushCache = FALSE;
303 }
304
305 DEBUG ((EFI_D_INFO, "XenPvBlk: New disk with %ld sectors of %d bytes\n",
306 Dev->MediaInfo.Sectors, Dev->MediaInfo.SectorSize));
307
308 *DevPtr = Dev;
309 return EFI_SUCCESS;
310
311Error2:
312 XenBusIo->UnregisterWatch (XenBusIo, Dev->StateWatchToken);
313 XenBusIo->XsRemove (XenBusIo, XST_NIL, "ring-ref");
314 XenBusIo->XsRemove (XenBusIo, XST_NIL, "event-channel");
315 XenBusIo->XsRemove (XenBusIo, XST_NIL, "protocol");
316 goto Error;
317AbortTransaction:
318 XenBusIo->XsTransactionEnd (XenBusIo, &Transaction, TRUE);
319Error:
320 XenPvBlockFree (Dev);
321 return EFI_DEVICE_ERROR;
322}
323
324VOID
325XenPvBlockFrontShutdown (
326 IN XEN_BLOCK_FRONT_DEVICE *Dev
327 )
328{
329 XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
330 XENSTORE_STATUS Status;
331 UINT64 Value;
332
333 XenPvBlockSync (Dev);
334
335 Status = XenBusIo->SetState (XenBusIo, XST_NIL, XenbusStateClosing);
336 if (Status != XENSTORE_STATUS_SUCCESS) {
337 DEBUG ((EFI_D_ERROR,
338 "XenPvBlk: error while changing state to Closing: %d\n",
339 Status));
340 goto Close;
341 }
342
343 Status = XenPvBlkWaitForBackendState (Dev, XenbusStateClosing, NULL);
344 if (Status != XENSTORE_STATUS_SUCCESS) {
345 DEBUG ((EFI_D_ERROR,
346 "XenPvBlk: error while waiting for closing backend state: %d\n",
347 Status));
348 goto Close;
349 }
350
351 Status = XenBusIo->SetState (XenBusIo, XST_NIL, XenbusStateClosed);
352 if (Status != XENSTORE_STATUS_SUCCESS) {
353 DEBUG ((EFI_D_ERROR,
354 "XenPvBlk: error while changing state to Closed: %d\n",
355 Status));
356 goto Close;
357 }
358
359 Status = XenPvBlkWaitForBackendState (Dev, XenbusStateClosed, NULL);
360 if (Status != XENSTORE_STATUS_SUCCESS) {
361 DEBUG ((EFI_D_ERROR,
362 "XenPvBlk: error while waiting for closed backend state: %d\n",
363 Status));
364 goto Close;
365 }
366
367 Status = XenBusIo->SetState (XenBusIo, XST_NIL, XenbusStateInitialising);
368 if (Status != XENSTORE_STATUS_SUCCESS) {
369 DEBUG ((EFI_D_ERROR,
370 "XenPvBlk: error while changing state to initialising: %d\n",
371 Status));
372 goto Close;
373 }
374
375 while (TRUE) {
376 Status = XenBusReadUint64 (XenBusIo, "state", TRUE, &Value);
377 if (Status != XENSTORE_STATUS_SUCCESS) {
378 DEBUG ((EFI_D_ERROR,
379 "XenPvBlk: error while waiting for new backend state: %d\n",
380 Status));
381 goto Close;
382 }
383 if (Value <= XenbusStateInitWait || Value >= XenbusStateClosed) {
384 break;
385 }
386 DEBUG ((EFI_D_INFO,
387 "XenPvBlk: waiting backend state %d, current: %d\n",
388 XenbusStateInitWait, Value));
389 XenBusIo->WaitForWatch (XenBusIo, Dev->StateWatchToken);
390 }
391
392Close:
393 XenBusIo->UnregisterWatch (XenBusIo, Dev->StateWatchToken);
394 XenBusIo->XsRemove (XenBusIo, XST_NIL, "ring-ref");
395 XenBusIo->XsRemove (XenBusIo, XST_NIL, "event-channel");
396 XenBusIo->XsRemove (XenBusIo, XST_NIL, "protocol");
397
398 XenPvBlockFree (Dev);
399}
400
401STATIC
402VOID
403XenPvBlockWaitSlot (
404 IN XEN_BLOCK_FRONT_DEVICE *Dev
405 )
406{
407 /* Wait for a slot */
408 if (RING_FULL (&Dev->Ring)) {
409 while (TRUE) {
410 XenPvBlockAsyncIoPoll (Dev);
411 if (!RING_FULL (&Dev->Ring)) {
412 break;
413 }
414 /* Really no slot, could wait for an event on Dev->EventChannel. */
415 }
416 }
417}
418
419VOID
420XenPvBlockAsyncIo (
421 IN OUT XEN_BLOCK_FRONT_IO *IoData,
422 IN BOOLEAN IsWrite
423 )
424{
425 XEN_BLOCK_FRONT_DEVICE *Dev = IoData->Dev;
426 XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
427 blkif_request_t *Request;
428 RING_IDX RingIndex;
429 BOOLEAN Notify;
430 INT32 NumSegments, Index;
431 UINTN Start, End;
432
433 // Can't io at non-sector-aligned location
434 ASSERT(!(IoData->Sector & ((Dev->MediaInfo.SectorSize / 512) - 1)));
435 // Can't io non-sector-sized amounts
436 ASSERT(!(IoData->Size & (Dev->MediaInfo.SectorSize - 1)));
437 // Can't io non-sector-aligned buffer
438 ASSERT(!((UINTN) IoData->Buffer & (Dev->MediaInfo.SectorSize - 1)));
439
440 Start = (UINTN) IoData->Buffer & ~EFI_PAGE_MASK;
441 End = ((UINTN) IoData->Buffer + IoData->Size + EFI_PAGE_SIZE - 1) & ~EFI_PAGE_MASK;
442 IoData->NumRef = NumSegments = (INT32)((End - Start) / EFI_PAGE_SIZE);
443
444 ASSERT (NumSegments <= BLKIF_MAX_SEGMENTS_PER_REQUEST);
445
446 XenPvBlockWaitSlot (Dev);
447 RingIndex = Dev->Ring.req_prod_pvt;
448 Request = RING_GET_REQUEST (&Dev->Ring, RingIndex);
449
450 Request->operation = IsWrite ? BLKIF_OP_WRITE : BLKIF_OP_READ;
451 Request->nr_segments = (UINT8)NumSegments;
452 Request->handle = Dev->DeviceId;
453 Request->id = (UINTN) IoData;
454 Request->sector_number = IoData->Sector;
455
456 for (Index = 0; Index < NumSegments; Index++) {
457 Request->seg[Index].first_sect = 0;
458 Request->seg[Index].last_sect = EFI_PAGE_SIZE / 512 - 1;
459 }
460 Request->seg[0].first_sect = (UINT8)(((UINTN) IoData->Buffer & EFI_PAGE_MASK) / 512);
461 Request->seg[NumSegments - 1].last_sect =
462 (UINT8)((((UINTN) IoData->Buffer + IoData->Size - 1) & EFI_PAGE_MASK) / 512);
463 for (Index = 0; Index < NumSegments; Index++) {
464 UINTN Data = Start + Index * EFI_PAGE_SIZE;
465 XenBusIo->GrantAccess (XenBusIo, Dev->DomainId,
466 Data >> EFI_PAGE_SHIFT, IsWrite,
467 &Request->seg[Index].gref);
468 IoData->GrantRef[Index] = Request->seg[Index].gref;
469 }
470
471 Dev->Ring.req_prod_pvt = RingIndex + 1;
472
473 MemoryFence ();
474 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY (&Dev->Ring, Notify);
475
476 if (Notify) {
477 UINT32 ReturnCode;
478 ReturnCode = XenBusIo->EventChannelNotify (XenBusIo, Dev->EventChannel);
479 if (ReturnCode != 0) {
480 DEBUG ((EFI_D_ERROR,
481 "XenPvBlk: Unexpected return value from EventChannelNotify: %d\n",
482 ReturnCode));
483 }
484 }
485}
486
487EFI_STATUS
488XenPvBlockIo (
489 IN OUT XEN_BLOCK_FRONT_IO *IoData,
490 IN BOOLEAN IsWrite
491 )
492{
493 //
494 // Status value that correspond to an IO in progress.
495 //
496 IoData->Status = EFI_ALREADY_STARTED;
497 XenPvBlockAsyncIo (IoData, IsWrite);
498
499 while (IoData->Status == EFI_ALREADY_STARTED) {
500 XenPvBlockAsyncIoPoll (IoData->Dev);
501 }
502
503 return IoData->Status;
504}
505
506STATIC
507VOID
508XenPvBlockPushOperation (
509 IN XEN_BLOCK_FRONT_DEVICE *Dev,
510 IN UINT8 Operation,
511 IN UINT64 Id
512 )
513{
514 INT32 Index;
515 blkif_request_t *Request;
516 BOOLEAN Notify;
517
518 XenPvBlockWaitSlot (Dev);
519 Index = Dev->Ring.req_prod_pvt;
520 Request = RING_GET_REQUEST(&Dev->Ring, Index);
521 Request->operation = Operation;
522 Request->nr_segments = 0;
523 Request->handle = Dev->DeviceId;
524 Request->id = Id;
525 /* Not needed anyway, but the backend will check it */
526 Request->sector_number = 0;
527 Dev->Ring.req_prod_pvt = Index + 1;
528 MemoryFence ();
529 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY (&Dev->Ring, Notify);
530 if (Notify) {
531 XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
532 UINT32 ReturnCode;
533 ReturnCode = XenBusIo->EventChannelNotify (XenBusIo, Dev->EventChannel);
534 if (ReturnCode != 0) {
535 DEBUG ((EFI_D_ERROR,
536 "XenPvBlk: Unexpected return value from EventChannelNotify: %d\n",
537 ReturnCode));
538 }
539 }
540}
541
542VOID
543XenPvBlockSync (
544 IN XEN_BLOCK_FRONT_DEVICE *Dev
545 )
546{
547 if (Dev->MediaInfo.ReadWrite) {
548 if (Dev->MediaInfo.FeatureBarrier) {
549 XenPvBlockPushOperation (Dev, BLKIF_OP_WRITE_BARRIER, 0);
550 }
551
552 if (Dev->MediaInfo.FeatureFlushCache) {
553 XenPvBlockPushOperation (Dev, BLKIF_OP_FLUSH_DISKCACHE, 0);
554 }
555 }
556
557 /* Note: This won't finish if another thread enqueues requests. */
558 while (TRUE) {
559 XenPvBlockAsyncIoPoll (Dev);
560 if (RING_FREE_REQUESTS (&Dev->Ring) == RING_SIZE (&Dev->Ring)) {
561 break;
562 }
563 }
564}
565
566VOID
567XenPvBlockAsyncIoPoll (
568 IN XEN_BLOCK_FRONT_DEVICE *Dev
569 )
570{
571 RING_IDX ProducerIndex, ConsumerIndex;
572 blkif_response_t *Response;
573 INT32 More;
574
575 do {
576 ProducerIndex = Dev->Ring.sring->rsp_prod;
577 /* Ensure we see queued responses up to 'ProducerIndex'. */
578 MemoryFence ();
579 ConsumerIndex = Dev->Ring.rsp_cons;
580
581 while (ConsumerIndex != ProducerIndex) {
582 XEN_BLOCK_FRONT_IO *IoData = NULL;
583 INT16 Status;
584
585 Response = RING_GET_RESPONSE (&Dev->Ring, ConsumerIndex);
586
587 IoData = (VOID *) (UINTN) Response->id;
588 Status = Response->status;
589
590 switch (Response->operation) {
591 case BLKIF_OP_READ:
592 case BLKIF_OP_WRITE:
593 {
594 INT32 Index;
595
596 if (Status != BLKIF_RSP_OKAY) {
597 DEBUG ((EFI_D_ERROR,
598 "XenPvBlk: "
599 "%a error %d on %a at sector %p, num bytes %p\n",
600 Response->operation == BLKIF_OP_READ ? "read" : "write",
601 Status, IoData->Dev->NodeName,
602 IoData->Sector,
603 IoData->Size));
604 }
605
606 for (Index = 0; Index < IoData->NumRef; Index++) {
607 Dev->XenBusIo->GrantEndAccess (Dev->XenBusIo, IoData->GrantRef[Index]);
608 }
609
610 break;
611 }
612
613 case BLKIF_OP_WRITE_BARRIER:
614 if (Status != BLKIF_RSP_OKAY) {
615 DEBUG ((EFI_D_ERROR, "XenPvBlk: write barrier error %d\n", Status));
616 }
617 break;
618 case BLKIF_OP_FLUSH_DISKCACHE:
619 if (Status != BLKIF_RSP_OKAY) {
620 DEBUG ((EFI_D_ERROR, "XenPvBlk: flush error %d\n", Status));
621 }
622 break;
623
624 default:
625 DEBUG ((EFI_D_ERROR,
626 "XenPvBlk: unrecognized block operation %d response (status %d)\n",
627 Response->operation, Status));
628 break;
629 }
630
631 Dev->Ring.rsp_cons = ++ConsumerIndex;
632 if (IoData != NULL) {
633 IoData->Status = Status ? EFI_DEVICE_ERROR : EFI_SUCCESS;
634 }
635 if (Dev->Ring.rsp_cons != ConsumerIndex) {
636 /* We reentered, we must not continue here */
637 break;
638 }
639 }
640
641 RING_FINAL_CHECK_FOR_RESPONSES (&Dev->Ring, More);
642 } while (More != 0);
643}