]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
CommitLineData
a41b5272 1/** @file\r
2 The file for AHCI mode of ATA host controller.\r
1aff716a 3\r
cc28ab7a 4 Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.<BR>\r
9c32277a 5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
9d510e61 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a41b5272 7\r
8**/\r
9\r
10#include "AtaAtapiPassThru.h"\r
11\r
12/**\r
13 Read AHCI Operation register.\r
14\r
15 @param PciIo The PCI IO protocol instance.\r
16 @param Offset The operation register offset.\r
17\r
18 @return The register content read.\r
19\r
20**/\r
21UINT32\r
22EFIAPI\r
23AhciReadReg (\r
24 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
25 IN UINT32 Offset\r
26 )\r
27{\r
1436aea4 28 UINT32 Data;\r
a41b5272 29\r
30 ASSERT (PciIo != NULL);\r
1aff716a 31\r
a41b5272 32 Data = 0;\r
33\r
34 PciIo->Mem.Read (\r
35 PciIo,\r
36 EfiPciIoWidthUint32,\r
37 EFI_AHCI_BAR_INDEX,\r
1436aea4 38 (UINT64)Offset,\r
a41b5272 39 1,\r
40 &Data\r
41 );\r
42\r
43 return Data;\r
44}\r
45\r
46/**\r
47 Write AHCI Operation register.\r
48\r
49 @param PciIo The PCI IO protocol instance.\r
50 @param Offset The operation register offset.\r
51 @param Data The data used to write down.\r
52\r
53**/\r
54VOID\r
55EFIAPI\r
56AhciWriteReg (\r
57 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
58 IN UINT32 Offset,\r
59 IN UINT32 Data\r
60 )\r
61{\r
62 ASSERT (PciIo != NULL);\r
63\r
64 PciIo->Mem.Write (\r
65 PciIo,\r
66 EfiPciIoWidthUint32,\r
67 EFI_AHCI_BAR_INDEX,\r
1436aea4 68 (UINT64)Offset,\r
a41b5272 69 1,\r
70 &Data\r
71 );\r
72\r
1436aea4 73 return;\r
a41b5272 74}\r
75\r
76/**\r
77 Do AND operation with the value of AHCI Operation register.\r
78\r
79 @param PciIo The PCI IO protocol instance.\r
80 @param Offset The operation register offset.\r
81 @param AndData The data used to do AND operation.\r
82\r
83**/\r
84VOID\r
85EFIAPI\r
86AhciAndReg (\r
87 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
88 IN UINT32 Offset,\r
89 IN UINT32 AndData\r
90 )\r
91{\r
1436aea4 92 UINT32 Data;\r
1aff716a 93\r
a41b5272 94 ASSERT (PciIo != NULL);\r
95\r
1436aea4 96 Data = AhciReadReg (PciIo, Offset);\r
a41b5272 97\r
98 Data &= AndData;\r
99\r
100 AhciWriteReg (PciIo, Offset, Data);\r
101}\r
102\r
103/**\r
104 Do OR operation with the value of AHCI Operation register.\r
105\r
106 @param PciIo The PCI IO protocol instance.\r
107 @param Offset The operation register offset.\r
108 @param OrData The data used to do OR operation.\r
109\r
110**/\r
111VOID\r
112EFIAPI\r
113AhciOrReg (\r
114 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
115 IN UINT32 Offset,\r
116 IN UINT32 OrData\r
117 )\r
118{\r
1436aea4 119 UINT32 Data;\r
a41b5272 120\r
121 ASSERT (PciIo != NULL);\r
122\r
1436aea4 123 Data = AhciReadReg (PciIo, Offset);\r
a41b5272 124\r
125 Data |= OrData;\r
126\r
127 AhciWriteReg (PciIo, Offset, Data);\r
128}\r
129\r
130/**\r
8536cc4b 131 Wait for the value of the specified MMIO register set to the test value.\r
1aff716a 132\r
aca84419 133 @param PciIo The PCI IO protocol instance.\r
8536cc4b 134 @param Offset The MMIO address to test.\r
aca84419 135 @param MaskValue The mask value of memory.\r
136 @param TestValue The test value of memory.\r
8536cc4b 137 @param Timeout The time out value for wait memory set, uses 100ns as a unit.\r
a41b5272 138\r
8536cc4b 139 @retval EFI_TIMEOUT The MMIO setting is time out.\r
140 @retval EFI_SUCCESS The MMIO is correct set.\r
a41b5272 141\r
142**/\r
143EFI_STATUS\r
144EFIAPI\r
8536cc4b 145AhciWaitMmioSet (\r
1436aea4
MK
146 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
147 IN UINTN Offset,\r
148 IN UINT32 MaskValue,\r
149 IN UINT32 TestValue,\r
150 IN UINT64 Timeout\r
a41b5272 151 )\r
152{\r
1436aea4
MK
153 UINT32 Value;\r
154 UINT64 Delay;\r
155 BOOLEAN InfiniteWait;\r
a41b5272 156\r
ab82122d
TF
157 if (Timeout == 0) {\r
158 InfiniteWait = TRUE;\r
159 } else {\r
160 InfiniteWait = FALSE;\r
161 }\r
162\r
163 Delay = DivU64x32 (Timeout, 1000) + 1;\r
a41b5272 164\r
165 do {\r
8536cc4b 166 //\r
167 // Access PCI MMIO space to see if the value is the tested one.\r
168 //\r
1436aea4 169 Value = AhciReadReg (PciIo, (UINT32)Offset) & MaskValue;\r
a41b5272 170\r
171 if (Value == TestValue) {\r
172 return EFI_SUCCESS;\r
173 }\r
174\r
175 //\r
176 // Stall for 100 microseconds.\r
177 //\r
178 MicroSecondDelay (100);\r
179\r
180 Delay--;\r
ab82122d 181 } while (InfiniteWait || (Delay > 0));\r
a41b5272 182\r
8536cc4b 183 return EFI_TIMEOUT;\r
184}\r
185\r
186/**\r
187 Wait for the value of the specified system memory set to the test value.\r
1aff716a 188\r
8536cc4b 189 @param Address The system memory address to test.\r
190 @param MaskValue The mask value of memory.\r
191 @param TestValue The test value of memory.\r
192 @param Timeout The time out value for wait memory set, uses 100ns as a unit.\r
193\r
194 @retval EFI_TIMEOUT The system memory setting is time out.\r
195 @retval EFI_SUCCESS The system memory is correct set.\r
196\r
197**/\r
198EFI_STATUS\r
199EFIAPI\r
200AhciWaitMemSet (\r
1436aea4
MK
201 IN EFI_PHYSICAL_ADDRESS Address,\r
202 IN UINT32 MaskValue,\r
203 IN UINT32 TestValue,\r
204 IN UINT64 Timeout\r
8536cc4b 205 )\r
206{\r
1436aea4
MK
207 UINT32 Value;\r
208 UINT64 Delay;\r
209 BOOLEAN InfiniteWait;\r
ab82122d
TF
210\r
211 if (Timeout == 0) {\r
212 InfiniteWait = TRUE;\r
213 } else {\r
214 InfiniteWait = FALSE;\r
215 }\r
8536cc4b 216\r
ab82122d 217 Delay = DivU64x32 (Timeout, 1000) + 1;\r
8536cc4b 218\r
219 do {\r
220 //\r
8c39253d 221 // Access system memory to see if the value is the tested one.\r
8536cc4b 222 //\r
223 // The system memory pointed by Address will be updated by the\r
224 // SATA Host Controller, "volatile" is introduced to prevent\r
225 // compiler from optimizing the access to the memory address\r
226 // to only read once.\r
227 //\r
1436aea4 228 Value = *(volatile UINT32 *)(UINTN)Address;\r
8536cc4b 229 Value &= MaskValue;\r
230\r
231 if (Value == TestValue) {\r
232 return EFI_SUCCESS;\r
233 }\r
234\r
235 //\r
236 // Stall for 100 microseconds.\r
237 //\r
238 MicroSecondDelay (100);\r
239\r
240 Delay--;\r
ab82122d 241 } while (InfiniteWait || (Delay > 0));\r
8536cc4b 242\r
243 return EFI_TIMEOUT;\r
a41b5272 244}\r
245\r
490b5ea1 246/**\r
247 Check the memory status to the test value.\r
1aff716a 248\r
cc28ab7a
AM
249 @param[in] Address The memory address to test.\r
250 @param[in] MaskValue The mask value of memory.\r
251 @param[in] TestValue The test value of memory.\r
490b5ea1 252\r
cc28ab7a 253 @retval EFI_NOT_READY The memory is not set.\r
490b5ea1 254 @retval EFI_SUCCESS The memory is correct set.\r
490b5ea1 255**/\r
256EFI_STATUS\r
257EFIAPI\r
258AhciCheckMemSet (\r
1436aea4
MK
259 IN UINTN Address,\r
260 IN UINT32 MaskValue,\r
261 IN UINT32 TestValue\r
490b5ea1 262 )\r
263{\r
1436aea4 264 UINT32 Value;\r
490b5ea1 265\r
1436aea4 266 Value = *(volatile UINT32 *)Address;\r
8536cc4b 267 Value &= MaskValue;\r
490b5ea1 268\r
269 if (Value == TestValue) {\r
270 return EFI_SUCCESS;\r
271 }\r
272\r
cc28ab7a 273 return EFI_NOT_READY;\r
490b5ea1 274}\r
275\r
a41b5272 276/**\r
277\r
278 Clear the port interrupt and error status. It will also clear\r
279 HBA interrupt status.\r
1aff716a 280\r
a41b5272 281 @param PciIo The PCI IO protocol instance.\r
282 @param Port The number of port.\r
1aff716a 283\r
284**/\r
a41b5272 285VOID\r
286EFIAPI\r
287AhciClearPortStatus (\r
1436aea4
MK
288 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
289 IN UINT8 Port\r
1aff716a 290 )\r
a41b5272 291{\r
1436aea4 292 UINT32 Offset;\r
a41b5272 293\r
294 //\r
295 // Clear any error status\r
490b5ea1 296 //\r
a41b5272 297 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
298 AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
299\r
300 //\r
301 // Clear any port interrupt status\r
302 //\r
303 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
304 AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
305\r
306 //\r
307 // Clear any HBA interrupt status\r
308 //\r
309 AhciWriteReg (PciIo, EFI_AHCI_IS_OFFSET, AhciReadReg (PciIo, EFI_AHCI_IS_OFFSET));\r
310}\r
311\r
e519983a 312/**\r
313 This function is used to dump the Status Registers and if there is ERR bit set\r
314 in the Status Register, the Error Register's value is also be dumped.\r
315\r
316 @param PciIo The PCI IO protocol instance.\r
a7b3f90f 317 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
e519983a 318 @param Port The number of port.\r
319 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
320\r
321**/\r
322VOID\r
323EFIAPI\r
324AhciDumpPortStatus (\r
1436aea4
MK
325 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
326 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
327 IN UINT8 Port,\r
328 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
e519983a 329 )\r
330{\r
1436aea4
MK
331 UINTN Offset;\r
332 UINT32 Data;\r
333 UINTN FisBaseAddr;\r
334 EFI_STATUS Status;\r
e519983a 335\r
336 ASSERT (PciIo != NULL);\r
337\r
e519983a 338 if (AtaStatusBlock != NULL) {\r
339 ZeroMem (AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
340\r
a7b3f90f
FT
341 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
342 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
343\r
cc28ab7a 344 Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H);\r
a7b3f90f
FT
345 if (!EFI_ERROR (Status)) {\r
346 //\r
347 // If D2H FIS is received, update StatusBlock with its content.\r
348 //\r
349 CopyMem (AtaStatusBlock, (UINT8 *)Offset, sizeof (EFI_ATA_STATUS_BLOCK));\r
350 } else {\r
351 //\r
352 // If D2H FIS is not received, only update Status & Error field through PxTFD\r
353 // as there is no other way to get the content of the Shadow Register Block.\r
354 //\r
355 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
356 Data = AhciReadReg (PciIo, (UINT32)Offset);\r
357\r
1436aea4 358 AtaStatusBlock->AtaStatus = (UINT8)Data;\r
a7b3f90f
FT
359 if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {\r
360 AtaStatusBlock->AtaError = (UINT8)(Data >> 8);\r
361 }\r
e519983a 362 }\r
363 }\r
364}\r
365\r
a41b5272 366/**\r
367 Enable the FIS running for giving port.\r
1aff716a 368\r
a41b5272 369 @param PciIo The PCI IO protocol instance.\r
370 @param Port The number of port.\r
8536cc4b 371 @param Timeout The timeout value of enabling FIS, uses 100ns as a unit.\r
a41b5272 372\r
373 @retval EFI_DEVICE_ERROR The FIS enable setting fails.\r
374 @retval EFI_TIMEOUT The FIS enable setting is time out.\r
375 @retval EFI_SUCCESS The FIS enable successfully.\r
376\r
377**/\r
378EFI_STATUS\r
379EFIAPI\r
380AhciEnableFisReceive (\r
1436aea4
MK
381 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
382 IN UINT8 Port,\r
383 IN UINT64 Timeout\r
490b5ea1 384 )\r
385{\r
1436aea4 386 UINT32 Offset;\r
a41b5272 387\r
388 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
389 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
390\r
5e90aa1e 391 return EFI_SUCCESS;\r
a41b5272 392}\r
393\r
394/**\r
395 Disable the FIS running for giving port.\r
396\r
397 @param PciIo The PCI IO protocol instance.\r
398 @param Port The number of port.\r
8536cc4b 399 @param Timeout The timeout value of disabling FIS, uses 100ns as a unit.\r
a41b5272 400\r
401 @retval EFI_DEVICE_ERROR The FIS disable setting fails.\r
402 @retval EFI_TIMEOUT The FIS disable setting is time out.\r
403 @retval EFI_UNSUPPORTED The port is in running state.\r
404 @retval EFI_SUCCESS The FIS disable successfully.\r
405\r
406**/\r
407EFI_STATUS\r
408EFIAPI\r
409AhciDisableFisReceive (\r
1436aea4
MK
410 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
411 IN UINT8 Port,\r
412 IN UINT64 Timeout\r
1aff716a 413 )\r
a41b5272 414{\r
1436aea4
MK
415 UINT32 Offset;\r
416 UINT32 Data;\r
a41b5272 417\r
418 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
419 Data = AhciReadReg (PciIo, Offset);\r
420\r
421 //\r
422 // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.\r
423 //\r
424 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {\r
425 return EFI_UNSUPPORTED;\r
426 }\r
1aff716a 427\r
a41b5272 428 //\r
429 // Check if the Fis receive DMA engine for the port is running.\r
430 //\r
431 if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {\r
432 return EFI_SUCCESS;\r
433 }\r
434\r
1436aea4 435 AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_FRE));\r
a41b5272 436\r
8536cc4b 437 return AhciWaitMmioSet (\r
490b5ea1 438 PciIo,\r
a41b5272 439 Offset,\r
440 EFI_AHCI_PORT_CMD_FR,\r
441 0,\r
442 Timeout\r
490b5ea1 443 );\r
a41b5272 444}\r
445\r
a41b5272 446/**\r
447 Build the command list, command table and prepare the fis receiver.\r
1aff716a 448\r
aca84419 449 @param PciIo The PCI IO protocol instance.\r
a41b5272 450 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
aca84419 451 @param Port The number of port.\r
452 @param PortMultiplier The timeout value of stop.\r
453 @param CommandFis The control fis will be used for the transfer.\r
454 @param CommandList The command list will be used for the transfer.\r
455 @param AtapiCommand The atapi command will be used for the transfer.\r
456 @param AtapiCommandLength The length of the atapi command.\r
457 @param CommandSlotNumber The command slot will be used for the transfer.\r
a41b5272 458 @param DataPhysicalAddr The pointer to the data buffer pci bus master address.\r
459 @param DataLength The data count to be transferred.\r
460\r
1aff716a 461**/\r
a41b5272 462VOID\r
463EFIAPI\r
464AhciBuildCommand (\r
1436aea4
MK
465 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
466 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
467 IN UINT8 Port,\r
468 IN UINT8 PortMultiplier,\r
469 IN EFI_AHCI_COMMAND_FIS *CommandFis,\r
470 IN EFI_AHCI_COMMAND_LIST *CommandList,\r
471 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
472 IN UINT8 AtapiCommandLength,\r
473 IN UINT8 CommandSlotNumber,\r
474 IN OUT VOID *DataPhysicalAddr,\r
475 IN UINT32 DataLength\r
1aff716a 476 )\r
a41b5272 477{\r
1436aea4
MK
478 UINT64 BaseAddr;\r
479 UINT32 PrdtNumber;\r
480 UINT32 PrdtIndex;\r
481 UINTN RemainedData;\r
482 UINTN MemAddr;\r
483 DATA_64 Data64;\r
484 UINT32 Offset;\r
a41b5272 485\r
486 //\r
487 // Filling the PRDT\r
1aff716a 488 //\r
f1bc233a 489 PrdtNumber = (UINT32)DivU64x32 (((UINT64)DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1), EFI_AHCI_MAX_DATA_PER_PRDT);\r
a41b5272 490\r
491 //\r
492 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.\r
493 // It also limits that the maximum amount of the PRDT entry in the command table\r
494 // is 65535.\r
495 //\r
496 ASSERT (PrdtNumber <= 65535);\r
497\r
1436aea4 498 Data64.Uint64 = (UINTN)(AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
a41b5272 499\r
500 BaseAddr = Data64.Uint64;\r
1aff716a 501\r
1436aea4 502 ZeroMem ((VOID *)((UINTN)BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));\r
1aff716a 503\r
a41b5272 504 ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
505\r
506 CommandFis->AhciCFisPmNum = PortMultiplier;\r
1aff716a 507\r
a41b5272 508 CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
509\r
510 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
511 if (AtapiCommand != NULL) {\r
512 CopyMem (\r
513 &AhciRegisters->AhciCommandTable->AtapiCmd,\r
514 AtapiCommand,\r
515 AtapiCommandLength\r
516 );\r
517\r
518 CommandList->AhciCmdA = 1;\r
519 CommandList->AhciCmdP = 1;\r
a41b5272 520\r
521 AhciOrReg (PciIo, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
522 } else {\r
1436aea4 523 AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
a41b5272 524 }\r
1aff716a 525\r
1436aea4
MK
526 RemainedData = (UINTN)DataLength;\r
527 MemAddr = (UINTN)DataPhysicalAddr;\r
e0e7f80c 528 CommandList->AhciCmdPrdtl = PrdtNumber;\r
1aff716a 529\r
a41b5272 530 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
490b5ea1 531 if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {\r
a41b5272 532 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;\r
533 } else {\r
534 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;\r
535 }\r
536\r
1436aea4 537 Data64.Uint64 = (UINT64)MemAddr;\r
a41b5272 538 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba = Data64.Uint32.Lower32;\r
539 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;\r
1436aea4
MK
540 RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;\r
541 MemAddr += EFI_AHCI_MAX_DATA_PER_PRDT;\r
a41b5272 542 }\r
543\r
544 //\r
545 // Set the last PRDT to Interrupt On Complete\r
546 //\r
547 if (PrdtNumber > 0) {\r
548 AhciRegisters->AhciCommandTable->PrdtTable[PrdtNumber - 1].AhciPrdtIoc = 1;\r
549 }\r
550\r
551 CopyMem (\r
1436aea4 552 (VOID *)((UINTN)AhciRegisters->AhciCmdList + (UINTN)CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),\r
a41b5272 553 CommandList,\r
554 sizeof (EFI_AHCI_COMMAND_LIST)\r
1aff716a 555 );\r
a41b5272 556\r
1436aea4 557 Data64.Uint64 = (UINT64)(UINTN)AhciRegisters->AhciCommandTablePciAddr;\r
a41b5272 558 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;\r
559 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;\r
560 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;\r
a41b5272 561}\r
562\r
563/**\r
8c39253d 564 Build a command FIS.\r
1aff716a 565\r
aca84419 566 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.\r
a41b5272 567 @param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.\r
568\r
569**/\r
570VOID\r
571EFIAPI\r
572AhciBuildCommandFis (\r
1436aea4
MK
573 IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,\r
574 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock\r
a41b5272 575 )\r
576{\r
577 ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
578\r
579 CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;\r
580 //\r
581 // Indicator it's a command\r
582 //\r
1436aea4
MK
583 CmdFis->AhciCFisCmdInd = 0x1;\r
584 CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;\r
a41b5272 585\r
1436aea4
MK
586 CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;\r
587 CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;\r
a41b5272 588\r
1436aea4
MK
589 CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;\r
590 CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;\r
a41b5272 591\r
1436aea4
MK
592 CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;\r
593 CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;\r
a41b5272 594\r
1436aea4
MK
595 CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;\r
596 CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;\r
a41b5272 597\r
598 CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;\r
599 CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;\r
600\r
1436aea4 601 CmdFis->AhciCFisDevHead = (UINT8)(AtaCommandBlock->AtaDeviceHead | 0xE0);\r
a41b5272 602}\r
603\r
b465a811
AM
604/**\r
605 Wait until SATA device reports it is ready for operation.\r
606\r
607 @param[in] PciIo Pointer to AHCI controller PciIo.\r
608 @param[in] Port SATA port index on which to reset.\r
609\r
610 @retval EFI_SUCCESS Device ready for operation.\r
611 @retval EFI_TIMEOUT Device failed to get ready within required period.\r
612**/\r
613EFI_STATUS\r
614AhciWaitDeviceReady (\r
615 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
616 IN UINT8 Port\r
1436aea4 617 )\r
b465a811 618{\r
1436aea4
MK
619 UINT32 PhyDetectDelay;\r
620 UINT32 Data;\r
621 UINT32 Offset;\r
b465a811
AM
622\r
623 //\r
624 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ\r
625 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.\r
626 //\r
627 PhyDetectDelay = 16 * 1000;\r
628 do {\r
629 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
1436aea4
MK
630 if (AhciReadReg (PciIo, Offset) != 0) {\r
631 AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
b465a811 632 }\r
1436aea4 633\r
b465a811
AM
634 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
635\r
636 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;\r
637 if (Data == 0) {\r
638 break;\r
639 }\r
640\r
641 MicroSecondDelay (1000);\r
642 PhyDetectDelay--;\r
643 } while (PhyDetectDelay > 0);\r
644\r
645 if (PhyDetectDelay == 0) {\r
646 DEBUG ((DEBUG_ERROR, "Port %d Device not ready (TFD=0x%X)\n", Port, Data));\r
647 return EFI_TIMEOUT;\r
648 } else {\r
649 return EFI_SUCCESS;\r
650 }\r
651}\r
652\r
b465a811
AM
653/**\r
654 Reset the SATA port. Algorithm follows AHCI spec 1.3.1 section 10.4.2\r
655\r
656 @param[in] PciIo Pointer to AHCI controller PciIo.\r
657 @param[in] Port SATA port index on which to reset.\r
658\r
659 @retval EFI_SUCCESS Port reset.\r
660 @retval Others Failed to reset the port.\r
661**/\r
662EFI_STATUS\r
663AhciResetPort (\r
664 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
665 IN UINT8 Port\r
666 )\r
667{\r
668 UINT32 Offset;\r
669 EFI_STATUS Status;\r
670\r
671 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
672 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);\r
673 //\r
674 // SW is required to keep DET set to 0x1 at least for 1 milisecond to ensure that\r
675 // at least one COMRESET signal is sent.\r
676 //\r
1436aea4 677 MicroSecondDelay (1000);\r
b465a811
AM
678 AhciAndReg (PciIo, Offset, ~(UINT32)EFI_AHCI_PORT_SSTS_DET_MASK);\r
679\r
680 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
681 Status = AhciWaitMmioSet (PciIo, Offset, EFI_AHCI_PORT_SSTS_DET_MASK, EFI_AHCI_PORT_SSTS_DET_PCE, ATA_ATAPI_TIMEOUT);\r
682 if (EFI_ERROR (Status)) {\r
683 return Status;\r
684 }\r
685\r
686 return AhciWaitDeviceReady (PciIo, Port);\r
687}\r
688\r
689/**\r
690 Recovers the SATA port from error condition.\r
691 This function implements algorithm described in\r
692 AHCI spec 1.3.1 section 6.2.2\r
693\r
694 @param[in] PciIo Pointer to AHCI controller PciIo.\r
695 @param[in] Port SATA port index on which to check.\r
696\r
697 @retval EFI_SUCCESS Port recovered.\r
698 @retval Others Failed to recover port.\r
699**/\r
700EFI_STATUS\r
701AhciRecoverPortError (\r
702 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
703 IN UINT8 Port\r
704 )\r
705{\r
706 UINT32 Offset;\r
707 UINT32 PortInterrupt;\r
708 UINT32 PortTfd;\r
709 EFI_STATUS Status;\r
710\r
1436aea4 711 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
b465a811
AM
712 PortInterrupt = AhciReadReg (PciIo, Offset);\r
713 if ((PortInterrupt & EFI_AHCI_PORT_IS_FATAL_ERROR_MASK) == 0) {\r
714 //\r
715 // No fatal error detected. Exit with success as port should still be operational.\r
716 // No need to clear IS as it will be cleared when the next command starts.\r
717 //\r
718 return EFI_SUCCESS;\r
719 }\r
720\r
721 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
722 AhciAndReg (PciIo, Offset, ~(UINT32)EFI_AHCI_PORT_CMD_ST);\r
723\r
724 Status = AhciWaitMmioSet (PciIo, Offset, EFI_AHCI_PORT_CMD_CR, 0, ATA_ATAPI_TIMEOUT);\r
725 if (EFI_ERROR (Status)) {\r
726 DEBUG ((DEBUG_ERROR, "Ahci port %d is in hung state, aborting recovery\n", Port));\r
727 return Status;\r
728 }\r
729\r
730 //\r
731 // If TFD.BSY or TFD.DRQ is still set it means that drive is hung and software has\r
732 // to reset it before sending any additional commands.\r
733 //\r
1436aea4 734 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
b465a811
AM
735 PortTfd = AhciReadReg (PciIo, Offset);\r
736 if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
737 Status = AhciResetPort (PciIo, Port);\r
738 if (EFI_ERROR (Status)) {\r
739 DEBUG ((DEBUG_ERROR, "Failed to reset the port %d\n", Port));\r
740 }\r
741 }\r
742\r
743 return EFI_SUCCESS;\r
744}\r
745\r
cc28ab7a
AM
746/**\r
747 Checks if specified FIS has been received.\r
748\r
749 @param[in] PciIo Pointer to AHCI controller PciIo.\r
750 @param[in] Port SATA port index on which to check.\r
751 @param[in] FisType FIS type for which to check.\r
752\r
753 @retval EFI_SUCCESS FIS received.\r
754 @retval EFI_NOT_READY FIS not received yet.\r
755 @retval EFI_DEVICE_ERROR AHCI controller reported an error on port.\r
756**/\r
757EFI_STATUS\r
758AhciCheckFisReceived (\r
759 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
760 IN UINT8 Port,\r
761 IN SATA_FIS_TYPE FisType\r
762 )\r
763{\r
1436aea4
MK
764 UINT32 Offset;\r
765 UINT32 PortInterrupt;\r
766 UINT32 PortTfd;\r
cc28ab7a 767\r
1436aea4 768 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
cc28ab7a
AM
769 PortInterrupt = AhciReadReg (PciIo, Offset);\r
770 if ((PortInterrupt & EFI_AHCI_PORT_IS_ERROR_MASK) != 0) {\r
771 DEBUG ((DEBUG_ERROR, "AHCI: Error interrupt reported PxIS: %X\n", PortInterrupt));\r
772 return EFI_DEVICE_ERROR;\r
773 }\r
1436aea4 774\r
cc28ab7a
AM
775 //\r
776 // For PIO setup FIS - According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.\r
777 // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device\r
778 // after the transaction is finished successfully.\r
779 // To get better device compatibilities, we further check if the PxTFD's ERR bit is set.\r
780 // By this way, we can know if there is a real error happened.\r
781 //\r
782 if (((FisType == SataFisD2H) && ((PortInterrupt & EFI_AHCI_PORT_IS_DHRS) != 0)) ||\r
1436aea4
MK
783 ((FisType == SataFisPioSetup) && ((PortInterrupt & (EFI_AHCI_PORT_IS_PSS | EFI_AHCI_PORT_IS_DHRS)) != 0)) ||\r
784 ((FisType == SataFisDmaSetup) && ((PortInterrupt & (EFI_AHCI_PORT_IS_DSS | EFI_AHCI_PORT_IS_DHRS)) != 0)))\r
785 {\r
786 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
787 PortTfd = AhciReadReg (PciIo, (UINT32)Offset);\r
cc28ab7a
AM
788 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
789 return EFI_DEVICE_ERROR;\r
790 } else {\r
791 return EFI_SUCCESS;\r
792 }\r
793 }\r
794\r
795 return EFI_NOT_READY;\r
796}\r
797\r
798/**\r
799 Waits until specified FIS has been received.\r
800\r
801 @param[in] PciIo Pointer to AHCI controller PciIo.\r
802 @param[in] Port SATA port index on which to check.\r
803 @param[in] Timeout Time after which function should stop polling.\r
804 @param[in] FisType FIS type for which to check.\r
805\r
806 @retval EFI_SUCCESS FIS received.\r
807 @retval EFI_TIMEOUT FIS failed to arrive within a specified time period.\r
808 @retval EFI_DEVICE_ERROR AHCI controller reported an error on port.\r
809**/\r
810EFI_STATUS\r
811AhciWaitUntilFisReceived (\r
812 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
813 IN UINT8 Port,\r
814 IN UINT64 Timeout,\r
815 IN SATA_FIS_TYPE FisType\r
816 )\r
817{\r
818 EFI_STATUS Status;\r
819 BOOLEAN InfiniteWait;\r
820 UINT64 Delay;\r
821\r
822 Delay = DivU64x32 (Timeout, 1000) + 1;\r
823 if (Timeout == 0) {\r
824 InfiniteWait = TRUE;\r
825 } else {\r
826 InfiniteWait = FALSE;\r
827 }\r
828\r
829 do {\r
830 Status = AhciCheckFisReceived (PciIo, Port, FisType);\r
831 if (Status != EFI_NOT_READY) {\r
832 return Status;\r
833 }\r
1436aea4 834\r
cc28ab7a
AM
835 //\r
836 // Stall for 100 microseconds.\r
837 //\r
838 MicroSecondDelay (100);\r
839 Delay--;\r
840 } while (InfiniteWait || (Delay > 0));\r
841\r
842 return EFI_TIMEOUT;\r
843}\r
844\r
91d95113
AM
845/**\r
846 Prints contents of the ATA command block into the debug port.\r
847\r
848 @param[in] AtaCommandBlock AtaCommandBlock to print.\r
849 @param[in] DebugLevel Debug level on which to print.\r
850**/\r
851VOID\r
852AhciPrintCommandBlock (\r
853 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
854 IN UINT32 DebugLevel\r
855 )\r
856{\r
857 DEBUG ((DebugLevel, "ATA COMMAND BLOCK:\n"));\r
858 DEBUG ((DebugLevel, "AtaCommand: %d\n", AtaCommandBlock->AtaCommand));\r
859 DEBUG ((DebugLevel, "AtaFeatures: %X\n", AtaCommandBlock->AtaFeatures));\r
860 DEBUG ((DebugLevel, "AtaSectorNumber: %d\n", AtaCommandBlock->AtaSectorNumber));\r
861 DEBUG ((DebugLevel, "AtaCylinderLow: %X\n", AtaCommandBlock->AtaCylinderHigh));\r
862 DEBUG ((DebugLevel, "AtaCylinderHigh: %X\n", AtaCommandBlock->AtaCylinderHigh));\r
863 DEBUG ((DebugLevel, "AtaDeviceHead: %d\n", AtaCommandBlock->AtaDeviceHead));\r
864 DEBUG ((DebugLevel, "AtaSectorNumberExp: %d\n", AtaCommandBlock->AtaSectorNumberExp));\r
865 DEBUG ((DebugLevel, "AtaCylinderLowExp: %X\n", AtaCommandBlock->AtaCylinderLowExp));\r
866 DEBUG ((DebugLevel, "AtaCylinderHighExp: %X\n", AtaCommandBlock->AtaCylinderHighExp));\r
867 DEBUG ((DebugLevel, "AtaFeaturesExp: %X\n", AtaCommandBlock->AtaFeaturesExp));\r
868 DEBUG ((DebugLevel, "AtaSectorCount: %d\n", AtaCommandBlock->AtaSectorCount));\r
869 DEBUG ((DebugLevel, "AtaSectorCountExp: %d\n", AtaCommandBlock->AtaSectorCountExp));\r
870}\r
871\r
872/**\r
873 Prints contents of the ATA status block into the debug port.\r
874\r
875 @param[in] AtaStatusBlock AtaStatusBlock to print.\r
876 @param[in] DebugLevel Debug level on which to print.\r
877**/\r
878VOID\r
879AhciPrintStatusBlock (\r
880 IN EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
881 IN UINT32 DebugLevel\r
882 )\r
883{\r
4c7ce0d2
LG
884 //\r
885 // Skip NULL pointer\r
886 //\r
887 if (AtaStatusBlock == NULL) {\r
888 return;\r
889 }\r
890\r
91d95113
AM
891 //\r
892 // Only print status and error since we have all of the rest printed as\r
893 // a part of command block print.\r
894 //\r
895 DEBUG ((DebugLevel, "ATA STATUS BLOCK:\n"));\r
896 DEBUG ((DebugLevel, "AtaStatus: %d\n", AtaStatusBlock->AtaStatus));\r
897 DEBUG ((DebugLevel, "AtaError: %d\n", AtaStatusBlock->AtaError));\r
898}\r
899\r
a41b5272 900/**\r
901 Start a PIO data transfer on specific port.\r
1aff716a 902\r
490b5ea1 903 @param[in] PciIo The PCI IO protocol instance.\r
904 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
905 @param[in] Port The number of port.\r
906 @param[in] PortMultiplier The timeout value of stop.\r
907 @param[in] AtapiCommand The atapi command will be used for the\r
908 transfer.\r
909 @param[in] AtapiCommandLength The length of the atapi command.\r
910 @param[in] Read The transfer direction.\r
911 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
912 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
913 @param[in, out] MemoryAddr The pointer to the data buffer.\r
914 @param[in] DataCount The data count to be transferred.\r
8536cc4b 915 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 916 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
917 used by non-blocking mode.\r
a41b5272 918\r
919 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.\r
920 @retval EFI_TIMEOUT The operation is time out.\r
921 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
922 @retval EFI_SUCCESS The PIO data transfer executes successfully.\r
923\r
924**/\r
925EFI_STATUS\r
aca84419 926EFIAPI\r
a41b5272 927AhciPioTransfer (\r
1436aea4
MK
928 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
929 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
930 IN UINT8 Port,\r
931 IN UINT8 PortMultiplier,\r
932 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
933 IN UINT8 AtapiCommandLength,\r
934 IN BOOLEAN Read,\r
935 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
936 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
937 IN OUT VOID *MemoryAddr,\r
938 IN UINT32 DataCount,\r
939 IN UINT64 Timeout,\r
940 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 941 )\r
942{\r
1436aea4
MK
943 EFI_STATUS Status;\r
944 EFI_PHYSICAL_ADDRESS PhyAddr;\r
945 VOID *Map;\r
946 UINTN MapLength;\r
947 EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
948 EFI_AHCI_COMMAND_FIS CFis;\r
949 EFI_AHCI_COMMAND_LIST CmdList;\r
950 UINT32 PrdCount;\r
951 UINT32 Retry;\r
a6542894 952 EFI_STATUS RecoveryStatus;\r
a41b5272 953\r
954 if (Read) {\r
955 Flag = EfiPciIoOperationBusMasterWrite;\r
956 } else {\r
957 Flag = EfiPciIoOperationBusMasterRead;\r
958 }\r
959\r
960 //\r
961 // construct command list and command table with pci bus address\r
962 //\r
963 MapLength = DataCount;\r
1436aea4
MK
964 Status = PciIo->Map (\r
965 PciIo,\r
966 Flag,\r
967 MemoryAddr,\r
968 &MapLength,\r
969 &PhyAddr,\r
970 &Map\r
971 );\r
a41b5272 972\r
973 if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
9e70c18b 974 return EFI_BAD_BUFFER_SIZE;\r
a41b5272 975 }\r
1aff716a 976\r
a41b5272 977 //\r
978 // Package read needed\r
979 //\r
980 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
981\r
982 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
983\r
984 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
985 CmdList.AhciCmdW = Read ? 0 : 1;\r
986\r
64e25d4b
AM
987 for (Retry = 0; Retry < AHCI_COMMAND_RETRIES; Retry++) {\r
988 AhciBuildCommand (\r
989 PciIo,\r
990 AhciRegisters,\r
991 Port,\r
992 PortMultiplier,\r
993 &CFis,\r
994 &CmdList,\r
995 AtapiCommand,\r
996 AtapiCommandLength,\r
997 0,\r
998 (VOID *)(UINTN)PhyAddr,\r
999 DataCount\r
1000 );\r
1aff716a 1001\r
91d95113
AM
1002 DEBUG ((DEBUG_VERBOSE, "Starting command for PIO transfer:\n"));\r
1003 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_VERBOSE);\r
64e25d4b 1004 Status = AhciStartCommand (\r
1436aea4
MK
1005 PciIo,\r
1006 Port,\r
1007 0,\r
1008 Timeout\r
1009 );\r
64e25d4b
AM
1010 if (EFI_ERROR (Status)) {\r
1011 break;\r
1012 }\r
490b5ea1 1013\r
64e25d4b
AM
1014 if (Read && (AtapiCommand == 0)) {\r
1015 Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisPioSetup);\r
1016 if (Status == EFI_SUCCESS) {\r
1436aea4 1017 PrdCount = *(volatile UINT32 *)(&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
64e25d4b
AM
1018 if (PrdCount == DataCount) {\r
1019 Status = EFI_SUCCESS;\r
1020 } else {\r
1021 Status = EFI_DEVICE_ERROR;\r
1022 }\r
43654b1c 1023 }\r
64e25d4b
AM
1024 } else {\r
1025 Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);\r
8536cc4b 1026 }\r
a41b5272 1027\r
64e25d4b
AM
1028 if (Status == EFI_DEVICE_ERROR) {\r
1029 DEBUG ((DEBUG_ERROR, "PIO command failed at retry %d\n", Retry));\r
a6542894
AM
1030 RecoveryStatus = AhciRecoverPortError (PciIo, Port);\r
1031 if (EFI_ERROR (RecoveryStatus)) {\r
64e25d4b
AM
1032 break;\r
1033 }\r
1034 } else {\r
1035 break;\r
1036 }\r
b465a811
AM
1037 }\r
1038\r
a41b5272 1039 AhciStopCommand (\r
490b5ea1 1040 PciIo,\r
a41b5272 1041 Port,\r
1042 Timeout\r
1043 );\r
1aff716a 1044\r
a41b5272 1045 AhciDisableFisReceive (\r
490b5ea1 1046 PciIo,\r
a41b5272 1047 Port,\r
1048 Timeout\r
1049 );\r
1050\r
1051 PciIo->Unmap (\r
1436aea4
MK
1052 PciIo,\r
1053 Map\r
1054 );\r
a41b5272 1055\r
a7b3f90f 1056 AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
91d95113
AM
1057\r
1058 if (Status == EFI_DEVICE_ERROR) {\r
1059 DEBUG ((DEBUG_ERROR, "Failed to execute command for PIO transfer:\n"));\r
1060 //\r
1061 // Repeat command block here to make sure it is printed on\r
1062 // device error debug level.\r
1063 //\r
1064 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_ERROR);\r
1065 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_ERROR);\r
1066 } else {\r
1067 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_VERBOSE);\r
1068 }\r
1069\r
a41b5272 1070 return Status;\r
1071}\r
1072\r
1073/**\r
1074 Start a DMA data transfer on specific port\r
1075\r
490b5ea1 1076 @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.\r
1077 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1078 @param[in] Port The number of port.\r
1079 @param[in] PortMultiplier The timeout value of stop.\r
1080 @param[in] AtapiCommand The atapi command will be used for the\r
1081 transfer.\r
1082 @param[in] AtapiCommandLength The length of the atapi command.\r
1083 @param[in] Read The transfer direction.\r
1084 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
1085 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
1086 @param[in, out] MemoryAddr The pointer to the data buffer.\r
1087 @param[in] DataCount The data count to be transferred.\r
8536cc4b 1088 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 1089 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1090 used by non-blocking mode.\r
aca84419 1091\r
1092 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.\r
1093 @retval EFI_TIMEOUT The operation is time out.\r
1094 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
1095 @retval EFI_SUCCESS The DMA data transfer executes successfully.\r
490b5ea1 1096\r
a41b5272 1097**/\r
1098EFI_STATUS\r
1099EFIAPI\r
1100AhciDmaTransfer (\r
1436aea4
MK
1101 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
1102 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1103 IN UINT8 Port,\r
1104 IN UINT8 PortMultiplier,\r
1105 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
1106 IN UINT8 AtapiCommandLength,\r
1107 IN BOOLEAN Read,\r
1108 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
1109 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
1110 IN OUT VOID *MemoryAddr,\r
1111 IN UINT32 DataCount,\r
1112 IN UINT64 Timeout,\r
1113 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 1114 )\r
1115{\r
1436aea4
MK
1116 EFI_STATUS Status;\r
1117 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1118 VOID *Map;\r
1119 UINTN MapLength;\r
1120 EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
1121 EFI_AHCI_COMMAND_FIS CFis;\r
1122 EFI_AHCI_COMMAND_LIST CmdList;\r
1123 EFI_PCI_IO_PROTOCOL *PciIo;\r
1124 EFI_TPL OldTpl;\r
1125 UINT32 Retry;\r
a6542894 1126 EFI_STATUS RecoveryStatus;\r
a41b5272 1127\r
490b5ea1 1128 Map = NULL;\r
1129 PciIo = Instance->PciIo;\r
a41b5272 1130\r
490b5ea1 1131 if (PciIo == NULL) {\r
1132 return EFI_INVALID_PARAMETER;\r
a41b5272 1133 }\r
1134\r
aa759653
LG
1135 //\r
1136 // Set Status to suppress incorrect compiler/analyzer warnings\r
1137 //\r
1138 Status = EFI_SUCCESS;\r
1139\r
a41b5272 1140 //\r
64e25d4b
AM
1141 // DMA buffer allocation. Needs to be done only once for both sync and async\r
1142 // DMA transfers irrespective of number of retries.\r
a41b5272 1143 //\r
64e25d4b 1144 if ((Task == NULL) || ((Task != NULL) && (Task->Map == NULL))) {\r
490b5ea1 1145 if (Read) {\r
1146 Flag = EfiPciIoOperationBusMasterWrite;\r
1147 } else {\r
1148 Flag = EfiPciIoOperationBusMasterRead;\r
1149 }\r
a41b5272 1150\r
490b5ea1 1151 MapLength = DataCount;\r
1436aea4
MK
1152 Status = PciIo->Map (\r
1153 PciIo,\r
1154 Flag,\r
1155 MemoryAddr,\r
1156 &MapLength,\r
1157 &PhyAddr,\r
1158 &Map\r
1159 );\r
490b5ea1 1160\r
1161 if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
9e70c18b 1162 return EFI_BAD_BUFFER_SIZE;\r
490b5ea1 1163 }\r
1436aea4 1164\r
490b5ea1 1165 if (Task != NULL) {\r
1166 Task->Map = Map;\r
1167 }\r
64e25d4b
AM
1168 }\r
1169\r
1436aea4 1170 if ((Task == NULL) || ((Task != NULL) && !Task->IsStart)) {\r
490b5ea1 1171 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
1172\r
1173 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
1174\r
1175 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
1176 CmdList.AhciCmdW = Read ? 0 : 1;\r
a41b5272 1177 }\r
1178\r
64e25d4b
AM
1179 if (Task == NULL) {\r
1180 //\r
1181 // Before starting the Blocking BlockIO operation, push to finish all non-blocking\r
1182 // BlockIO tasks.\r
1183 // Delay 100us to simulate the blocking time out checking.\r
1184 //\r
1185 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1186 while (!IsListEmpty (&Instance->NonBlockingTaskList)) {\r
1187 AsyncNonBlockingTransferRoutine (NULL, Instance);\r
1188 //\r
1189 // Stall for 100us.\r
1190 //\r
1191 MicroSecondDelay (100);\r
1192 }\r
1436aea4 1193\r
64e25d4b
AM
1194 gBS->RestoreTPL (OldTpl);\r
1195 for (Retry = 0; Retry < AHCI_COMMAND_RETRIES; Retry++) {\r
1196 AhciBuildCommand (\r
1197 PciIo,\r
1198 AhciRegisters,\r
1199 Port,\r
1200 PortMultiplier,\r
1201 &CFis,\r
1202 &CmdList,\r
1203 AtapiCommand,\r
1204 AtapiCommandLength,\r
1205 0,\r
1206 (VOID *)(UINTN)PhyAddr,\r
1207 DataCount\r
1208 );\r
1209\r
91d95113
AM
1210 DEBUG ((DEBUG_VERBOSE, "Starting command for sync DMA transfer:\n"));\r
1211 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_VERBOSE);\r
64e25d4b 1212 Status = AhciStartCommand (\r
1436aea4
MK
1213 PciIo,\r
1214 Port,\r
1215 0,\r
1216 Timeout\r
1217 );\r
64e25d4b
AM
1218 if (EFI_ERROR (Status)) {\r
1219 break;\r
1220 }\r
1436aea4 1221\r
64e25d4b
AM
1222 Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);\r
1223 if (Status == EFI_DEVICE_ERROR) {\r
1224 DEBUG ((DEBUG_ERROR, "DMA command failed at retry: %d\n", Retry));\r
a6542894
AM
1225 RecoveryStatus = AhciRecoverPortError (PciIo, Port);\r
1226 if (EFI_ERROR (RecoveryStatus)) {\r
64e25d4b
AM
1227 break;\r
1228 }\r
cc28ab7a 1229 } else {\r
64e25d4b 1230 break;\r
cc28ab7a
AM
1231 }\r
1232 }\r
490b5ea1 1233 } else {\r
64e25d4b
AM
1234 if (!Task->IsStart) {\r
1235 AhciBuildCommand (\r
1236 PciIo,\r
1237 AhciRegisters,\r
1238 Port,\r
1239 PortMultiplier,\r
1240 &CFis,\r
1241 &CmdList,\r
1242 AtapiCommand,\r
1243 AtapiCommandLength,\r
1244 0,\r
1245 (VOID *)(UINTN)PhyAddr,\r
1246 DataCount\r
1247 );\r
1248\r
91d95113
AM
1249 DEBUG ((DEBUG_VERBOSE, "Starting command for async DMA transfer:\n"));\r
1250 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_VERBOSE);\r
64e25d4b 1251 Status = AhciStartCommand (\r
1436aea4
MK
1252 PciIo,\r
1253 Port,\r
1254 0,\r
1255 Timeout\r
1256 );\r
64e25d4b
AM
1257 if (!EFI_ERROR (Status)) {\r
1258 Task->IsStart = TRUE;\r
1259 }\r
1260 }\r
1436aea4 1261\r
64e25d4b
AM
1262 if (Task->IsStart) {\r
1263 Status = AhciCheckFisReceived (PciIo, Port, SataFisD2H);\r
1264 if (Status == EFI_DEVICE_ERROR) {\r
1265 DEBUG ((DEBUG_ERROR, "DMA command failed at retry: %d\n", Task->RetryTimes));\r
a6542894 1266 RecoveryStatus = AhciRecoverPortError (PciIo, Port);\r
64e25d4b
AM
1267 //\r
1268 // If recovery passed mark the Task as not started and change the status\r
1269 // to EFI_NOT_READY. This will make the higher level call this function again\r
1270 // and on next call the command will be re-issued due to IsStart being FALSE.\r
1271 // This also makes the next condition decrement the RetryTimes.\r
1272 //\r
a6542894 1273 if (RecoveryStatus == EFI_SUCCESS) {\r
64e25d4b 1274 Task->IsStart = FALSE;\r
1436aea4 1275 Status = EFI_NOT_READY;\r
64e25d4b
AM
1276 }\r
1277 }\r
a41b5272 1278\r
64e25d4b 1279 if (Status == EFI_NOT_READY) {\r
1436aea4 1280 if (!Task->InfiniteWait && (Task->RetryTimes == 0)) {\r
64e25d4b
AM
1281 Status = EFI_TIMEOUT;\r
1282 } else {\r
1283 Task->RetryTimes--;\r
1284 }\r
1285 }\r
1286 }\r
b465a811
AM
1287 }\r
1288\r
490b5ea1 1289 //\r
1290 // For Blocking mode, the command should be stopped, the Fis should be disabled\r
1291 // and the PciIo should be unmapped.\r
1aff716a 1292 // For non-blocking mode, only when a error is happened (if the return status is\r
1293 // EFI_NOT_READY that means the command doesn't finished, try again.), first do the\r
490b5ea1 1294 // context cleanup, then set the packet's Asb status.\r
1295 //\r
1436aea4 1296 if ((Task == NULL) ||\r
490b5ea1 1297 ((Task != NULL) && (Status != EFI_NOT_READY))\r
1436aea4
MK
1298 )\r
1299 {\r
490b5ea1 1300 AhciStopCommand (\r
1aff716a 1301 PciIo,\r
490b5ea1 1302 Port,\r
1303 Timeout\r
1304 );\r
a41b5272 1305\r
490b5ea1 1306 AhciDisableFisReceive (\r
1aff716a 1307 PciIo,\r
490b5ea1 1308 Port,\r
1309 Timeout\r
1310 );\r
a41b5272 1311\r
490b5ea1 1312 PciIo->Unmap (\r
1313 PciIo,\r
1314 (Task != NULL) ? Task->Map : Map\r
1315 );\r
e519983a 1316\r
490b5ea1 1317 if (Task != NULL) {\r
1318 Task->Packet->Asb->AtaStatus = 0x01;\r
1319 }\r
1320 }\r
1321\r
a7b3f90f 1322 AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
91d95113
AM
1323\r
1324 if (Status == EFI_DEVICE_ERROR) {\r
1325 DEBUG ((DEBUG_ERROR, "Failed to execute command for DMA transfer:\n"));\r
1326 //\r
1327 // Repeat command block here to make sure it is printed on\r
1328 // device error debug level.\r
1329 //\r
1330 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_ERROR);\r
1331 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_ERROR);\r
1332 } else {\r
1333 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_VERBOSE);\r
1334 }\r
1335\r
a41b5272 1336 return Status;\r
1337}\r
1338\r
1339/**\r
1340 Start a non data transfer on specific port.\r
1aff716a 1341\r
490b5ea1 1342 @param[in] PciIo The PCI IO protocol instance.\r
1343 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1344 @param[in] Port The number of port.\r
1345 @param[in] PortMultiplier The timeout value of stop.\r
1346 @param[in] AtapiCommand The atapi command will be used for the\r
1347 transfer.\r
1348 @param[in] AtapiCommandLength The length of the atapi command.\r
1349 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
1350 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
8536cc4b 1351 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 1352 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1353 used by non-blocking mode.\r
a41b5272 1354\r
1355 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.\r
1356 @retval EFI_TIMEOUT The operation is time out.\r
1357 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
1358 @retval EFI_SUCCESS The non data transfer executes successfully.\r
1359\r
1aff716a 1360**/\r
a41b5272 1361EFI_STATUS\r
1362EFIAPI\r
1363AhciNonDataTransfer (\r
1436aea4
MK
1364 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1365 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1366 IN UINT8 Port,\r
1367 IN UINT8 PortMultiplier,\r
1368 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
1369 IN UINT8 AtapiCommandLength,\r
1370 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
1371 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
1372 IN UINT64 Timeout,\r
1373 IN ATA_NONBLOCK_TASK *Task\r
490b5ea1 1374 )\r
a41b5272 1375{\r
1436aea4
MK
1376 EFI_STATUS Status;\r
1377 EFI_AHCI_COMMAND_FIS CFis;\r
1378 EFI_AHCI_COMMAND_LIST CmdList;\r
1379 UINT32 Retry;\r
a6542894 1380 EFI_STATUS RecoveryStatus;\r
a41b5272 1381\r
1382 //\r
1383 // Package read needed\r
1384 //\r
1385 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
1386\r
1387 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
1388\r
1389 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
1390\r
64e25d4b
AM
1391 for (Retry = 0; Retry < AHCI_COMMAND_RETRIES; Retry++) {\r
1392 AhciBuildCommand (\r
1393 PciIo,\r
1394 AhciRegisters,\r
1395 Port,\r
1396 PortMultiplier,\r
1397 &CFis,\r
1398 &CmdList,\r
1399 AtapiCommand,\r
1400 AtapiCommandLength,\r
1401 0,\r
1402 NULL,\r
1403 0\r
1404 );\r
490b5ea1 1405\r
91d95113
AM
1406 DEBUG ((DEBUG_VERBOSE, "Starting command for non data transfer:\n"));\r
1407 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_VERBOSE);\r
64e25d4b 1408 Status = AhciStartCommand (\r
1436aea4
MK
1409 PciIo,\r
1410 Port,\r
1411 0,\r
1412 Timeout\r
1413 );\r
64e25d4b
AM
1414 if (EFI_ERROR (Status)) {\r
1415 break;\r
1416 }\r
490b5ea1 1417\r
64e25d4b
AM
1418 Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);\r
1419 if (Status == EFI_DEVICE_ERROR) {\r
1420 DEBUG ((DEBUG_ERROR, "Non data transfer failed at retry %d\n", Retry));\r
a6542894
AM
1421 RecoveryStatus = AhciRecoverPortError (PciIo, Port);\r
1422 if (EFI_ERROR (RecoveryStatus)) {\r
64e25d4b
AM
1423 break;\r
1424 }\r
1425 } else {\r
1426 break;\r
1427 }\r
b465a811 1428 }\r
490b5ea1 1429\r
a41b5272 1430 AhciStopCommand (\r
490b5ea1 1431 PciIo,\r
a41b5272 1432 Port,\r
1433 Timeout\r
1434 );\r
1435\r
1436 AhciDisableFisReceive (\r
490b5ea1 1437 PciIo,\r
a41b5272 1438 Port,\r
1439 Timeout\r
1440 );\r
1441\r
a7b3f90f 1442 AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
e519983a 1443\r
91d95113
AM
1444 if (Status == EFI_DEVICE_ERROR) {\r
1445 DEBUG ((DEBUG_ERROR, "Failed to execute command for non data transfer:\n"));\r
1446 //\r
1447 // Repeat command block here to make sure it is printed on\r
1448 // device error debug level.\r
1449 //\r
1450 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_ERROR);\r
1451 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_ERROR);\r
1452 } else {\r
1453 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_VERBOSE);\r
1454 }\r
1455\r
a41b5272 1456 return Status;\r
1457}\r
1458\r
1459/**\r
1460 Stop command running for giving port\r
1aff716a 1461\r
a41b5272 1462 @param PciIo The PCI IO protocol instance.\r
1463 @param Port The number of port.\r
8536cc4b 1464 @param Timeout The timeout value of stop, uses 100ns as a unit.\r
1aff716a 1465\r
a41b5272 1466 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.\r
1467 @retval EFI_TIMEOUT The operation is time out.\r
1468 @retval EFI_SUCCESS The command stop successfully.\r
1469\r
1470**/\r
1471EFI_STATUS\r
1472EFIAPI\r
1473AhciStopCommand (\r
1436aea4
MK
1474 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1475 IN UINT8 Port,\r
1476 IN UINT64 Timeout\r
a41b5272 1477 )\r
1478{\r
1436aea4
MK
1479 UINT32 Offset;\r
1480 UINT32 Data;\r
a41b5272 1481\r
1482 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1483 Data = AhciReadReg (PciIo, Offset);\r
1484\r
1485 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {\r
490b5ea1 1486 return EFI_SUCCESS;\r
a41b5272 1487 }\r
1488\r
1489 if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
1436aea4 1490 AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_ST));\r
a41b5272 1491 }\r
1492\r
8536cc4b 1493 return AhciWaitMmioSet (\r
490b5ea1 1494 PciIo,\r
a41b5272 1495 Offset,\r
1496 EFI_AHCI_PORT_CMD_CR,\r
1497 0,\r
1498 Timeout\r
490b5ea1 1499 );\r
a41b5272 1500}\r
1501\r
1502/**\r
1503 Start command for give slot on specific port.\r
490b5ea1 1504\r
a41b5272 1505 @param PciIo The PCI IO protocol instance.\r
1506 @param Port The number of port.\r
490b5ea1 1507 @param CommandSlot The number of Command Slot.\r
8536cc4b 1508 @param Timeout The timeout value of start, uses 100ns as a unit.\r
490b5ea1 1509\r
a41b5272 1510 @retval EFI_DEVICE_ERROR The command start unsuccessfully.\r
1511 @retval EFI_TIMEOUT The operation is time out.\r
1512 @retval EFI_SUCCESS The command start successfully.\r
1513\r
1514**/\r
1515EFI_STATUS\r
1516EFIAPI\r
1517AhciStartCommand (\r
1436aea4
MK
1518 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1519 IN UINT8 Port,\r
1520 IN UINT8 CommandSlot,\r
1521 IN UINT64 Timeout\r
a41b5272 1522 )\r
1523{\r
1436aea4
MK
1524 UINT32 CmdSlotBit;\r
1525 EFI_STATUS Status;\r
1526 UINT32 PortStatus;\r
1527 UINT32 StartCmd;\r
1528 UINT32 PortTfd;\r
1529 UINT32 Offset;\r
1530 UINT32 Capability;\r
a41b5272 1531\r
1532 //\r
1533 // Collect AHCI controller information\r
1534 //\r
1436aea4 1535 Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
a41b5272 1536\r
1436aea4 1537 CmdSlotBit = (UINT32)(1 << CommandSlot);\r
a41b5272 1538\r
1539 AhciClearPortStatus (\r
1540 PciIo,\r
1541 Port\r
1542 );\r
1543\r
1544 Status = AhciEnableFisReceive (\r
1aff716a 1545 PciIo,\r
a41b5272 1546 Port,\r
1547 Timeout\r
1548 );\r
490b5ea1 1549\r
a41b5272 1550 if (EFI_ERROR (Status)) {\r
1551 return Status;\r
1552 }\r
1553\r
1436aea4 1554 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
a41b5272 1555 PortStatus = AhciReadReg (PciIo, Offset);\r
490b5ea1 1556\r
a41b5272 1557 StartCmd = 0;\r
1558 if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
1436aea4 1559 StartCmd = AhciReadReg (PciIo, Offset);\r
a41b5272 1560 StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;\r
1561 StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;\r
1562 }\r
1563\r
1436aea4 1564 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
a41b5272 1565 PortTfd = AhciReadReg (PciIo, Offset);\r
1566\r
1567 if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
1568 if ((Capability & BIT24) != 0) {\r
1569 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
cbd2a4b3 1570 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);\r
a41b5272 1571\r
8536cc4b 1572 AhciWaitMmioSet (\r
490b5ea1 1573 PciIo,\r
a41b5272 1574 Offset,\r
cbd2a4b3 1575 EFI_AHCI_PORT_CMD_CLO,\r
a41b5272 1576 0,\r
1577 Timeout\r
490b5ea1 1578 );\r
a41b5272 1579 }\r
1580 }\r
1581\r
1582 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1583 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);\r
1584\r
e519983a 1585 //\r
1586 // Setting the command\r
1587 //\r
e519983a 1588 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
1589 AhciAndReg (PciIo, Offset, 0);\r
1590 AhciOrReg (PciIo, Offset, CmdSlotBit);\r
1591\r
a41b5272 1592 return EFI_SUCCESS;\r
1593}\r
1594\r
a41b5272 1595/**\r
1596 Do AHCI HBA reset.\r
490b5ea1 1597\r
a41b5272 1598 @param PciIo The PCI IO protocol instance.\r
8536cc4b 1599 @param Timeout The timeout value of reset, uses 100ns as a unit.\r
490b5ea1 1600\r
a41b5272 1601 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.\r
1602 @retval EFI_TIMEOUT The reset operation is time out.\r
1603 @retval EFI_SUCCESS AHCI controller is reset successfully.\r
1604\r
1605**/\r
1606EFI_STATUS\r
1607EFIAPI\r
1608AhciReset (\r
1436aea4
MK
1609 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1610 IN UINT64 Timeout\r
1aff716a 1611 )\r
a41b5272 1612{\r
1436aea4
MK
1613 UINT64 Delay;\r
1614 UINT32 Value;\r
a41b5272 1615\r
1ff1dd0f 1616 //\r
6052a15f 1617 // Make sure that GHC.AE bit is set before accessing any AHCI registers.\r
1ff1dd0f 1618 //\r
1436aea4 1619 Value = AhciReadReg (PciIo, EFI_AHCI_GHC_OFFSET);\r
6052a15f
MW
1620\r
1621 if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
1ff1dd0f
FT
1622 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
1623 }\r
a41b5272 1624\r
1625 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
1626\r
1436aea4 1627 Delay = DivU64x32 (Timeout, 1000) + 1;\r
a41b5272 1628\r
1629 do {\r
1436aea4 1630 Value = AhciReadReg (PciIo, EFI_AHCI_GHC_OFFSET);\r
a41b5272 1631\r
1632 if ((Value & EFI_AHCI_GHC_RESET) == 0) {\r
1633 break;\r
1634 }\r
1635\r
1636 //\r
1637 // Stall for 100 microseconds.\r
1638 //\r
1436aea4 1639 MicroSecondDelay (100);\r
a41b5272 1640\r
1641 Delay--;\r
1642 } while (Delay > 0);\r
1643\r
1644 if (Delay == 0) {\r
1645 return EFI_TIMEOUT;\r
1646 }\r
1647\r
1648 return EFI_SUCCESS;\r
1649}\r
1650\r
12873d57 1651/**\r
1652 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
1653\r
1654 @param PciIo The PCI IO protocol instance.\r
1655 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1656 @param Port The number of port.\r
79992d6e 1657 @param PortMultiplier The port multiplier port number.\r
12873d57 1658 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1659\r
1660 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.\r
1661 @retval Others Fail to get return status data.\r
1662\r
1663**/\r
1664EFI_STATUS\r
1665EFIAPI\r
1666AhciAtaSmartReturnStatusCheck (\r
1436aea4
MK
1667 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1668 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1669 IN UINT8 Port,\r
1670 IN UINT8 PortMultiplier,\r
1671 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
12873d57 1672 )\r
1673{\r
1436aea4
MK
1674 EFI_STATUS Status;\r
1675 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1676 UINT8 LBAMid;\r
1677 UINT8 LBAHigh;\r
1678 UINTN FisBaseAddr;\r
1679 UINT32 Value;\r
12873d57 1680\r
1681 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1682\r
1683 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1684 AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;\r
1685 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1686 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1687\r
1688 //\r
1689 // Send S.M.A.R.T Read Return Status command to device\r
1690 //\r
1691 Status = AhciNonDataTransfer (\r
1692 PciIo,\r
1693 AhciRegisters,\r
1694 (UINT8)Port,\r
1695 (UINT8)PortMultiplier,\r
1696 NULL,\r
1697 0,\r
1698 &AtaCommandBlock,\r
1699 AtaStatusBlock,\r
490b5ea1 1700 ATA_ATAPI_TIMEOUT,\r
1701 NULL\r
12873d57 1702 );\r
1703\r
1704 if (EFI_ERROR (Status)) {\r
cffd2171
EL
1705 REPORT_STATUS_CODE (\r
1706 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
1707 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
1708 );\r
12873d57 1709 return EFI_DEVICE_ERROR;\r
1710 }\r
1711\r
cffd2171
EL
1712 REPORT_STATUS_CODE (\r
1713 EFI_PROGRESS_CODE,\r
1714 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
1715 );\r
1716\r
12873d57 1717 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1718\r
1436aea4 1719 Value = *(UINT32 *)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
12873d57 1720\r
1721 if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
1722 LBAMid = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];\r
1723 LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];\r
1724\r
1725 if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
1726 //\r
1727 // The threshold exceeded condition is not detected by the device\r
1728 //\r
87000d77 1729 DEBUG ((DEBUG_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
cffd2171 1730 REPORT_STATUS_CODE (\r
1436aea4
MK
1731 EFI_PROGRESS_CODE,\r
1732 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
1733 );\r
12873d57 1734 } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
1735 //\r
1736 // The threshold exceeded condition is detected by the device\r
1737 //\r
87000d77 1738 DEBUG ((DEBUG_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
cffd2171 1739 REPORT_STATUS_CODE (\r
1436aea4
MK
1740 EFI_PROGRESS_CODE,\r
1741 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
1742 );\r
12873d57 1743 }\r
1744 }\r
1745\r
1746 return EFI_SUCCESS;\r
1747}\r
1748\r
1749/**\r
1750 Enable SMART command of the disk if supported.\r
1751\r
1752 @param PciIo The PCI IO protocol instance.\r
1753 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1754 @param Port The number of port.\r
79992d6e 1755 @param PortMultiplier The port multiplier port number.\r
12873d57 1756 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
1757 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1758\r
1759**/\r
1760VOID\r
1761EFIAPI\r
1762AhciAtaSmartSupport (\r
1436aea4
MK
1763 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1764 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1765 IN UINT8 Port,\r
1766 IN UINT8 PortMultiplier,\r
1767 IN EFI_IDENTIFY_DATA *IdentifyData,\r
1768 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
12873d57 1769 )\r
1770{\r
1436aea4
MK
1771 EFI_STATUS Status;\r
1772 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
12873d57 1773\r
1774 //\r
1775 // Detect if the device supports S.M.A.R.T.\r
1776 //\r
1777 if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
1778 //\r
1779 // S.M.A.R.T is not supported by the device\r
1780 //\r
1436aea4
MK
1781 DEBUG ((\r
1782 DEBUG_INFO,\r
1783 "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",\r
1784 Port,\r
1785 PortMultiplier\r
1786 ));\r
cffd2171
EL
1787 REPORT_STATUS_CODE (\r
1788 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
1789 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
1790 );\r
12873d57 1791 } else {\r
1792 //\r
1793 // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
1794 //\r
1795 if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
cffd2171
EL
1796 REPORT_STATUS_CODE (\r
1797 EFI_PROGRESS_CODE,\r
1798 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)\r
1799 );\r
1800\r
12873d57 1801 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1802\r
1803 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1804 AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;\r
1805 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1806 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1807\r
1808 //\r
1809 // Send S.M.A.R.T Enable command to device\r
1810 //\r
1811 Status = AhciNonDataTransfer (\r
1812 PciIo,\r
1813 AhciRegisters,\r
1814 (UINT8)Port,\r
1815 (UINT8)PortMultiplier,\r
1816 NULL,\r
1817 0,\r
1818 &AtaCommandBlock,\r
1819 AtaStatusBlock,\r
490b5ea1 1820 ATA_ATAPI_TIMEOUT,\r
1821 NULL\r
12873d57 1822 );\r
1823\r
12873d57 1824 if (!EFI_ERROR (Status)) {\r
1825 //\r
1826 // Send S.M.A.R.T AutoSave command to device\r
1827 //\r
1828 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1829\r
1830 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1831 AtaCommandBlock.AtaFeatures = 0xD2;\r
1832 AtaCommandBlock.AtaSectorCount = 0xF1;\r
1833 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1834 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1835\r
1836 Status = AhciNonDataTransfer (\r
1837 PciIo,\r
1838 AhciRegisters,\r
1839 (UINT8)Port,\r
1840 (UINT8)PortMultiplier,\r
1841 NULL,\r
1842 0,\r
1843 &AtaCommandBlock,\r
1844 AtaStatusBlock,\r
490b5ea1 1845 ATA_ATAPI_TIMEOUT,\r
1846 NULL\r
12873d57 1847 );\r
12873d57 1848 }\r
1849 }\r
c9742578
LG
1850\r
1851 AhciAtaSmartReturnStatusCheck (\r
1852 PciIo,\r
1853 AhciRegisters,\r
1854 (UINT8)Port,\r
1855 (UINT8)PortMultiplier,\r
1856 AtaStatusBlock\r
1857 );\r
1858\r
1436aea4
MK
1859 DEBUG ((\r
1860 DEBUG_INFO,\r
1861 "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",\r
1862 Port,\r
1863 PortMultiplier\r
1864 ));\r
12873d57 1865 }\r
1866\r
1436aea4 1867 return;\r
12873d57 1868}\r
1869\r
a41b5272 1870/**\r
1871 Send Buffer cmd to specific device.\r
1aff716a 1872\r
aca84419 1873 @param PciIo The PCI IO protocol instance.\r
1874 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1875 @param Port The number of port.\r
79992d6e 1876 @param PortMultiplier The port multiplier port number.\r
aca84419 1877 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1878\r
1879 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1880 @retval EFI_TIMEOUT The operation is time out.\r
1881 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1882 @retval EFI_SUCCESS The cmd executes successfully.\r
1883\r
1884**/\r
1885EFI_STATUS\r
1886EFIAPI\r
1887AhciIdentify (\r
1436aea4
MK
1888 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1889 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1890 IN UINT8 Port,\r
1891 IN UINT8 PortMultiplier,\r
1892 IN OUT EFI_IDENTIFY_DATA *Buffer\r
a41b5272 1893 )\r
1894{\r
1436aea4
MK
1895 EFI_STATUS Status;\r
1896 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1897 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
a41b5272 1898\r
1436aea4 1899 if ((PciIo == NULL) || (AhciRegisters == NULL) || (Buffer == NULL)) {\r
a41b5272 1900 return EFI_INVALID_PARAMETER;\r
1901 }\r
1902\r
1903 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1904 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 1905\r
a41b5272 1906 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
1907 AtaCommandBlock.AtaSectorCount = 1;\r
1908\r
1909 Status = AhciPioTransfer (\r
1910 PciIo,\r
1911 AhciRegisters,\r
1912 Port,\r
1913 PortMultiplier,\r
1914 NULL,\r
1915 0,\r
1916 TRUE,\r
1917 &AtaCommandBlock,\r
1918 &AtaStatusBlock,\r
1919 Buffer,\r
1920 sizeof (EFI_IDENTIFY_DATA),\r
1aff716a 1921 ATA_ATAPI_TIMEOUT,\r
490b5ea1 1922 NULL\r
a41b5272 1923 );\r
1924\r
1925 return Status;\r
1926}\r
1927\r
1928/**\r
1929 Send Buffer cmd to specific device.\r
1aff716a 1930\r
aca84419 1931 @param PciIo The PCI IO protocol instance.\r
1932 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1933 @param Port The number of port.\r
79992d6e 1934 @param PortMultiplier The port multiplier port number.\r
aca84419 1935 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1936\r
1937 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1938 @retval EFI_TIMEOUT The operation is time out.\r
1939 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1940 @retval EFI_SUCCESS The cmd executes successfully.\r
1941\r
1942**/\r
1943EFI_STATUS\r
1944EFIAPI\r
1945AhciIdentifyPacket (\r
1436aea4
MK
1946 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1947 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1948 IN UINT8 Port,\r
1949 IN UINT8 PortMultiplier,\r
1950 IN OUT EFI_IDENTIFY_DATA *Buffer\r
a41b5272 1951 )\r
1952{\r
1436aea4
MK
1953 EFI_STATUS Status;\r
1954 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1955 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
a41b5272 1956\r
1436aea4 1957 if ((PciIo == NULL) || (AhciRegisters == NULL)) {\r
a41b5272 1958 return EFI_INVALID_PARAMETER;\r
1959 }\r
490b5ea1 1960\r
a41b5272 1961 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1962 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1963\r
1964 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DEVICE;\r
1965 AtaCommandBlock.AtaSectorCount = 1;\r
1966\r
1967 Status = AhciPioTransfer (\r
1968 PciIo,\r
1969 AhciRegisters,\r
1970 Port,\r
1971 PortMultiplier,\r
1972 NULL,\r
1973 0,\r
1974 TRUE,\r
1975 &AtaCommandBlock,\r
1976 &AtaStatusBlock,\r
1977 Buffer,\r
1978 sizeof (EFI_IDENTIFY_DATA),\r
490b5ea1 1979 ATA_ATAPI_TIMEOUT,\r
1980 NULL\r
a41b5272 1981 );\r
1982\r
1983 return Status;\r
1984}\r
1985\r
1986/**\r
1987 Send SET FEATURE cmd on specific device.\r
1aff716a 1988\r
aca84419 1989 @param PciIo The PCI IO protocol instance.\r
1990 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1991 @param Port The number of port.\r
79992d6e 1992 @param PortMultiplier The port multiplier port number.\r
aca84419 1993 @param Feature The data to send Feature register.\r
1994 @param FeatureSpecificData The specific data for SET FEATURE cmd.\r
8d3c4b55 1995 @param Timeout The timeout value of SET FEATURE cmd, uses 100ns as a unit.\r
a41b5272 1996\r
1997 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1998 @retval EFI_TIMEOUT The operation is time out.\r
1999 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
2000 @retval EFI_SUCCESS The cmd executes successfully.\r
2001\r
2002**/\r
2003EFI_STATUS\r
2004EFIAPI\r
2005AhciDeviceSetFeature (\r
1436aea4
MK
2006 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2007 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2008 IN UINT8 Port,\r
2009 IN UINT8 PortMultiplier,\r
2010 IN UINT16 Feature,\r
2011 IN UINT32 FeatureSpecificData,\r
2012 IN UINT64 Timeout\r
a41b5272 2013 )\r
2014{\r
1436aea4
MK
2015 EFI_STATUS Status;\r
2016 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2017 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
a41b5272 2018\r
2019 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2020 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 2021\r
a41b5272 2022 AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;\r
1436aea4
MK
2023 AtaCommandBlock.AtaFeatures = (UINT8)Feature;\r
2024 AtaCommandBlock.AtaFeaturesExp = (UINT8)(Feature >> 8);\r
2025 AtaCommandBlock.AtaSectorCount = (UINT8)FeatureSpecificData;\r
2026 AtaCommandBlock.AtaSectorNumber = (UINT8)(FeatureSpecificData >> 8);\r
2027 AtaCommandBlock.AtaCylinderLow = (UINT8)(FeatureSpecificData >> 16);\r
2028 AtaCommandBlock.AtaCylinderHigh = (UINT8)(FeatureSpecificData >> 24);\r
a41b5272 2029\r
2030 Status = AhciNonDataTransfer (\r
2031 PciIo,\r
2032 AhciRegisters,\r
2033 (UINT8)Port,\r
2034 (UINT8)PortMultiplier,\r
2035 NULL,\r
2036 0,\r
2037 &AtaCommandBlock,\r
2038 &AtaStatusBlock,\r
8d3c4b55 2039 Timeout,\r
490b5ea1 2040 NULL\r
a41b5272 2041 );\r
2042\r
2043 return Status;\r
2044}\r
2045\r
2046/**\r
1aff716a 2047 This function is used to send out ATAPI commands conforms to the Packet Command\r
a41b5272 2048 with PIO Protocol.\r
2049\r
2050 @param PciIo The PCI IO protocol instance.\r
2051 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1aff716a 2052 @param Port The number of port.\r
a41b5272 2053 @param PortMultiplier The number of port multiplier.\r
2054 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.\r
2055\r
2056 @retval EFI_SUCCESS send out the ATAPI packet command successfully\r
2057 and device sends data successfully.\r
2058 @retval EFI_DEVICE_ERROR the device failed to send data.\r
2059\r
2060**/\r
2061EFI_STATUS\r
2062EFIAPI\r
2063AhciPacketCommandExecute (\r
1436aea4
MK
2064 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2065 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2066 IN UINT8 Port,\r
2067 IN UINT8 PortMultiplier,\r
2068 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
a41b5272 2069 )\r
2070{\r
1436aea4
MK
2071 EFI_STATUS Status;\r
2072 VOID *Buffer;\r
2073 UINT32 Length;\r
2074 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2075 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
2076 BOOLEAN Read;\r
2077\r
2078 if ((Packet == NULL) || (Packet->Cdb == NULL)) {\r
a41b5272 2079 return EFI_INVALID_PARAMETER;\r
2080 }\r
2081\r
2082 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2083 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1436aea4 2084 AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;\r
a41b5272 2085 //\r
2086 // No OVL; No DMA\r
2087 //\r
1436aea4 2088 AtaCommandBlock.AtaFeatures = 0x00;\r
a41b5272 2089 //\r
2090 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
2091 // determine how many data should be transferred.\r
2092 //\r
1436aea4
MK
2093 AtaCommandBlock.AtaCylinderLow = (UINT8)(ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
2094 AtaCommandBlock.AtaCylinderHigh = (UINT8)(ATAPI_MAX_BYTE_COUNT >> 8);\r
a41b5272 2095\r
2096 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
2097 Buffer = Packet->InDataBuffer;\r
2098 Length = Packet->InTransferLength;\r
1436aea4 2099 Read = TRUE;\r
a41b5272 2100 } else {\r
2101 Buffer = Packet->OutDataBuffer;\r
2102 Length = Packet->OutTransferLength;\r
1436aea4 2103 Read = FALSE;\r
a41b5272 2104 }\r
2105\r
490b5ea1 2106 if (Length == 0) {\r
a41b5272 2107 Status = AhciNonDataTransfer (\r
2108 PciIo,\r
2109 AhciRegisters,\r
2110 Port,\r
2111 PortMultiplier,\r
2112 Packet->Cdb,\r
2113 Packet->CdbLength,\r
2114 &AtaCommandBlock,\r
2115 &AtaStatusBlock,\r
1aff716a 2116 Packet->Timeout,\r
490b5ea1 2117 NULL\r
a41b5272 2118 );\r
2119 } else {\r
cbd2a4b3 2120 Status = AhciPioTransfer (\r
2121 PciIo,\r
2122 AhciRegisters,\r
2123 Port,\r
2124 PortMultiplier,\r
2125 Packet->Cdb,\r
2126 Packet->CdbLength,\r
2127 Read,\r
2128 &AtaCommandBlock,\r
2129 &AtaStatusBlock,\r
2130 Buffer,\r
2131 Length,\r
1aff716a 2132 Packet->Timeout,\r
cbd2a4b3 2133 NULL\r
2134 );\r
a41b5272 2135 }\r
1436aea4 2136\r
a41b5272 2137 return Status;\r
2138}\r
2139\r
2140/**\r
2141 Allocate transfer-related data struct which is used at AHCI mode.\r
1aff716a 2142\r
a41b5272 2143 @param PciIo The PCI IO protocol instance.\r
2144 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
2145\r
2146**/\r
2147EFI_STATUS\r
2148EFIAPI\r
2149AhciCreateTransferDescriptor (\r
1436aea4
MK
2150 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2151 IN OUT EFI_AHCI_REGISTERS *AhciRegisters\r
a41b5272 2152 )\r
2153{\r
1436aea4
MK
2154 EFI_STATUS Status;\r
2155 UINTN Bytes;\r
2156 VOID *Buffer;\r
a41b5272 2157\r
2158 UINT32 Capability;\r
467cacbf 2159 UINT32 PortImplementBitMap;\r
a41b5272 2160 UINT8 MaxPortNumber;\r
2161 UINT8 MaxCommandSlotNumber;\r
2162 BOOLEAN Support64Bit;\r
2163 UINT64 MaxReceiveFisSize;\r
2164 UINT64 MaxCommandListSize;\r
2165 UINT64 MaxCommandTableSize;\r
ed365e93 2166 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr;\r
2167 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr;\r
2168 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr;\r
a41b5272 2169\r
2170 Buffer = NULL;\r
2171 //\r
2172 // Collect AHCI controller information\r
2173 //\r
1436aea4 2174 Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
a41b5272 2175 //\r
2176 // Get the number of command slots per port supported by this HBA.\r
2177 //\r
1436aea4
MK
2178 MaxCommandSlotNumber = (UINT8)(((Capability & 0x1F00) >> 8) + 1);\r
2179 Support64Bit = (BOOLEAN)(((Capability & BIT31) != 0) ? TRUE : FALSE);\r
d1102dba 2180\r
1436aea4 2181 PortImplementBitMap = AhciReadReg (PciIo, EFI_AHCI_PI_OFFSET);\r
467cacbf 2182 //\r
8c39253d 2183 // Get the highest bit of implemented ports which decides how many bytes are allocated for received FIS.\r
467cacbf 2184 //\r
1436aea4 2185 MaxPortNumber = (UINT8)(UINTN)(HighBitSet32 (PortImplementBitMap) + 1);\r
467cacbf 2186 if (MaxPortNumber == 0) {\r
2187 return EFI_DEVICE_ERROR;\r
2188 }\r
a41b5272 2189\r
1436aea4
MK
2190 MaxReceiveFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
2191 Status = PciIo->AllocateBuffer (\r
2192 PciIo,\r
2193 AllocateAnyPages,\r
2194 EfiBootServicesData,\r
2195 EFI_SIZE_TO_PAGES ((UINTN)MaxReceiveFisSize),\r
2196 &Buffer,\r
2197 0\r
2198 );\r
a41b5272 2199\r
2200 if (EFI_ERROR (Status)) {\r
2201 return EFI_OUT_OF_RESOURCES;\r
2202 }\r
2203\r
5dec0c68 2204 ZeroMem (Buffer, (UINTN)MaxReceiveFisSize);\r
a41b5272 2205\r
2206 AhciRegisters->AhciRFis = Buffer;\r
2207 AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;\r
1436aea4 2208 Bytes = (UINTN)MaxReceiveFisSize;\r
a41b5272 2209\r
2210 Status = PciIo->Map (\r
2211 PciIo,\r
2212 EfiPciIoOperationBusMasterCommonBuffer,\r
2213 Buffer,\r
2214 &Bytes,\r
ed365e93 2215 &AhciRFisPciAddr,\r
a41b5272 2216 &AhciRegisters->MapRFis\r
2217 );\r
2218\r
2219 if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {\r
2220 //\r
1aff716a 2221 // Map error or unable to map the whole RFis buffer into a contiguous region.\r
a41b5272 2222 //\r
2223 Status = EFI_OUT_OF_RESOURCES;\r
2224 goto Error6;\r
2225 }\r
2226\r
ed365e93 2227 if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {\r
a41b5272 2228 //\r
2229 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2230 //\r
2231 Status = EFI_DEVICE_ERROR;\r
2232 goto Error5;\r
2233 }\r
1436aea4 2234\r
ed365e93 2235 AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;\r
a41b5272 2236\r
2237 //\r
2238 // Allocate memory for command list\r
8c39253d 2239 // Note that the implementation is a single task model which only use a command list for all ports.\r
a41b5272 2240 //\r
1436aea4 2241 Buffer = NULL;\r
a41b5272 2242 MaxCommandListSize = MaxCommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST);\r
1436aea4
MK
2243 Status = PciIo->AllocateBuffer (\r
2244 PciIo,\r
2245 AllocateAnyPages,\r
2246 EfiBootServicesData,\r
2247 EFI_SIZE_TO_PAGES ((UINTN)MaxCommandListSize),\r
2248 &Buffer,\r
2249 0\r
2250 );\r
a41b5272 2251\r
2252 if (EFI_ERROR (Status)) {\r
2253 //\r
1aff716a 2254 // Free mapped resource.\r
a41b5272 2255 //\r
2256 Status = EFI_OUT_OF_RESOURCES;\r
2257 goto Error5;\r
2258 }\r
2259\r
5dec0c68 2260 ZeroMem (Buffer, (UINTN)MaxCommandListSize);\r
a41b5272 2261\r
2262 AhciRegisters->AhciCmdList = Buffer;\r
2263 AhciRegisters->MaxCommandListSize = MaxCommandListSize;\r
1436aea4 2264 Bytes = (UINTN)MaxCommandListSize;\r
a41b5272 2265\r
2266 Status = PciIo->Map (\r
2267 PciIo,\r
2268 EfiPciIoOperationBusMasterCommonBuffer,\r
2269 Buffer,\r
2270 &Bytes,\r
ed365e93 2271 &AhciCmdListPciAddr,\r
a41b5272 2272 &AhciRegisters->MapCmdList\r
2273 );\r
2274\r
2275 if (EFI_ERROR (Status) || (Bytes != MaxCommandListSize)) {\r
2276 //\r
2277 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2278 //\r
2279 Status = EFI_OUT_OF_RESOURCES;\r
2280 goto Error4;\r
2281 }\r
2282\r
ed365e93 2283 if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {\r
a41b5272 2284 //\r
2285 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2286 //\r
2287 Status = EFI_DEVICE_ERROR;\r
2288 goto Error3;\r
2289 }\r
1436aea4 2290\r
ed365e93 2291 AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;\r
a41b5272 2292\r
2293 //\r
2294 // Allocate memory for command table\r
2295 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.\r
2296 //\r
1436aea4 2297 Buffer = NULL;\r
a41b5272 2298 MaxCommandTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);\r
2299\r
2300 Status = PciIo->AllocateBuffer (\r
2301 PciIo,\r
2302 AllocateAnyPages,\r
2303 EfiBootServicesData,\r
1436aea4 2304 EFI_SIZE_TO_PAGES ((UINTN)MaxCommandTableSize),\r
a41b5272 2305 &Buffer,\r
2306 0\r
2307 );\r
2308\r
2309 if (EFI_ERROR (Status)) {\r
2310 //\r
1aff716a 2311 // Free mapped resource.\r
a41b5272 2312 //\r
2313 Status = EFI_OUT_OF_RESOURCES;\r
2314 goto Error3;\r
2315 }\r
2316\r
5dec0c68 2317 ZeroMem (Buffer, (UINTN)MaxCommandTableSize);\r
a41b5272 2318\r
2319 AhciRegisters->AhciCommandTable = Buffer;\r
2320 AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;\r
1436aea4 2321 Bytes = (UINTN)MaxCommandTableSize;\r
a41b5272 2322\r
2323 Status = PciIo->Map (\r
2324 PciIo,\r
2325 EfiPciIoOperationBusMasterCommonBuffer,\r
2326 Buffer,\r
2327 &Bytes,\r
ed365e93 2328 &AhciCommandTablePciAddr,\r
a41b5272 2329 &AhciRegisters->MapCommandTable\r
2330 );\r
2331\r
2332 if (EFI_ERROR (Status) || (Bytes != MaxCommandTableSize)) {\r
2333 //\r
2334 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2335 //\r
2336 Status = EFI_OUT_OF_RESOURCES;\r
2337 goto Error2;\r
2338 }\r
2339\r
ed365e93 2340 if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {\r
a41b5272 2341 //\r
2342 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2343 //\r
2344 Status = EFI_DEVICE_ERROR;\r
2345 goto Error1;\r
2346 }\r
1436aea4 2347\r
ed365e93 2348 AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;\r
a41b5272 2349\r
2350 return EFI_SUCCESS;\r
2351 //\r
1aff716a 2352 // Map error or unable to map the whole CmdList buffer into a contiguous region.\r
a41b5272 2353 //\r
2354Error1:\r
2355 PciIo->Unmap (\r
2356 PciIo,\r
2357 AhciRegisters->MapCommandTable\r
2358 );\r
2359Error2:\r
2360 PciIo->FreeBuffer (\r
2361 PciIo,\r
1436aea4 2362 EFI_SIZE_TO_PAGES ((UINTN)MaxCommandTableSize),\r
a41b5272 2363 AhciRegisters->AhciCommandTable\r
2364 );\r
2365Error3:\r
2366 PciIo->Unmap (\r
2367 PciIo,\r
2368 AhciRegisters->MapCmdList\r
2369 );\r
2370Error4:\r
2371 PciIo->FreeBuffer (\r
2372 PciIo,\r
1436aea4 2373 EFI_SIZE_TO_PAGES ((UINTN)MaxCommandListSize),\r
a41b5272 2374 AhciRegisters->AhciCmdList\r
2375 );\r
2376Error5:\r
2377 PciIo->Unmap (\r
2378 PciIo,\r
2379 AhciRegisters->MapRFis\r
2380 );\r
2381Error6:\r
2382 PciIo->FreeBuffer (\r
2383 PciIo,\r
1436aea4 2384 EFI_SIZE_TO_PAGES ((UINTN)MaxReceiveFisSize),\r
a41b5272 2385 AhciRegisters->AhciRFis\r
2386 );\r
2387\r
2388 return Status;\r
2389}\r
2390\r
f3100a1a
RN
2391/**\r
2392 Read logs from SATA device.\r
2393\r
2394 @param PciIo The PCI IO protocol instance.\r
2395 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
2396 @param Port The number of port.\r
2397 @param PortMultiplier The multiplier of port.\r
2398 @param Buffer The data buffer to store SATA logs.\r
2399 @param LogNumber The address of the log.\r
2400 @param PageNumber The page number of the log.\r
2401\r
2402 @retval EFI_INVALID_PARAMETER PciIo, AhciRegisters or Buffer is NULL.\r
2403 @retval others Return status of AhciPioTransfer().\r
2404**/\r
2405EFI_STATUS\r
2406AhciReadLogExt (\r
1436aea4
MK
2407 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2408 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2409 IN UINT8 Port,\r
2410 IN UINT8 PortMultiplier,\r
2411 IN OUT UINT8 *Buffer,\r
2412 IN UINT8 LogNumber,\r
2413 IN UINT8 PageNumber\r
f3100a1a
RN
2414 )\r
2415{\r
1436aea4
MK
2416 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2417 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
f3100a1a 2418\r
1436aea4 2419 if ((PciIo == NULL) || (AhciRegisters == NULL) || (Buffer == NULL)) {\r
f3100a1a
RN
2420 return EFI_INVALID_PARAMETER;\r
2421 }\r
2422\r
2423 ///\r
2424 /// Read log from device\r
2425 ///\r
2426 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2427 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
2428 ZeroMem (Buffer, 512);\r
2429\r
2430 AtaCommandBlock.AtaCommand = ATA_CMD_READ_LOG_EXT;\r
2431 AtaCommandBlock.AtaSectorCount = 1;\r
2432 AtaCommandBlock.AtaSectorNumber = LogNumber;\r
2433 AtaCommandBlock.AtaCylinderLow = PageNumber;\r
2434\r
2435 return AhciPioTransfer (\r
2436 PciIo,\r
2437 AhciRegisters,\r
2438 Port,\r
2439 PortMultiplier,\r
2440 NULL,\r
2441 0,\r
2442 TRUE,\r
2443 &AtaCommandBlock,\r
2444 &AtaStatusBlock,\r
2445 Buffer,\r
2446 512,\r
2447 ATA_ATAPI_TIMEOUT,\r
2448 NULL\r
2449 );\r
2450}\r
2451\r
2452/**\r
2453 Enable DEVSLP of the disk if supported.\r
2454\r
2455 @param PciIo The PCI IO protocol instance.\r
2456 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
2457 @param Port The number of port.\r
2458 @param PortMultiplier The multiplier of port.\r
2459 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
2460\r
2461 @retval EFI_SUCCESS The DEVSLP is enabled per policy successfully.\r
2462 @retval EFI_UNSUPPORTED The DEVSLP isn't supported by the controller/device and policy requires to enable it.\r
2463**/\r
2464EFI_STATUS\r
2465AhciEnableDevSlp (\r
1436aea4
MK
2466 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2467 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2468 IN UINT8 Port,\r
2469 IN UINT8 PortMultiplier,\r
2470 IN EFI_IDENTIFY_DATA *IdentifyData\r
f3100a1a
RN
2471 )\r
2472{\r
2473 EFI_STATUS Status;\r
2474 UINT32 Offset;\r
2475 UINT32 Capability2;\r
2476 UINT8 LogData[512];\r
2477 DEVSLP_TIMING_VARIABLES DevSlpTiming;\r
2478 UINT32 PortCmd;\r
2479 UINT32 PortDevSlp;\r
2480\r
2481 if (mAtaAtapiPolicy->DeviceSleepEnable != 1) {\r
2482 return EFI_SUCCESS;\r
2483 }\r
2484\r
2485 //\r
2486 // Do not enable DevSlp if DevSlp is not supported.\r
2487 //\r
2488 Capability2 = AhciReadReg (PciIo, AHCI_CAPABILITY2_OFFSET);\r
2489 DEBUG ((DEBUG_INFO, "AHCI CAPABILITY2 = %08x\n", Capability2));\r
2490 if ((Capability2 & AHCI_CAP2_SDS) == 0) {\r
2491 return EFI_UNSUPPORTED;\r
2492 }\r
2493\r
2494 //\r
2495 // Do not enable DevSlp if DevSlp is not present\r
2496 // Do not enable DevSlp if Hot Plug or Mechanical Presence Switch is supported\r
2497 //\r
2498 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH;\r
2499 PortCmd = AhciReadReg (PciIo, Offset + EFI_AHCI_PORT_CMD);\r
2500 PortDevSlp = AhciReadReg (PciIo, Offset + AHCI_PORT_DEVSLP);\r
2501 DEBUG ((DEBUG_INFO, "Port CMD/DEVSLP = %08x / %08x\n", PortCmd, PortDevSlp));\r
2502 if (((PortDevSlp & AHCI_PORT_DEVSLP_DSP) == 0) ||\r
2503 ((PortCmd & (EFI_AHCI_PORT_CMD_HPCP | EFI_AHCI_PORT_CMD_MPSP)) != 0)\r
1436aea4
MK
2504 )\r
2505 {\r
f3100a1a
RN
2506 return EFI_UNSUPPORTED;\r
2507 }\r
2508\r
2509 //\r
2510 // Do not enable DevSlp if the device doesn't support DevSlp\r
2511 //\r
1436aea4
MK
2512 DEBUG ((\r
2513 DEBUG_INFO,\r
2514 "IDENTIFY DEVICE: [77] = %04x, [78] = %04x, [79] = %04x\n",\r
2515 IdentifyData->AtaData.reserved_77,\r
2516 IdentifyData->AtaData.serial_ata_features_supported,\r
2517 IdentifyData->AtaData.serial_ata_features_enabled\r
2518 ));\r
f3100a1a 2519 if ((IdentifyData->AtaData.serial_ata_features_supported & BIT8) == 0) {\r
1436aea4
MK
2520 DEBUG ((\r
2521 DEBUG_INFO,\r
2522 "DevSlp feature is not supported for device at port [%d] PortMultiplier [%d]!\n",\r
2523 Port,\r
2524 PortMultiplier\r
2525 ));\r
f3100a1a
RN
2526 return EFI_UNSUPPORTED;\r
2527 }\r
2528\r
2529 //\r
2530 // Enable DevSlp when it is not enabled.\r
2531 //\r
2532 if ((IdentifyData->AtaData.serial_ata_features_enabled & BIT8) != 0) {\r
2533 Status = AhciDeviceSetFeature (\r
1436aea4
MK
2534 PciIo,\r
2535 AhciRegisters,\r
2536 Port,\r
2537 0,\r
2538 ATA_SUB_CMD_ENABLE_SATA_FEATURE,\r
2539 0x09,\r
2540 ATA_ATAPI_TIMEOUT\r
2541 );\r
2542 DEBUG ((\r
2543 DEBUG_INFO,\r
2544 "DevSlp set feature for device at port [%d] PortMultiplier [%d] - %r\n",\r
2545 Port,\r
2546 PortMultiplier,\r
2547 Status\r
2548 ));\r
f3100a1a
RN
2549 if (EFI_ERROR (Status)) {\r
2550 return Status;\r
2551 }\r
2552 }\r
2553\r
1436aea4 2554 Status = AhciReadLogExt (PciIo, AhciRegisters, Port, PortMultiplier, LogData, 0x30, 0x08);\r
f3100a1a
RN
2555\r
2556 //\r
2557 // Clear PxCMD.ST and PxDEVSLP.ADSE before updating PxDEVSLP.DITO and PxDEVSLP.MDAT.\r
2558 //\r
2559 AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd & ~EFI_AHCI_PORT_CMD_ST);\r
2560 PortDevSlp &= ~AHCI_PORT_DEVSLP_ADSE;\r
2561 AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
2562\r
2563 //\r
2564 // Set PxDEVSLP.DETO and PxDEVSLP.MDAT to 0.\r
2565 //\r
2566 PortDevSlp &= ~AHCI_PORT_DEVSLP_DETO_MASK;\r
2567 PortDevSlp &= ~AHCI_PORT_DEVSLP_MDAT_MASK;\r
2568 AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
2569 DEBUG ((DEBUG_INFO, "Read Log Ext at port [%d] PortMultiplier [%d] - %r\n", Port, PortMultiplier, Status));\r
2570 if (EFI_ERROR (Status)) {\r
2571 //\r
2572 // Assume DEVSLP TIMING VARIABLES is not supported if the Identify Device Data log (30h, 8) fails\r
2573 //\r
4e738cd4 2574 ZeroMem (&DevSlpTiming, sizeof (DevSlpTiming));\r
f3100a1a
RN
2575 } else {\r
2576 CopyMem (&DevSlpTiming, &LogData[48], sizeof (DevSlpTiming));\r
1436aea4
MK
2577 DEBUG ((\r
2578 DEBUG_INFO,\r
2579 "DevSlpTiming: Supported(%d), Deto(%d), Madt(%d)\n",\r
2580 DevSlpTiming.Supported,\r
2581 DevSlpTiming.Deto,\r
2582 DevSlpTiming.Madt\r
2583 ));\r
f3100a1a
RN
2584 }\r
2585\r
2586 //\r
2587 // Use 20ms as default DETO when DEVSLP TIMING VARIABLES is not supported or the DETO is 0.\r
2588 //\r
2589 if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Deto == 0)) {\r
2590 DevSlpTiming.Deto = 20;\r
2591 }\r
2592\r
2593 //\r
2594 // Use 10ms as default MADT when DEVSLP TIMING VARIABLES is not supported or the MADT is 0.\r
2595 //\r
2596 if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Madt == 0)) {\r
2597 DevSlpTiming.Madt = 10;\r
2598 }\r
2599\r
2600 PortDevSlp |= DevSlpTiming.Deto << 2;\r
2601 PortDevSlp |= DevSlpTiming.Madt << 10;\r
2602 AhciOrReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
2603\r
2604 if (mAtaAtapiPolicy->AggressiveDeviceSleepEnable == 1) {\r
2605 if ((Capability2 & AHCI_CAP2_SADM) != 0) {\r
2606 PortDevSlp &= ~AHCI_PORT_DEVSLP_DITO_MASK;\r
2607 PortDevSlp |= (625 << 15);\r
2608 AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
2609\r
2610 PortDevSlp |= AHCI_PORT_DEVSLP_ADSE;\r
2611 AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
2612 }\r
2613 }\r
2614\r
f3100a1a
RN
2615 AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd);\r
2616\r
1436aea4
MK
2617 DEBUG ((\r
2618 DEBUG_INFO,\r
2619 "Enabled DevSlp feature at port [%d] PortMultiplier [%d], Port CMD/DEVSLP = %08x / %08x\n",\r
2620 Port,\r
2621 PortMultiplier,\r
2622 PortCmd,\r
2623 PortDevSlp\r
2624 ));\r
f3100a1a
RN
2625\r
2626 return EFI_SUCCESS;\r
2627}\r
8d3c4b55
RN
2628\r
2629/**\r
2630 Spin-up disk if IDD was incomplete or PUIS feature is enabled\r
2631\r
2632 @param PciIo The PCI IO protocol instance.\r
2633 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
2634 @param Port The number of port.\r
2635 @param PortMultiplier The multiplier of port.\r
2636 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
2637\r
2638**/\r
2639EFI_STATUS\r
2640AhciSpinUpDisk (\r
1436aea4
MK
2641 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2642 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2643 IN UINT8 Port,\r
2644 IN UINT8 PortMultiplier,\r
2645 IN OUT EFI_IDENTIFY_DATA *IdentifyData\r
8d3c4b55
RN
2646 )\r
2647{\r
1436aea4
MK
2648 EFI_STATUS Status;\r
2649 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2650 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
2651 UINT8 Buffer[512];\r
8d3c4b55
RN
2652\r
2653 if (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_REQUIRED_IDD_INCOMPLETE) {\r
2654 //\r
2655 // Use SET_FEATURE subcommand to spin up the device.\r
2656 //\r
2657 Status = AhciDeviceSetFeature (\r
1436aea4
MK
2658 PciIo,\r
2659 AhciRegisters,\r
2660 Port,\r
2661 PortMultiplier,\r
2662 ATA_SUB_CMD_PUIS_SET_DEVICE_SPINUP,\r
2663 0x00,\r
2664 ATA_SPINUP_TIMEOUT\r
8d3c4b55 2665 );\r
1436aea4
MK
2666 DEBUG ((\r
2667 DEBUG_INFO,\r
2668 "CMD_PUIS_SET_DEVICE_SPINUP for device at port [%d] PortMultiplier [%d] - %r!\n",\r
2669 Port,\r
2670 PortMultiplier,\r
2671 Status\r
2672 ));\r
8d3c4b55
RN
2673 if (EFI_ERROR (Status)) {\r
2674 return Status;\r
2675 }\r
2676 } else {\r
2677 ASSERT (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_NOT_REQUIRED_IDD_INCOMPLETE);\r
2678\r
2679 //\r
2680 // Use READ_SECTORS to spin up the device if SpinUp SET FEATURE subcommand is not supported\r
2681 //\r
2682 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2683 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
2684 //\r
2685 // Perform READ SECTORS PIO Data-In command to Read LBA 0\r
2686 //\r
1436aea4
MK
2687 AtaCommandBlock.AtaCommand = ATA_CMD_READ_SECTORS;\r
2688 AtaCommandBlock.AtaSectorCount = 0x1;\r
8d3c4b55
RN
2689\r
2690 Status = AhciPioTransfer (\r
2691 PciIo,\r
2692 AhciRegisters,\r
2693 Port,\r
2694 PortMultiplier,\r
2695 NULL,\r
2696 0,\r
2697 TRUE,\r
2698 &AtaCommandBlock,\r
2699 &AtaStatusBlock,\r
2700 &Buffer,\r
2701 sizeof (Buffer),\r
2702 ATA_SPINUP_TIMEOUT,\r
2703 NULL\r
2704 );\r
1436aea4
MK
2705 DEBUG ((\r
2706 DEBUG_INFO,\r
2707 "Read LBA 0 for device at port [%d] PortMultiplier [%d] - %r!\n",\r
2708 Port,\r
2709 PortMultiplier,\r
2710 Status\r
2711 ));\r
8d3c4b55
RN
2712 if (EFI_ERROR (Status)) {\r
2713 return Status;\r
2714 }\r
2715 }\r
2716\r
2717 //\r
2718 // Read the complete IDENTIFY DEVICE data.\r
2719 //\r
2720 ZeroMem (IdentifyData, sizeof (*IdentifyData));\r
2721 Status = AhciIdentify (PciIo, AhciRegisters, Port, PortMultiplier, IdentifyData);\r
2722 if (EFI_ERROR (Status)) {\r
1436aea4
MK
2723 DEBUG ((\r
2724 DEBUG_ERROR,\r
2725 "Read IDD failed for device at port [%d] PortMultiplier [%d] - %r!\n",\r
2726 Port,\r
2727 PortMultiplier,\r
2728 Status\r
2729 ));\r
8d3c4b55
RN
2730 return Status;\r
2731 }\r
2732\r
1436aea4
MK
2733 DEBUG ((\r
2734 DEBUG_INFO,\r
2735 "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",\r
2736 IdentifyData->AtaData.config,\r
2737 IdentifyData->AtaData.specific_config,\r
2738 IdentifyData->AtaData.command_set_supported_83,\r
2739 IdentifyData->AtaData.command_set_feature_enb_86\r
2740 ));\r
8d3c4b55
RN
2741 //\r
2742 // Check if IDD is incomplete\r
2743 //\r
2744 if ((IdentifyData->AtaData.config & BIT2) != 0) {\r
2745 return EFI_DEVICE_ERROR;\r
2746 }\r
2747\r
2748 return EFI_SUCCESS;\r
2749}\r
2750\r
06766c0e
RN
2751/**\r
2752 Enable/disable/skip PUIS of the disk according to policy.\r
2753\r
2754 @param PciIo The PCI IO protocol instance.\r
2755 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
2756 @param Port The number of port.\r
2757 @param PortMultiplier The multiplier of port.\r
2758\r
2759**/\r
2760EFI_STATUS\r
2761AhciPuisEnable (\r
1436aea4
MK
2762 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2763 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2764 IN UINT8 Port,\r
2765 IN UINT8 PortMultiplier\r
06766c0e
RN
2766 )\r
2767{\r
1436aea4 2768 EFI_STATUS Status;\r
06766c0e
RN
2769\r
2770 Status = EFI_SUCCESS;\r
2771 if (mAtaAtapiPolicy->PuisEnable == 0) {\r
2772 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, PortMultiplier, ATA_SUB_CMD_DISABLE_PUIS, 0x00, ATA_ATAPI_TIMEOUT);\r
2773 } else if (mAtaAtapiPolicy->PuisEnable == 1) {\r
2774 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, PortMultiplier, ATA_SUB_CMD_ENABLE_PUIS, 0x00, ATA_ATAPI_TIMEOUT);\r
2775 }\r
1436aea4
MK
2776\r
2777 DEBUG ((\r
2778 DEBUG_INFO,\r
2779 "%a PUIS feature at port [%d] PortMultiplier [%d] - %r!\n",\r
06766c0e 2780 (mAtaAtapiPolicy->PuisEnable == 0) ? "Disable" : (\r
1436aea4
MK
2781 (mAtaAtapiPolicy->PuisEnable == 1) ? "Enable" : "Skip"\r
2782 ),\r
2783 Port,\r
2784 PortMultiplier,\r
2785 Status\r
2786 ));\r
06766c0e
RN
2787 return Status;\r
2788}\r
2789\r
a41b5272 2790/**\r
2791 Initialize ATA host controller at AHCI mode.\r
2792\r
1aff716a 2793 The function is designed to initialize ATA host controller.\r
2794\r
a41b5272 2795 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
2796\r
2797**/\r
2798EFI_STATUS\r
2799EFIAPI\r
2800AhciModeInitialization (\r
1436aea4 2801 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance\r
a41b5272 2802 )\r
2803{\r
1436aea4
MK
2804 EFI_STATUS Status;\r
2805 EFI_PCI_IO_PROTOCOL *PciIo;\r
2806 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2807 UINT32 Capability;\r
2808 UINT8 MaxPortNumber;\r
2809 UINT32 PortImplementBitMap;\r
2810\r
2811 EFI_AHCI_REGISTERS *AhciRegisters;\r
2812\r
2813 UINT8 Port;\r
2814 DATA_64 Data64;\r
2815 UINT32 Offset;\r
2816 UINT32 Data;\r
2817 EFI_IDENTIFY_DATA Buffer;\r
2818 EFI_ATA_DEVICE_TYPE DeviceType;\r
2819 EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
2820 EFI_ATA_TRANSFER_MODE TransferMode;\r
2821 UINT32 PhyDetectDelay;\r
2822 UINT32 Value;\r
cbd2a4b3 2823\r
a41b5272 2824 if (Instance == NULL) {\r
2825 return EFI_INVALID_PARAMETER;\r
2826 }\r
2827\r
2828 PciIo = Instance->PciIo;\r
2829 IdeInit = Instance->IdeControllerInit;\r
2830\r
1aff716a 2831 Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT);\r
a41b5272 2832\r
2833 if (EFI_ERROR (Status)) {\r
2834 return EFI_DEVICE_ERROR;\r
2835 }\r
2836\r
2837 //\r
1ff1dd0f 2838 // Collect AHCI controller information\r
a41b5272 2839 //\r
1ff1dd0f 2840 Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
6052a15f 2841\r
a41b5272 2842 //\r
6052a15f 2843 // Make sure that GHC.AE bit is set before accessing any AHCI registers.\r
a41b5272 2844 //\r
1436aea4 2845 Value = AhciReadReg (PciIo, EFI_AHCI_GHC_OFFSET);\r
6052a15f
MW
2846\r
2847 if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
1ff1dd0f
FT
2848 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
2849 }\r
a2c9b087
AB
2850\r
2851 //\r
2852 // Enable 64-bit DMA support in the PCI layer if this controller\r
2853 // supports it.\r
2854 //\r
2855 if ((Capability & EFI_AHCI_CAP_S64A) != 0) {\r
2856 Status = PciIo->Attributes (\r
2857 PciIo,\r
2858 EfiPciIoAttributeOperationEnable,\r
2859 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
2860 NULL\r
2861 );\r
2862 if (EFI_ERROR (Status)) {\r
1436aea4
MK
2863 DEBUG ((\r
2864 DEBUG_WARN,\r
a2c9b087 2865 "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",\r
1436aea4
MK
2866 Status\r
2867 ));\r
a2c9b087
AB
2868 }\r
2869 }\r
2870\r
a41b5272 2871 //\r
2872 // Get the number of command slots per port supported by this HBA.\r
2873 //\r
1436aea4 2874 MaxPortNumber = (UINT8)((Capability & 0x1F) + 1);\r
a41b5272 2875\r
2876 //\r
2877 // Get the bit map of those ports exposed by this HBA.\r
1aff716a 2878 // It indicates which ports that the HBA supports are available for software to use.\r
a41b5272 2879 //\r
1436aea4 2880 PortImplementBitMap = AhciReadReg (PciIo, EFI_AHCI_PI_OFFSET);\r
1aff716a 2881\r
a41b5272 2882 AhciRegisters = &Instance->AhciRegisters;\r
1436aea4 2883 Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
a41b5272 2884\r
2885 if (EFI_ERROR (Status)) {\r
2886 return EFI_OUT_OF_RESOURCES;\r
2887 }\r
2888\r
1436aea4 2889 for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port++) {\r
27daa865 2890 if ((PortImplementBitMap & (((UINT32)BIT0) << Port)) != 0) {\r
6b13aa60 2891 //\r
2892 // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.\r
2893 //\r
2894 if ((MaxPortNumber--) == 0) {\r
2895 //\r
2896 // Should never be here.\r
2897 //\r
2898 ASSERT (FALSE);\r
2899 return EFI_SUCCESS;\r
2900 }\r
2901\r
cbd2a4b3 2902 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
2903\r
2904 //\r
2905 // Initialize FIS Base Address Register and Command List Base Address Register for use.\r
2906 //\r
1436aea4
MK
2907 Data64.Uint64 = (UINTN)(AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
2908 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
cbd2a4b3 2909 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2910 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
2911 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2912\r
1436aea4
MK
2913 Data64.Uint64 = (UINTN)(AhciRegisters->AhciCmdListPciAddr);\r
2914 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
cbd2a4b3 2915 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2916 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
2917 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2918\r
a41b5272 2919 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1436aea4 2920 Data = AhciReadReg (PciIo, Offset);\r
a41b5272 2921 if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
2922 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
2923 }\r
a41b5272 2924\r
cbd2a4b3 2925 if ((Capability & EFI_AHCI_CAP_SSS) != 0) {\r
2926 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
2927 }\r
2928\r
2929 //\r
2930 // Disable aggressive power management.\r
2931 //\r
2932 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
2933 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
2934 //\r
2935 // Disable the reporting of the corresponding interrupt to system software.\r
2936 //\r
2937 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
2938 AhciAndReg (PciIo, Offset, 0);\r
a41b5272 2939\r
cbd2a4b3 2940 //\r
2941 // Now inform the IDE Controller Init Module.\r
2942 //\r
2943 IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
2944\r
2945 //\r
2946 // Enable FIS Receive DMA engine for the first D2H FIS.\r
2947 //\r
2948 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
2949 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
cbd2a4b3 2950\r
a41b5272 2951 //\r
1fb805b1 2952 // Wait for the Phy to detect the presence of a device.\r
a41b5272 2953 //\r
cbd2a4b3 2954 PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;\r
1436aea4 2955 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
cbd2a4b3 2956 do {\r
2957 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
2958 if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {\r
2959 break;\r
a41b5272 2960 }\r
2961\r
cbd2a4b3 2962 MicroSecondDelay (1000);\r
2963 PhyDetectDelay--;\r
2964 } while (PhyDetectDelay > 0);\r
2965\r
2966 if (PhyDetectDelay == 0) {\r
a41b5272 2967 //\r
cbd2a4b3 2968 // No device detected at this port.\r
2721fabc 2969 // Clear PxCMD.SUD for those ports at which there are no device present.\r
a41b5272 2970 //\r
2721fabc 2971 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
2972 AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_SUD));\r
cbd2a4b3 2973 continue;\r
2974 }\r
a41b5272 2975\r
b465a811
AM
2976 Status = AhciWaitDeviceReady (PciIo, Port);\r
2977 if (EFI_ERROR (Status)) {\r
cbd2a4b3 2978 continue;\r
2979 }\r
a41b5272 2980\r
cbd2a4b3 2981 //\r
2982 // When the first D2H register FIS is received, the content of PxSIG register is updated.\r
2983 //\r
2984 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
8536cc4b 2985 Status = AhciWaitMmioSet (\r
1aff716a 2986 PciIo,\r
cbd2a4b3 2987 Offset,\r
2988 0x0000FFFF,\r
2989 0x00000101,\r
1436aea4 2990 EFI_TIMER_PERIOD_SECONDS (16)\r
cbd2a4b3 2991 );\r
2992 if (EFI_ERROR (Status)) {\r
2993 continue;\r
2994 }\r
a41b5272 2995\r
cbd2a4b3 2996 Data = AhciReadReg (PciIo, Offset);\r
2997 if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
2998 Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
a41b5272 2999\r
cbd2a4b3 3000 if (EFI_ERROR (Status)) {\r
a41b5272 3001 continue;\r
3002 }\r
aca84419 3003\r
cbd2a4b3 3004 DeviceType = EfiIdeCdrom;\r
3005 } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
3006 Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
a41b5272 3007\r
a41b5272 3008 if (EFI_ERROR (Status)) {\r
cbd2a4b3 3009 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
a41b5272 3010 continue;\r
3011 }\r
3012\r
8d3c4b55 3013 DEBUG ((\r
1436aea4
MK
3014 DEBUG_INFO,\r
3015 "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",\r
3016 Buffer.AtaData.config,\r
3017 Buffer.AtaData.specific_config,\r
3018 Buffer.AtaData.command_set_supported_83,\r
3019 Buffer.AtaData.command_set_feature_enb_86\r
8d3c4b55
RN
3020 ));\r
3021 if ((Buffer.AtaData.config & BIT2) != 0) {\r
3022 //\r
3023 // SpinUp disk if device reported incomplete IDENTIFY DEVICE.\r
3024 //\r
3025 Status = AhciSpinUpDisk (\r
3026 PciIo,\r
3027 AhciRegisters,\r
3028 Port,\r
3029 0,\r
3030 &Buffer\r
3031 );\r
3032 if (EFI_ERROR (Status)) {\r
3033 DEBUG ((DEBUG_ERROR, "Spin up standby device failed - %r\n", Status));\r
3034 continue;\r
3035 }\r
3036 }\r
3037\r
cbd2a4b3 3038 DeviceType = EfiIdeHarddisk;\r
3039 } else {\r
3040 continue;\r
3041 }\r
1436aea4
MK
3042\r
3043 DEBUG ((\r
3044 DEBUG_INFO,\r
3045 "port [%d] port multitplier [%d] has a [%a]\n",\r
3046 Port,\r
3047 0,\r
3048 DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"\r
3049 ));\r
a41b5272 3050\r
cbd2a4b3 3051 //\r
3052 // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
3053 //\r
fc80ee69 3054 if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {\r
cbd2a4b3 3055 AhciAtaSmartSupport (\r
3056 PciIo,\r
3057 AhciRegisters,\r
3058 Port,\r
3059 0,\r
3060 &Buffer,\r
3061 NULL\r
3062 );\r
3063 }\r
a41b5272 3064\r
cbd2a4b3 3065 //\r
3066 // Submit identify data to IDE controller init driver\r
3067 //\r
3068 IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
aca84419 3069\r
cbd2a4b3 3070 //\r
3071 // Now start to config ide device parameter and transfer mode.\r
3072 //\r
3073 Status = IdeInit->CalculateMode (\r
3074 IdeInit,\r
3075 Port,\r
3076 0,\r
3077 &SupportedModes\r
3078 );\r
3079 if (EFI_ERROR (Status)) {\r
87000d77 3080 DEBUG ((DEBUG_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
cbd2a4b3 3081 continue;\r
3082 }\r
3083\r
3084 //\r
3085 // Set best supported PIO mode on this IDE device\r
3086 //\r
3087 if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
3088 TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
3089 } else {\r
3090 TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
3091 }\r
3092\r
1436aea4 3093 TransferMode.ModeNumber = (UINT8)(SupportedModes->PioMode.Mode);\r
cbd2a4b3 3094\r
3095 //\r
8c39253d 3096 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA can't\r
cbd2a4b3 3097 // be set together. Only one DMA mode can be set to a device. If setting\r
3098 // DMA mode operation fails, we can continue moving on because we only use\r
3099 // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
3100 //\r
3101 if (SupportedModes->UdmaMode.Valid) {\r
3102 TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
1436aea4 3103 TransferMode.ModeNumber = (UINT8)(SupportedModes->UdmaMode.Mode);\r
cbd2a4b3 3104 } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
3105 TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
1436aea4 3106 TransferMode.ModeNumber = (UINT8)SupportedModes->MultiWordDmaMode.Mode;\r
cbd2a4b3 3107 }\r
3108\r
8d3c4b55 3109 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode), ATA_ATAPI_TIMEOUT);\r
cbd2a4b3 3110 if (EFI_ERROR (Status)) {\r
87000d77 3111 DEBUG ((DEBUG_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
cbd2a4b3 3112 continue;\r
3113 }\r
3114\r
3115 //\r
3116 // Found a ATA or ATAPI device, add it into the device list.\r
3117 //\r
23a596db 3118 CreateNewDeviceInfo (Instance, Port, 0xFFFF, DeviceType, &Buffer);\r
cbd2a4b3 3119 if (DeviceType == EfiIdeHarddisk) {\r
3120 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
f3100a1a
RN
3121 AhciEnableDevSlp (\r
3122 PciIo,\r
3123 AhciRegisters,\r
3124 Port,\r
3125 0,\r
3126 &Buffer\r
3127 );\r
a41b5272 3128 }\r
06766c0e
RN
3129\r
3130 //\r
3131 // Enable/disable PUIS according to policy setting if PUIS is capable (Word[83].BIT5 is set).\r
3132 //\r
3133 if ((Buffer.AtaData.command_set_supported_83 & BIT5) != 0) {\r
3134 Status = AhciPuisEnable (\r
3135 PciIo,\r
3136 AhciRegisters,\r
3137 Port,\r
3138 0\r
3139 );\r
3140 if (EFI_ERROR (Status)) {\r
3141 DEBUG ((DEBUG_ERROR, "PUIS enable/disable failed, Status = %r\n", Status));\r
3142 continue;\r
3143 }\r
3144 }\r
a41b5272 3145 }\r
3146 }\r
cbd2a4b3 3147\r
a41b5272 3148 return EFI_SUCCESS;\r
3149}\r