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
53 Read/Write BufferSize bytes from Lba into Buffer.
55 This function is common to XenPvBlkDxeBlockIoReadBlocks and
56 XenPvBlkDxeBlockIoWriteBlocks.
58 @param This Indicates a pointer to the calling context.
59 @param MediaId Id of the media, changes every time the media is replaced.
60 @param Lba The starting Logical Block Address to read from/write to.
61 @param BufferSize Size of Buffer, must be a multiple of device block size.
62 @param Buffer A pointer to the destination/source buffer for the data.
63 @param IsWrite Indicate if the operation is write or read.
65 @return See description of XenPvBlkDxeBlockIoReadBlocks and
66 XenPvBlkDxeBlockIoWriteBlocks.
70 XenPvBlkDxeBlockIoReadWriteBlocks (
71 IN EFI_BLOCK_IO_PROTOCOL
*This
,
79 XEN_BLOCK_FRONT_IO IoData
;
80 EFI_BLOCK_IO_MEDIA
*Media
= This
->Media
;
85 return EFI_INVALID_PARAMETER
;
87 if (BufferSize
== 0) {
91 if (BufferSize
% Media
->BlockSize
!= 0) {
92 DEBUG ((DEBUG_ERROR
, "XenPvBlkDxe: Bad buffer size: 0x%Lx\n",
94 return EFI_BAD_BUFFER_SIZE
;
97 if (Lba
> Media
->LastBlock
||
98 (BufferSize
/ Media
->BlockSize
) - 1 > Media
->LastBlock
- Lba
) {
100 "XenPvBlkDxe: %a with invalid LBA: 0x%Lx, size: 0x%Lx\n",
101 IsWrite
? "Write" : "Read", Lba
, (UINT64
)BufferSize
));
102 return EFI_INVALID_PARAMETER
;
105 if (IsWrite
&& Media
->ReadOnly
) {
106 return EFI_WRITE_PROTECTED
;
109 if ((Media
->IoAlign
> 1) && (UINTN
)Buffer
& (Media
->IoAlign
- 1)) {
111 // Grub2 does not appear to respect IoAlign of 512, so reallocate the
117 // Try again with a properly aligned buffer.
119 NewBuffer
= AllocateAlignedPages((BufferSize
+ EFI_PAGE_SIZE
) / EFI_PAGE_SIZE
,
122 Status
= XenPvBlkDxeBlockIoReadBlocks (This
, MediaId
,
123 Lba
, BufferSize
, NewBuffer
);
124 CopyMem (Buffer
, NewBuffer
, BufferSize
);
126 CopyMem (NewBuffer
, Buffer
, BufferSize
);
127 Status
= XenPvBlkDxeBlockIoWriteBlocks (This
, MediaId
,
128 Lba
, BufferSize
, NewBuffer
);
130 FreeAlignedPages (NewBuffer
, (BufferSize
+ EFI_PAGE_SIZE
) / EFI_PAGE_SIZE
);
134 IoData
.Dev
= XEN_BLOCK_FRONT_FROM_BLOCK_IO (This
);
135 Sector
= (UINTN
)MultU64x32 (Lba
, Media
->BlockSize
/ 512);
137 while (BufferSize
> 0) {
138 if (((UINTN
)Buffer
& EFI_PAGE_MASK
) == 0) {
139 IoData
.Size
= MIN (BLKIF_MAX_SEGMENTS_PER_REQUEST
* EFI_PAGE_SIZE
,
142 IoData
.Size
= MIN ((BLKIF_MAX_SEGMENTS_PER_REQUEST
- 1) * EFI_PAGE_SIZE
,
146 IoData
.Buffer
= Buffer
;
147 IoData
.Sector
= Sector
;
148 BufferSize
-= IoData
.Size
;
149 Buffer
= (VOID
*) ((UINTN
) Buffer
+ IoData
.Size
);
150 Sector
+= IoData
.Size
/ 512;
151 Status
= XenPvBlockIo (&IoData
, IsWrite
);
152 if (EFI_ERROR (Status
)) {
153 DEBUG ((DEBUG_ERROR
, "XenPvBlkDxe: Error during %a operation.\n",
154 IsWrite
? "write" : "read"));
163 Read BufferSize bytes from Lba into Buffer.
165 @param This Indicates a pointer to the calling context.
166 @param MediaId Id of the media, changes every time the media is replaced.
167 @param Lba The starting Logical Block Address to read from
168 @param BufferSize Size of Buffer, must be a multiple of device block size.
169 @param Buffer A pointer to the destination buffer for the data. The caller is
170 responsible for either having implicit or explicit ownership of the buffer.
172 @retval EFI_SUCCESS The data was read correctly from the device.
173 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
174 @retval EFI_NO_MEDIA There is no media in the device.
175 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
176 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
177 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
178 or the buffer is not on proper alignment.
183 XenPvBlkDxeBlockIoReadBlocks (
184 IN EFI_BLOCK_IO_PROTOCOL
*This
,
191 return XenPvBlkDxeBlockIoReadWriteBlocks (This
,
192 MediaId
, Lba
, BufferSize
, Buffer
, FALSE
);
196 Write BufferSize bytes from Lba into Buffer.
198 @param This Indicates a pointer to the calling context.
199 @param MediaId The media ID that the write request is for.
200 @param Lba The starting logical block address to be written. The caller is
201 responsible for writing to only legitimate locations.
202 @param BufferSize Size of Buffer, must be a multiple of device block size.
203 @param Buffer A pointer to the source buffer for the data.
205 @retval EFI_SUCCESS The data was written correctly to the device.
206 @retval EFI_WRITE_PROTECTED The device can not be written to.
207 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
208 @retval EFI_NO_MEDIA There is no media in the device.
209 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
210 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
211 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
212 or the buffer is not on proper alignment.
217 XenPvBlkDxeBlockIoWriteBlocks (
218 IN EFI_BLOCK_IO_PROTOCOL
*This
,
225 return XenPvBlkDxeBlockIoReadWriteBlocks (This
,
226 MediaId
, Lba
, BufferSize
, Buffer
, TRUE
);
230 Flush the Block Device.
232 @param This Indicates a pointer to the calling context.
234 @retval EFI_SUCCESS All outstanding data was written to the device
235 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
236 @retval EFI_NO_MEDIA There is no media in the device.
241 XenPvBlkDxeBlockIoFlushBlocks (
242 IN EFI_BLOCK_IO_PROTOCOL
*This
245 XenPvBlockSync (XEN_BLOCK_FRONT_FROM_BLOCK_IO (This
));
250 Reset the block device hardware.
252 @param[in] This Indicates a pointer to the calling context.
253 @param[in] ExtendedVerification Not used.
255 @retval EFI_SUCCESS The device was reset.
260 XenPvBlkDxeBlockIoReset (
261 IN EFI_BLOCK_IO_PROTOCOL
*This
,
262 IN BOOLEAN ExtendedVerification
266 // Since the initialization of the devices is done, then the device is
267 // working correctly.