\r
@retval EFI_DEVICE_ERROR Failed to notify host side via VirtIo write, or\r
unable to parse host response, or host response\r
- is not VIRTIO_BLK_S_OK.\r
+ is not VIRTIO_BLK_S_OK or failed to map Buffer\r
+ for a bus master operation.\r
\r
**/\r
\r
{\r
UINT32 BlockSize;\r
volatile VIRTIO_BLK_REQ Request;\r
- volatile UINT8 HostStatus;\r
+ volatile UINT8 *HostStatus;\r
+ VOID *HostStatusBuffer;\r
DESC_INDICES Indices;\r
+ VOID *RequestMapping;\r
+ VOID *StatusMapping;\r
+ VOID *BufferMapping;\r
+ EFI_PHYSICAL_ADDRESS BufferDeviceAddress;\r
+ EFI_PHYSICAL_ADDRESS HostStatusDeviceAddress;\r
+ EFI_PHYSICAL_ADDRESS RequestDeviceAddress;\r
+ EFI_STATUS Status;\r
\r
BlockSize = Dev->BlockIoMedia.BlockSize;\r
\r
Request.IoPrio = 0;\r
Request.Sector = MultU64x32(Lba, BlockSize / 512);\r
\r
- VirtioPrepare (&Dev->Ring, &Indices);\r
+ //\r
+ // Host status is bi-directional (we preset with a value and expect the\r
+ // device to update it). Allocate a host status buffer which can be mapped\r
+ // to access equally by both processor and the device.\r
+ //\r
+ Status = Dev->VirtIo->AllocateSharedPages (\r
+ Dev->VirtIo,\r
+ EFI_SIZE_TO_PAGES (sizeof *HostStatus),\r
+ &HostStatusBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ HostStatus = HostStatusBuffer;\r
+\r
+ //\r
+ // Map virtio-blk request header (must be done after request header is\r
+ // populated)\r
+ //\r
+ Status = VirtioMapAllBytesInSharedBuffer (\r
+ Dev->VirtIo,\r
+ VirtioOperationBusMasterRead,\r
+ (VOID *) &Request,\r
+ sizeof Request,\r
+ &RequestDeviceAddress,\r
+ &RequestMapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto FreeHostStatusBuffer;\r
+ }\r
+\r
+ //\r
+ // Map data buffer\r
+ //\r
+ if (BufferSize > 0) {\r
+ Status = VirtioMapAllBytesInSharedBuffer (\r
+ Dev->VirtIo,\r
+ (RequestIsWrite ?\r
+ VirtioOperationBusMasterRead :\r
+ VirtioOperationBusMasterWrite),\r
+ (VOID *) Buffer,\r
+ BufferSize,\r
+ &BufferDeviceAddress,\r
+ &BufferMapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto UnmapRequestBuffer;\r
+ }\r
+ }\r
\r
//\r
// preset a host status for ourselves that we do not accept as success\r
//\r
- HostStatus = VIRTIO_BLK_S_IOERR;\r
+ *HostStatus = VIRTIO_BLK_S_IOERR;\r
+\r
+ //\r
+ // Map the Status Buffer with VirtioOperationBusMasterCommonBuffer so that\r
+ // both processor and device can access it.\r
+ //\r
+ Status = VirtioMapAllBytesInSharedBuffer (\r
+ Dev->VirtIo,\r
+ VirtioOperationBusMasterCommonBuffer,\r
+ HostStatusBuffer,\r
+ sizeof *HostStatus,\r
+ &HostStatusDeviceAddress,\r
+ &StatusMapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto UnmapDataBuffer;\r
+ }\r
+\r
+ VirtioPrepare (&Dev->Ring, &Indices);\r
\r
//\r
// ensured by VirtioBlkInit() -- this predicate, in combination with the\r
//\r
// virtio-blk header in first desc\r
//\r
- VirtioAppendDesc (&Dev->Ring, (UINTN) &Request, sizeof Request,\r
- VRING_DESC_F_NEXT, &Indices);\r
+ VirtioAppendDesc (\r
+ &Dev->Ring,\r
+ RequestDeviceAddress,\r
+ sizeof Request,\r
+ VRING_DESC_F_NEXT,\r
+ &Indices\r
+ );\r
\r
//\r
// data buffer for read/write in second desc\r
//\r
// VRING_DESC_F_WRITE is interpreted from the host's point of view.\r
//\r
- VirtioAppendDesc (&Dev->Ring, (UINTN) Buffer, (UINT32) BufferSize,\r
+ VirtioAppendDesc (\r
+ &Dev->Ring,\r
+ BufferDeviceAddress,\r
+ (UINT32) BufferSize,\r
VRING_DESC_F_NEXT | (RequestIsWrite ? 0 : VRING_DESC_F_WRITE),\r
- &Indices);\r
+ &Indices\r
+ );\r
}\r
\r
//\r
// host status in last (second or third) desc\r
//\r
- VirtioAppendDesc (&Dev->Ring, (UINTN) &HostStatus, sizeof HostStatus,\r
- VRING_DESC_F_WRITE, &Indices);\r
+ VirtioAppendDesc (\r
+ &Dev->Ring,\r
+ HostStatusDeviceAddress,\r
+ sizeof *HostStatus,\r
+ VRING_DESC_F_WRITE,\r
+ &Indices\r
+ );\r
\r
//\r
// virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D).\r
//\r
if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices,\r
NULL) == EFI_SUCCESS &&\r
- HostStatus == VIRTIO_BLK_S_OK) {\r
- return EFI_SUCCESS;\r
+ *HostStatus == VIRTIO_BLK_S_OK) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
}\r
\r
- return EFI_DEVICE_ERROR;\r
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, StatusMapping);\r
+\r
+UnmapDataBuffer:\r
+ if (BufferSize > 0) {\r
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, BufferMapping);\r
+ }\r
+\r
+UnmapRequestBuffer:\r
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RequestMapping);\r
+\r
+FreeHostStatusBuffer:\r
+ Dev->VirtIo->FreeSharedPages (\r
+ Dev->VirtIo,\r
+ EFI_SIZE_TO_PAGES (sizeof *HostStatus),\r
+ HostStatusBuffer\r
+ );\r
+\r
+ return Status;\r
}\r
\r
\r