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 } 659