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