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