]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/XenPvBlkDxe/BlockFront.c
d07e980990562ed56c39b901abdeee2594373433
[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 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 }