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