BlockFront.c 20 KB

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