]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c
MdeModulePkg/AhciPei: Add PEI BlockIO support
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AhciPei / AhciPeiBlockIo.c
1 /** @file
2 The AhciPei driver is used to manage ATA hard disk device working under AHCI
3 mode at PEI phase.
4
5 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "AhciPei.h"
12
13 /**
14 Traverse the attached ATA devices list to find out the device with given index.
15
16 @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
17 instance.
18 @param[in] DeviceIndex The device index.
19
20 @retval The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of the device
21 info to access.
22
23 **/
24 PEI_AHCI_ATA_DEVICE_DATA *
25 SearchDeviceByIndex (
26 IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
27 IN UINTN DeviceIndex
28 )
29 {
30 PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
31 LIST_ENTRY *Node;
32
33 if ((DeviceIndex == 0) || (DeviceIndex > Private->ActiveDevices)) {
34 return NULL;
35 }
36
37 Node = GetFirstNode (&Private->DeviceList);
38 while (!IsNull (&Private->DeviceList, Node)) {
39 DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
40
41 if (DeviceData->DeviceIndex == DeviceIndex) {
42 return DeviceData;
43 }
44
45 Node = GetNextNode (&Private->DeviceList, Node);
46 }
47
48 return NULL;
49 }
50
51 /**
52 Read a number of blocks from ATA device.
53
54 This function performs ATA pass through transactions to read data from ATA device.
55 It may separate the read request into several ATA pass through transactions.
56
57 @param[in] DeviceData The pointer to the PEI_AHCI_ATA_DEVICE_DATA
58 data structure.
59 @param[in,out] Buffer The pointer to the current transaction buffer.
60 @param[in] StartLba The starting logical block address to be accessed.
61 @param[in] NumberOfBlocks The block number or sector count of the transfer.
62
63 @retval EFI_SUCCESS The data transfer is complete successfully.
64 @return Others Some error occurs when transferring data.
65
66 **/
67 EFI_STATUS
68 AccessAtaDevice (
69 IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
70 IN OUT UINT8 *Buffer,
71 IN EFI_LBA StartLba,
72 IN UINTN NumberOfBlocks
73 )
74 {
75 EFI_STATUS Status;
76 UINTN MaxTransferBlockNumber;
77 UINTN TransferBlockNumber;
78 UINTN BlockSize;
79
80 //
81 // Ensure Lba48Bit is a valid boolean value
82 //
83 ASSERT ((UINTN) DeviceData->Lba48Bit < 2);
84 if ((UINTN) DeviceData->Lba48Bit >= 2) {
85 return EFI_INVALID_PARAMETER;
86 }
87
88 Status = EFI_SUCCESS;
89 MaxTransferBlockNumber = mMaxTransferBlockNumber[DeviceData->Lba48Bit];
90 BlockSize = DeviceData->Media.BlockSize;
91
92 do {
93 if (NumberOfBlocks > MaxTransferBlockNumber) {
94 TransferBlockNumber = MaxTransferBlockNumber;
95 NumberOfBlocks -= MaxTransferBlockNumber;
96 } else {
97 TransferBlockNumber = NumberOfBlocks;
98 NumberOfBlocks = 0;
99 }
100 DEBUG ((
101 DEBUG_BLKIO, "%a: Blocking AccessAtaDevice, TransferBlockNumber = %x; StartLba = %x\n",
102 __FUNCTION__, TransferBlockNumber, StartLba
103 ));
104
105 Status = TransferAtaDevice (
106 DeviceData,
107 Buffer,
108 StartLba,
109 (UINT32) TransferBlockNumber,
110 FALSE // Read
111 );
112 if (EFI_ERROR (Status)) {
113 return Status;
114 }
115
116 StartLba += TransferBlockNumber;
117 Buffer += TransferBlockNumber * BlockSize;
118 } while (NumberOfBlocks > 0);
119
120 return Status;
121 }
122
123 /**
124 Read specified bytes from Lba from the device.
125
126 @param[in] DeviceData The pointer to the PEI_AHCI_ATA_DEVICE_DATA data structure.
127 @param[out] Buffer The Buffer used to store the Data read from the device.
128 @param[in] StartLba The start block number.
129 @param[in] BufferSize Total bytes to be read.
130
131 @retval EFI_SUCCESS Data are read from the device.
132 @retval Others Fail to read all the data.
133
134 **/
135 EFI_STATUS
136 AhciRead (
137 IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
138 OUT VOID *Buffer,
139 IN EFI_LBA StartLba,
140 IN UINTN BufferSize
141 )
142 {
143 EFI_STATUS Status;
144 UINTN BlockSize;
145 UINTN NumberOfBlocks;
146
147 //
148 // Check parameters.
149 //
150 if (Buffer == NULL) {
151 return EFI_INVALID_PARAMETER;
152 }
153
154 if (BufferSize == 0) {
155 return EFI_SUCCESS;
156 }
157
158 BlockSize = DeviceData->Media.BlockSize;
159 if ((BufferSize % BlockSize) != 0) {
160 return EFI_BAD_BUFFER_SIZE;
161 }
162
163 if (StartLba > DeviceData->Media.LastBlock) {
164 return EFI_INVALID_PARAMETER;
165 }
166 NumberOfBlocks = BufferSize / BlockSize;
167 if (NumberOfBlocks - 1 > DeviceData->Media.LastBlock - StartLba) {
168 return EFI_INVALID_PARAMETER;
169 }
170
171 //
172 // Invoke low level AtaDevice Access Routine.
173 //
174 Status = AccessAtaDevice (DeviceData, Buffer, StartLba, NumberOfBlocks);
175
176 return Status;
177 }
178
179
180 /**
181 Gets the count of block I/O devices that one specific block driver detects.
182
183 This function is used for getting the count of block I/O devices that one
184 specific block driver detects. If no device is detected, then the function
185 will return zero.
186
187 @param[in] PeiServices General-purpose services that are available
188 to every PEIM.
189 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
190 instance.
191 @param[out] NumberBlockDevices The number of block I/O devices discovered.
192
193 @retval EFI_SUCCESS The operation performed successfully.
194
195 **/
196 EFI_STATUS
197 EFIAPI
198 AhciBlockIoGetDeviceNo (
199 IN EFI_PEI_SERVICES **PeiServices,
200 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
201 OUT UINTN *NumberBlockDevices
202 )
203 {
204 PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
205
206 if (This == NULL || NumberBlockDevices == NULL) {
207 return EFI_INVALID_PARAMETER;
208 }
209
210 Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
211 *NumberBlockDevices = Private->ActiveDevices;
212
213 return EFI_SUCCESS;
214 }
215
216 /**
217 Gets a block device's media information.
218
219 This function will provide the caller with the specified block device's media
220 information. If the media changes, calling this function will update the media
221 information accordingly.
222
223 @param[in] PeiServices General-purpose services that are available to every
224 PEIM
225 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
226 @param[in] DeviceIndex Specifies the block device to which the function wants
227 to talk. Because the driver that implements Block I/O
228 PPIs will manage multiple block devices, the PPIs that
229 want to talk to a single device must specify the
230 device index that was assigned during the enumeration
231 process. This index is a number from one to
232 NumberBlockDevices.
233 @param[out] MediaInfo The media information of the specified block media.
234 The caller is responsible for the ownership of this
235 data structure.
236
237 @par Note:
238 The MediaInfo structure describes an enumeration of possible block device
239 types. This enumeration exists because no device paths are actually passed
240 across interfaces that describe the type or class of hardware that is publishing
241 the block I/O interface. This enumeration will allow for policy decisions
242 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
243 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
244 by a given device type, they should be reported in ascending order; this
245 order also applies to nested partitions, such as legacy MBR, where the
246 outermost partitions would have precedence in the reporting order. The
247 same logic applies to systems such as IDE that have precedence relationships
248 like "Master/Slave" or "Primary/Secondary". The master device should be
249 reported first, the slave second.
250
251 @retval EFI_SUCCESS Media information about the specified block device
252 was obtained successfully.
253 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
254 error.
255
256 **/
257 EFI_STATUS
258 EFIAPI
259 AhciBlockIoGetMediaInfo (
260 IN EFI_PEI_SERVICES **PeiServices,
261 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
262 IN UINTN DeviceIndex,
263 OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
264 )
265 {
266 PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
267 PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
268
269 if (This == NULL || MediaInfo == NULL) {
270 return EFI_INVALID_PARAMETER;
271 }
272
273 Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
274 DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
275 if (DeviceData == NULL) {
276 return EFI_NOT_FOUND;
277 }
278
279 MediaInfo->DeviceType = (EFI_PEI_BLOCK_DEVICE_TYPE) EDKII_PEI_BLOCK_DEVICE_TYPE_ATA_HARD_DISK;
280 MediaInfo->MediaPresent = TRUE;
281 MediaInfo->LastBlock = (UINTN) DeviceData->Media.LastBlock;
282 MediaInfo->BlockSize = DeviceData->Media.BlockSize;
283
284 return EFI_SUCCESS;
285 }
286
287 /**
288 Reads the requested number of blocks from the specified block device.
289
290 The function reads the requested number of blocks from the device. All the
291 blocks are read, or an error is returned. If there is no media in the device,
292 the function returns EFI_NO_MEDIA.
293
294 @param[in] PeiServices General-purpose services that are available to
295 every PEIM.
296 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
297 @param[in] DeviceIndex Specifies the block device to which the function wants
298 to talk. Because the driver that implements Block I/O
299 PPIs will manage multiple block devices, PPIs that
300 want to talk to a single device must specify the device
301 index that was assigned during the enumeration process.
302 This index is a number from one to NumberBlockDevices.
303 @param[in] StartLBA The starting logical block address (LBA) to read from
304 on the device
305 @param[in] BufferSize The size of the Buffer in bytes. This number must be
306 a multiple of the intrinsic block size of the device.
307 @param[out] Buffer A pointer to the destination buffer for the data.
308 The caller is responsible for the ownership of the
309 buffer.
310
311 @retval EFI_SUCCESS The data was read correctly from the device.
312 @retval EFI_DEVICE_ERROR The device reported an error while attempting
313 to perform the read operation.
314 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
315 valid, or the buffer is not properly aligned.
316 @retval EFI_NO_MEDIA There is no media in the device.
317 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
318 the intrinsic block size of the device.
319
320 **/
321 EFI_STATUS
322 EFIAPI
323 AhciBlockIoReadBlocks (
324 IN EFI_PEI_SERVICES **PeiServices,
325 IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
326 IN UINTN DeviceIndex,
327 IN EFI_PEI_LBA StartLBA,
328 IN UINTN BufferSize,
329 OUT VOID *Buffer
330 )
331 {
332 PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
333 PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
334
335 if (This == NULL) {
336 return EFI_INVALID_PARAMETER;
337 }
338
339 Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
340 DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
341 if (DeviceData == NULL) {
342 return EFI_NOT_FOUND;
343 }
344
345 return AhciRead (DeviceData, Buffer, StartLBA, BufferSize);
346 }
347
348 /**
349 Gets the count of block I/O devices that one specific block driver detects.
350
351 This function is used for getting the count of block I/O devices that one
352 specific block driver detects. If no device is detected, then the function
353 will return zero.
354
355 @param[in] PeiServices General-purpose services that are available
356 to every PEIM.
357 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
358 instance.
359 @param[out] NumberBlockDevices The number of block I/O devices discovered.
360
361 @retval EFI_SUCCESS The operation performed successfully.
362
363 **/
364 EFI_STATUS
365 EFIAPI
366 AhciBlockIoGetDeviceNo2 (
367 IN EFI_PEI_SERVICES **PeiServices,
368 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
369 OUT UINTN *NumberBlockDevices
370 )
371 {
372 PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
373
374 if (This == NULL || NumberBlockDevices == NULL) {
375 return EFI_INVALID_PARAMETER;
376 }
377
378 Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
379 *NumberBlockDevices = Private->ActiveDevices;
380
381 return EFI_SUCCESS;
382 }
383
384 /**
385 Gets a block device's media information.
386
387 This function will provide the caller with the specified block device's media
388 information. If the media changes, calling this function will update the media
389 information accordingly.
390
391 @param[in] PeiServices General-purpose services that are available to every
392 PEIM
393 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
394 @param[in] DeviceIndex Specifies the block device to which the function wants
395 to talk. Because the driver that implements Block I/O
396 PPIs will manage multiple block devices, the PPIs that
397 want to talk to a single device must specify the
398 device index that was assigned during the enumeration
399 process. This index is a number from one to
400 NumberBlockDevices.
401 @param[out] MediaInfo The media information of the specified block media.
402 The caller is responsible for the ownership of this
403 data structure.
404
405 @par Note:
406 The MediaInfo structure describes an enumeration of possible block device
407 types. This enumeration exists because no device paths are actually passed
408 across interfaces that describe the type or class of hardware that is publishing
409 the block I/O interface. This enumeration will allow for policy decisions
410 in the Recovery PEIM, such as "Try to recover from legacy floppy first,
411 LS-120 second, CD-ROM third." If there are multiple partitions abstracted
412 by a given device type, they should be reported in ascending order; this
413 order also applies to nested partitions, such as legacy MBR, where the
414 outermost partitions would have precedence in the reporting order. The
415 same logic applies to systems such as IDE that have precedence relationships
416 like "Master/Slave" or "Primary/Secondary". The master device should be
417 reported first, the slave second.
418
419 @retval EFI_SUCCESS Media information about the specified block device
420 was obtained successfully.
421 @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
422 error.
423
424 **/
425 EFI_STATUS
426 EFIAPI
427 AhciBlockIoGetMediaInfo2 (
428 IN EFI_PEI_SERVICES **PeiServices,
429 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
430 IN UINTN DeviceIndex,
431 OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
432 )
433 {
434 PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
435 PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
436
437 if (This == NULL || MediaInfo == NULL) {
438 return EFI_INVALID_PARAMETER;
439 }
440
441 Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
442 DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
443 if (DeviceData == NULL) {
444 return EFI_NOT_FOUND;
445 }
446
447 CopyMem (
448 MediaInfo,
449 &DeviceData->Media,
450 sizeof (EFI_PEI_BLOCK_IO2_MEDIA)
451 );
452
453 return EFI_SUCCESS;
454 }
455
456 /**
457 Reads the requested number of blocks from the specified block device.
458
459 The function reads the requested number of blocks from the device. All the
460 blocks are read, or an error is returned. If there is no media in the device,
461 the function returns EFI_NO_MEDIA.
462
463 @param[in] PeiServices General-purpose services that are available to
464 every PEIM.
465 @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
466 @param[in] DeviceIndex Specifies the block device to which the function wants
467 to talk. Because the driver that implements Block I/O
468 PPIs will manage multiple block devices, PPIs that
469 want to talk to a single device must specify the device
470 index that was assigned during the enumeration process.
471 This index is a number from one to NumberBlockDevices.
472 @param[in] StartLBA The starting logical block address (LBA) to read from
473 on the device
474 @param[in] BufferSize The size of the Buffer in bytes. This number must be
475 a multiple of the intrinsic block size of the device.
476 @param[out] Buffer A pointer to the destination buffer for the data.
477 The caller is responsible for the ownership of the
478 buffer.
479
480 @retval EFI_SUCCESS The data was read correctly from the device.
481 @retval EFI_DEVICE_ERROR The device reported an error while attempting
482 to perform the read operation.
483 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
484 valid, or the buffer is not properly aligned.
485 @retval EFI_NO_MEDIA There is no media in the device.
486 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
487 the intrinsic block size of the device.
488
489 **/
490 EFI_STATUS
491 EFIAPI
492 AhciBlockIoReadBlocks2 (
493 IN EFI_PEI_SERVICES **PeiServices,
494 IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
495 IN UINTN DeviceIndex,
496 IN EFI_PEI_LBA StartLBA,
497 IN UINTN BufferSize,
498 OUT VOID *Buffer
499 )
500 {
501 PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
502
503 if (This == NULL) {
504 return EFI_INVALID_PARAMETER;
505 }
506
507 Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
508 return AhciBlockIoReadBlocks (
509 PeiServices,
510 &Private->BlkIoPpi,
511 DeviceIndex,
512 StartLBA,
513 BufferSize,
514 Buffer
515 );
516 }