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