2 BlockIo implementation for Xen PV Block driver.
4 This file is implementing the interface between the actual driver in
5 BlockFront.c to the BlockIo protocol.
7 Copyright (C) 2014, Citrix Ltd.
9 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include "XenPvBlkDxe.h"
15 #include "BlockFront.h"
18 /// Block I/O Media structure
20 GLOBAL_REMOVE_IF_UNREFERENCED
21 EFI_BLOCK_IO_MEDIA gXenPvBlkDxeBlockIoMedia
= {
23 FALSE
, // RemovableMedia
24 FALSE
, // MediaPresent
25 FALSE
, // LogicalPartition
27 FALSE
, // WriteCaching
29 512, // IoAlign, BlockFront does not support less than 512 bits-aligned.
31 0, // LowestAlignedLba
32 0, // LogicalBlocksPerPhysicalBlock
33 0 // OptimalTransferLengthGranularity
37 /// Block I/O Protocol instance
39 GLOBAL_REMOVE_IF_UNREFERENCED
40 EFI_BLOCK_IO_PROTOCOL gXenPvBlkDxeBlockIo
= {
41 EFI_BLOCK_IO_PROTOCOL_REVISION3
, // Revision
42 &gXenPvBlkDxeBlockIoMedia
, // Media
43 XenPvBlkDxeBlockIoReset
, // Reset
44 XenPvBlkDxeBlockIoReadBlocks
, // ReadBlocks
45 XenPvBlkDxeBlockIoWriteBlocks
, // WriteBlocks
46 XenPvBlkDxeBlockIoFlushBlocks
// FlushBlocks
50 Read/Write BufferSize bytes from Lba into Buffer.
52 This function is common to XenPvBlkDxeBlockIoReadBlocks and
53 XenPvBlkDxeBlockIoWriteBlocks.
55 @param This Indicates a pointer to the calling context.
56 @param MediaId Id of the media, changes every time the media is replaced.
57 @param Lba The starting Logical Block Address to read from/write to.
58 @param BufferSize Size of Buffer, must be a multiple of device block size.
59 @param Buffer A pointer to the destination/source buffer for the data.
60 @param IsWrite Indicate if the operation is write or read.
62 @return See description of XenPvBlkDxeBlockIoReadBlocks and
63 XenPvBlkDxeBlockIoWriteBlocks.
67 XenPvBlkDxeBlockIoReadWriteBlocks (
68 IN EFI_BLOCK_IO_PROTOCOL
*This
,
76 XEN_BLOCK_FRONT_IO IoData
;
77 EFI_BLOCK_IO_MEDIA
*Media
= This
->Media
;
82 return EFI_INVALID_PARAMETER
;
85 if (BufferSize
== 0) {
89 if (BufferSize
% Media
->BlockSize
!= 0) {
92 "XenPvBlkDxe: Bad buffer size: 0x%Lx\n",
95 return EFI_BAD_BUFFER_SIZE
;
98 if ((Lba
> Media
->LastBlock
) ||
99 ((BufferSize
/ Media
->BlockSize
) - 1 > Media
->LastBlock
- Lba
))
103 "XenPvBlkDxe: %a with invalid LBA: 0x%Lx, size: 0x%Lx\n",
104 IsWrite
? "Write" : "Read",
108 return EFI_INVALID_PARAMETER
;
111 if (IsWrite
&& Media
->ReadOnly
) {
112 return EFI_WRITE_PROTECTED
;
115 if ((Media
->IoAlign
> 1) && (UINTN
)Buffer
& (Media
->IoAlign
- 1)) {
117 // Grub2 does not appear to respect IoAlign of 512, so reallocate the
123 // Try again with a properly aligned buffer.
125 NewBuffer
= AllocateAlignedPages (
126 (BufferSize
+ EFI_PAGE_SIZE
) / EFI_PAGE_SIZE
,
130 Status
= XenPvBlkDxeBlockIoReadBlocks (
137 CopyMem (Buffer
, NewBuffer
, BufferSize
);
139 CopyMem (NewBuffer
, Buffer
, BufferSize
);
140 Status
= XenPvBlkDxeBlockIoWriteBlocks (
149 FreeAlignedPages (NewBuffer
, (BufferSize
+ EFI_PAGE_SIZE
) / EFI_PAGE_SIZE
);
153 IoData
.Dev
= XEN_BLOCK_FRONT_FROM_BLOCK_IO (This
);
154 Sector
= (UINTN
)MultU64x32 (Lba
, Media
->BlockSize
/ 512);
156 while (BufferSize
> 0) {
157 if (((UINTN
)Buffer
& EFI_PAGE_MASK
) == 0) {
159 BLKIF_MAX_SEGMENTS_PER_REQUEST
* EFI_PAGE_SIZE
,
164 (BLKIF_MAX_SEGMENTS_PER_REQUEST
- 1) * EFI_PAGE_SIZE
,
169 IoData
.Buffer
= Buffer
;
170 IoData
.Sector
= Sector
;
171 BufferSize
-= IoData
.Size
;
172 Buffer
= (VOID
*)((UINTN
)Buffer
+ IoData
.Size
);
173 Sector
+= IoData
.Size
/ 512;
174 Status
= XenPvBlockIo (&IoData
, IsWrite
);
175 if (EFI_ERROR (Status
)) {
178 "XenPvBlkDxe: Error during %a operation.\n",
179 IsWrite
? "write" : "read"
189 Read BufferSize bytes from Lba into Buffer.
191 @param This Indicates a pointer to the calling context.
192 @param MediaId Id of the media, changes every time the media is replaced.
193 @param Lba The starting Logical Block Address to read from
194 @param BufferSize Size of Buffer, must be a multiple of device block size.
195 @param Buffer A pointer to the destination buffer for the data. The caller is
196 responsible for either having implicit or explicit ownership of the buffer.
198 @retval EFI_SUCCESS The data was read correctly from the device.
199 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
200 @retval EFI_NO_MEDIA There is no media in the device.
201 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
202 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
203 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
204 or the buffer is not on proper alignment.
209 XenPvBlkDxeBlockIoReadBlocks (
210 IN EFI_BLOCK_IO_PROTOCOL
*This
,
217 return XenPvBlkDxeBlockIoReadWriteBlocks (
228 Write BufferSize bytes from Lba into Buffer.
230 @param This Indicates a pointer to the calling context.
231 @param MediaId The media ID that the write request is for.
232 @param Lba The starting logical block address to be written. The caller is
233 responsible for writing to only legitimate locations.
234 @param BufferSize Size of Buffer, must be a multiple of device block size.
235 @param Buffer A pointer to the source buffer for the data.
237 @retval EFI_SUCCESS The data was written correctly to the device.
238 @retval EFI_WRITE_PROTECTED The device can not be written to.
239 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
240 @retval EFI_NO_MEDIA There is no media in the device.
241 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
242 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
243 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
244 or the buffer is not on proper alignment.
249 XenPvBlkDxeBlockIoWriteBlocks (
250 IN EFI_BLOCK_IO_PROTOCOL
*This
,
257 return XenPvBlkDxeBlockIoReadWriteBlocks (
268 Flush the Block Device.
270 @param This Indicates a pointer to the calling context.
272 @retval EFI_SUCCESS All outstanding data was written to the device
273 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
274 @retval EFI_NO_MEDIA There is no media in the device.
279 XenPvBlkDxeBlockIoFlushBlocks (
280 IN EFI_BLOCK_IO_PROTOCOL
*This
283 XenPvBlockSync (XEN_BLOCK_FRONT_FROM_BLOCK_IO (This
));
288 Reset the block device hardware.
290 @param[in] This Indicates a pointer to the calling context.
291 @param[in] ExtendedVerification Not used.
293 @retval EFI_SUCCESS The device was reset.
298 XenPvBlkDxeBlockIoReset (
299 IN EFI_BLOCK_IO_PROTOCOL
*This
,
300 IN BOOLEAN ExtendedVerification
304 // Since the initialization of the devices is done, then the device is
305 // working correctly.