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