]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
MdeModulePkg: Apply uncrustify changes
[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
a41b5272 952\r
953 if (Read) {\r
954 Flag = EfiPciIoOperationBusMasterWrite;\r
955 } else {\r
956 Flag = EfiPciIoOperationBusMasterRead;\r
957 }\r
958\r
959 //\r
960 // construct command list and command table with pci bus address\r
961 //\r
962 MapLength = DataCount;\r
1436aea4
MK
963 Status = PciIo->Map (\r
964 PciIo,\r
965 Flag,\r
966 MemoryAddr,\r
967 &MapLength,\r
968 &PhyAddr,\r
969 &Map\r
970 );\r
a41b5272 971\r
972 if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
9e70c18b 973 return EFI_BAD_BUFFER_SIZE;\r
a41b5272 974 }\r
1aff716a 975\r
a41b5272 976 //\r
977 // Package read needed\r
978 //\r
979 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
980\r
981 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
982\r
983 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
984 CmdList.AhciCmdW = Read ? 0 : 1;\r
985\r
64e25d4b
AM
986 for (Retry = 0; Retry < AHCI_COMMAND_RETRIES; Retry++) {\r
987 AhciBuildCommand (\r
988 PciIo,\r
989 AhciRegisters,\r
990 Port,\r
991 PortMultiplier,\r
992 &CFis,\r
993 &CmdList,\r
994 AtapiCommand,\r
995 AtapiCommandLength,\r
996 0,\r
997 (VOID *)(UINTN)PhyAddr,\r
998 DataCount\r
999 );\r
1aff716a 1000\r
91d95113
AM
1001 DEBUG ((DEBUG_VERBOSE, "Starting command for PIO transfer:\n"));\r
1002 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_VERBOSE);\r
64e25d4b 1003 Status = AhciStartCommand (\r
1436aea4
MK
1004 PciIo,\r
1005 Port,\r
1006 0,\r
1007 Timeout\r
1008 );\r
64e25d4b
AM
1009 if (EFI_ERROR (Status)) {\r
1010 break;\r
1011 }\r
490b5ea1 1012\r
64e25d4b
AM
1013 if (Read && (AtapiCommand == 0)) {\r
1014 Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisPioSetup);\r
1015 if (Status == EFI_SUCCESS) {\r
1436aea4 1016 PrdCount = *(volatile UINT32 *)(&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
64e25d4b
AM
1017 if (PrdCount == DataCount) {\r
1018 Status = EFI_SUCCESS;\r
1019 } else {\r
1020 Status = EFI_DEVICE_ERROR;\r
1021 }\r
43654b1c 1022 }\r
64e25d4b
AM
1023 } else {\r
1024 Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);\r
8536cc4b 1025 }\r
a41b5272 1026\r
64e25d4b
AM
1027 if (Status == EFI_DEVICE_ERROR) {\r
1028 DEBUG ((DEBUG_ERROR, "PIO command failed at retry %d\n", Retry));\r
1029 Status = AhciRecoverPortError (PciIo, Port);\r
1030 if (EFI_ERROR (Status)) {\r
1031 break;\r
1032 }\r
1033 } else {\r
1034 break;\r
1035 }\r
b465a811
AM
1036 }\r
1037\r
a41b5272 1038 AhciStopCommand (\r
490b5ea1 1039 PciIo,\r
a41b5272 1040 Port,\r
1041 Timeout\r
1042 );\r
1aff716a 1043\r
a41b5272 1044 AhciDisableFisReceive (\r
490b5ea1 1045 PciIo,\r
a41b5272 1046 Port,\r
1047 Timeout\r
1048 );\r
1049\r
1050 PciIo->Unmap (\r
1436aea4
MK
1051 PciIo,\r
1052 Map\r
1053 );\r
a41b5272 1054\r
a7b3f90f 1055 AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
91d95113
AM
1056\r
1057 if (Status == EFI_DEVICE_ERROR) {\r
1058 DEBUG ((DEBUG_ERROR, "Failed to execute command for PIO transfer:\n"));\r
1059 //\r
1060 // Repeat command block here to make sure it is printed on\r
1061 // device error debug level.\r
1062 //\r
1063 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_ERROR);\r
1064 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_ERROR);\r
1065 } else {\r
1066 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_VERBOSE);\r
1067 }\r
1068\r
a41b5272 1069 return Status;\r
1070}\r
1071\r
1072/**\r
1073 Start a DMA data transfer on specific port\r
1074\r
490b5ea1 1075 @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.\r
1076 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1077 @param[in] Port The number of port.\r
1078 @param[in] PortMultiplier The timeout value of stop.\r
1079 @param[in] AtapiCommand The atapi command will be used for the\r
1080 transfer.\r
1081 @param[in] AtapiCommandLength The length of the atapi command.\r
1082 @param[in] Read The transfer direction.\r
1083 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
1084 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
1085 @param[in, out] MemoryAddr The pointer to the data buffer.\r
1086 @param[in] DataCount The data count to be transferred.\r
8536cc4b 1087 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 1088 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1089 used by non-blocking mode.\r
aca84419 1090\r
1091 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.\r
1092 @retval EFI_TIMEOUT The operation is time out.\r
1093 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
1094 @retval EFI_SUCCESS The DMA data transfer executes successfully.\r
490b5ea1 1095\r
a41b5272 1096**/\r
1097EFI_STATUS\r
1098EFIAPI\r
1099AhciDmaTransfer (\r
1436aea4
MK
1100 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
1101 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1102 IN UINT8 Port,\r
1103 IN UINT8 PortMultiplier,\r
1104 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
1105 IN UINT8 AtapiCommandLength,\r
1106 IN BOOLEAN Read,\r
1107 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
1108 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
1109 IN OUT VOID *MemoryAddr,\r
1110 IN UINT32 DataCount,\r
1111 IN UINT64 Timeout,\r
1112 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 1113 )\r
1114{\r
1436aea4
MK
1115 EFI_STATUS Status;\r
1116 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1117 VOID *Map;\r
1118 UINTN MapLength;\r
1119 EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
1120 EFI_AHCI_COMMAND_FIS CFis;\r
1121 EFI_AHCI_COMMAND_LIST CmdList;\r
1122 EFI_PCI_IO_PROTOCOL *PciIo;\r
1123 EFI_TPL OldTpl;\r
1124 UINT32 Retry;\r
a41b5272 1125\r
490b5ea1 1126 Map = NULL;\r
1127 PciIo = Instance->PciIo;\r
a41b5272 1128\r
490b5ea1 1129 if (PciIo == NULL) {\r
1130 return EFI_INVALID_PARAMETER;\r
a41b5272 1131 }\r
1132\r
aa759653
LG
1133 //\r
1134 // Set Status to suppress incorrect compiler/analyzer warnings\r
1135 //\r
1136 Status = EFI_SUCCESS;\r
1137\r
a41b5272 1138 //\r
64e25d4b
AM
1139 // DMA buffer allocation. Needs to be done only once for both sync and async\r
1140 // DMA transfers irrespective of number of retries.\r
a41b5272 1141 //\r
64e25d4b 1142 if ((Task == NULL) || ((Task != NULL) && (Task->Map == NULL))) {\r
490b5ea1 1143 if (Read) {\r
1144 Flag = EfiPciIoOperationBusMasterWrite;\r
1145 } else {\r
1146 Flag = EfiPciIoOperationBusMasterRead;\r
1147 }\r
a41b5272 1148\r
490b5ea1 1149 MapLength = DataCount;\r
1436aea4
MK
1150 Status = PciIo->Map (\r
1151 PciIo,\r
1152 Flag,\r
1153 MemoryAddr,\r
1154 &MapLength,\r
1155 &PhyAddr,\r
1156 &Map\r
1157 );\r
490b5ea1 1158\r
1159 if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
9e70c18b 1160 return EFI_BAD_BUFFER_SIZE;\r
490b5ea1 1161 }\r
1436aea4 1162\r
490b5ea1 1163 if (Task != NULL) {\r
1164 Task->Map = Map;\r
1165 }\r
64e25d4b
AM
1166 }\r
1167\r
1436aea4 1168 if ((Task == NULL) || ((Task != NULL) && !Task->IsStart)) {\r
490b5ea1 1169 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
1170\r
1171 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
1172\r
1173 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
1174 CmdList.AhciCmdW = Read ? 0 : 1;\r
a41b5272 1175 }\r
1176\r
64e25d4b
AM
1177 if (Task == NULL) {\r
1178 //\r
1179 // Before starting the Blocking BlockIO operation, push to finish all non-blocking\r
1180 // BlockIO tasks.\r
1181 // Delay 100us to simulate the blocking time out checking.\r
1182 //\r
1183 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1184 while (!IsListEmpty (&Instance->NonBlockingTaskList)) {\r
1185 AsyncNonBlockingTransferRoutine (NULL, Instance);\r
1186 //\r
1187 // Stall for 100us.\r
1188 //\r
1189 MicroSecondDelay (100);\r
1190 }\r
1436aea4 1191\r
64e25d4b
AM
1192 gBS->RestoreTPL (OldTpl);\r
1193 for (Retry = 0; Retry < AHCI_COMMAND_RETRIES; Retry++) {\r
1194 AhciBuildCommand (\r
1195 PciIo,\r
1196 AhciRegisters,\r
1197 Port,\r
1198 PortMultiplier,\r
1199 &CFis,\r
1200 &CmdList,\r
1201 AtapiCommand,\r
1202 AtapiCommandLength,\r
1203 0,\r
1204 (VOID *)(UINTN)PhyAddr,\r
1205 DataCount\r
1206 );\r
1207\r
91d95113
AM
1208 DEBUG ((DEBUG_VERBOSE, "Starting command for sync DMA transfer:\n"));\r
1209 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_VERBOSE);\r
64e25d4b 1210 Status = AhciStartCommand (\r
1436aea4
MK
1211 PciIo,\r
1212 Port,\r
1213 0,\r
1214 Timeout\r
1215 );\r
64e25d4b
AM
1216 if (EFI_ERROR (Status)) {\r
1217 break;\r
1218 }\r
1436aea4 1219\r
64e25d4b
AM
1220 Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);\r
1221 if (Status == EFI_DEVICE_ERROR) {\r
1222 DEBUG ((DEBUG_ERROR, "DMA command failed at retry: %d\n", Retry));\r
1223 Status = AhciRecoverPortError (PciIo, Port);\r
1224 if (EFI_ERROR (Status)) {\r
1225 break;\r
1226 }\r
cc28ab7a 1227 } else {\r
64e25d4b 1228 break;\r
cc28ab7a
AM
1229 }\r
1230 }\r
490b5ea1 1231 } else {\r
64e25d4b
AM
1232 if (!Task->IsStart) {\r
1233 AhciBuildCommand (\r
1234 PciIo,\r
1235 AhciRegisters,\r
1236 Port,\r
1237 PortMultiplier,\r
1238 &CFis,\r
1239 &CmdList,\r
1240 AtapiCommand,\r
1241 AtapiCommandLength,\r
1242 0,\r
1243 (VOID *)(UINTN)PhyAddr,\r
1244 DataCount\r
1245 );\r
1246\r
91d95113
AM
1247 DEBUG ((DEBUG_VERBOSE, "Starting command for async DMA transfer:\n"));\r
1248 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_VERBOSE);\r
64e25d4b 1249 Status = AhciStartCommand (\r
1436aea4
MK
1250 PciIo,\r
1251 Port,\r
1252 0,\r
1253 Timeout\r
1254 );\r
64e25d4b
AM
1255 if (!EFI_ERROR (Status)) {\r
1256 Task->IsStart = TRUE;\r
1257 }\r
1258 }\r
1436aea4 1259\r
64e25d4b
AM
1260 if (Task->IsStart) {\r
1261 Status = AhciCheckFisReceived (PciIo, Port, SataFisD2H);\r
1262 if (Status == EFI_DEVICE_ERROR) {\r
1263 DEBUG ((DEBUG_ERROR, "DMA command failed at retry: %d\n", Task->RetryTimes));\r
1264 Status = AhciRecoverPortError (PciIo, Port);\r
1265 //\r
1266 // If recovery passed mark the Task as not started and change the status\r
1267 // to EFI_NOT_READY. This will make the higher level call this function again\r
1268 // and on next call the command will be re-issued due to IsStart being FALSE.\r
1269 // This also makes the next condition decrement the RetryTimes.\r
1270 //\r
1271 if (Status == EFI_SUCCESS) {\r
1272 Task->IsStart = FALSE;\r
1436aea4 1273 Status = EFI_NOT_READY;\r
64e25d4b
AM
1274 }\r
1275 }\r
a41b5272 1276\r
64e25d4b 1277 if (Status == EFI_NOT_READY) {\r
1436aea4 1278 if (!Task->InfiniteWait && (Task->RetryTimes == 0)) {\r
64e25d4b
AM
1279 Status = EFI_TIMEOUT;\r
1280 } else {\r
1281 Task->RetryTimes--;\r
1282 }\r
1283 }\r
1284 }\r
b465a811
AM
1285 }\r
1286\r
490b5ea1 1287 //\r
1288 // For Blocking mode, the command should be stopped, the Fis should be disabled\r
1289 // and the PciIo should be unmapped.\r
1aff716a 1290 // For non-blocking mode, only when a error is happened (if the return status is\r
1291 // EFI_NOT_READY that means the command doesn't finished, try again.), first do the\r
490b5ea1 1292 // context cleanup, then set the packet's Asb status.\r
1293 //\r
1436aea4 1294 if ((Task == NULL) ||\r
490b5ea1 1295 ((Task != NULL) && (Status != EFI_NOT_READY))\r
1436aea4
MK
1296 )\r
1297 {\r
490b5ea1 1298 AhciStopCommand (\r
1aff716a 1299 PciIo,\r
490b5ea1 1300 Port,\r
1301 Timeout\r
1302 );\r
a41b5272 1303\r
490b5ea1 1304 AhciDisableFisReceive (\r
1aff716a 1305 PciIo,\r
490b5ea1 1306 Port,\r
1307 Timeout\r
1308 );\r
a41b5272 1309\r
490b5ea1 1310 PciIo->Unmap (\r
1311 PciIo,\r
1312 (Task != NULL) ? Task->Map : Map\r
1313 );\r
e519983a 1314\r
490b5ea1 1315 if (Task != NULL) {\r
1316 Task->Packet->Asb->AtaStatus = 0x01;\r
1317 }\r
1318 }\r
1319\r
a7b3f90f 1320 AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
91d95113
AM
1321\r
1322 if (Status == EFI_DEVICE_ERROR) {\r
1323 DEBUG ((DEBUG_ERROR, "Failed to execute command for DMA transfer:\n"));\r
1324 //\r
1325 // Repeat command block here to make sure it is printed on\r
1326 // device error debug level.\r
1327 //\r
1328 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_ERROR);\r
1329 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_ERROR);\r
1330 } else {\r
1331 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_VERBOSE);\r
1332 }\r
1333\r
a41b5272 1334 return Status;\r
1335}\r
1336\r
1337/**\r
1338 Start a non data transfer on specific port.\r
1aff716a 1339\r
490b5ea1 1340 @param[in] PciIo The PCI IO protocol instance.\r
1341 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1342 @param[in] Port The number of port.\r
1343 @param[in] PortMultiplier The timeout value of stop.\r
1344 @param[in] AtapiCommand The atapi command will be used for the\r
1345 transfer.\r
1346 @param[in] AtapiCommandLength The length of the atapi command.\r
1347 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
1348 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
8536cc4b 1349 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 1350 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1351 used by non-blocking mode.\r
a41b5272 1352\r
1353 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.\r
1354 @retval EFI_TIMEOUT The operation is time out.\r
1355 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
1356 @retval EFI_SUCCESS The non data transfer executes successfully.\r
1357\r
1aff716a 1358**/\r
a41b5272 1359EFI_STATUS\r
1360EFIAPI\r
1361AhciNonDataTransfer (\r
1436aea4
MK
1362 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1363 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1364 IN UINT8 Port,\r
1365 IN UINT8 PortMultiplier,\r
1366 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
1367 IN UINT8 AtapiCommandLength,\r
1368 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
1369 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
1370 IN UINT64 Timeout,\r
1371 IN ATA_NONBLOCK_TASK *Task\r
490b5ea1 1372 )\r
a41b5272 1373{\r
1436aea4
MK
1374 EFI_STATUS Status;\r
1375 EFI_AHCI_COMMAND_FIS CFis;\r
1376 EFI_AHCI_COMMAND_LIST CmdList;\r
1377 UINT32 Retry;\r
a41b5272 1378\r
1379 //\r
1380 // Package read needed\r
1381 //\r
1382 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
1383\r
1384 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
1385\r
1386 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
1387\r
64e25d4b
AM
1388 for (Retry = 0; Retry < AHCI_COMMAND_RETRIES; Retry++) {\r
1389 AhciBuildCommand (\r
1390 PciIo,\r
1391 AhciRegisters,\r
1392 Port,\r
1393 PortMultiplier,\r
1394 &CFis,\r
1395 &CmdList,\r
1396 AtapiCommand,\r
1397 AtapiCommandLength,\r
1398 0,\r
1399 NULL,\r
1400 0\r
1401 );\r
490b5ea1 1402\r
91d95113
AM
1403 DEBUG ((DEBUG_VERBOSE, "Starting command for non data transfer:\n"));\r
1404 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_VERBOSE);\r
64e25d4b 1405 Status = AhciStartCommand (\r
1436aea4
MK
1406 PciIo,\r
1407 Port,\r
1408 0,\r
1409 Timeout\r
1410 );\r
64e25d4b
AM
1411 if (EFI_ERROR (Status)) {\r
1412 break;\r
1413 }\r
490b5ea1 1414\r
64e25d4b
AM
1415 Status = AhciWaitUntilFisReceived (PciIo, Port, Timeout, SataFisD2H);\r
1416 if (Status == EFI_DEVICE_ERROR) {\r
1417 DEBUG ((DEBUG_ERROR, "Non data transfer failed at retry %d\n", Retry));\r
1418 Status = AhciRecoverPortError (PciIo, Port);\r
1419 if (EFI_ERROR (Status)) {\r
1420 break;\r
1421 }\r
1422 } else {\r
1423 break;\r
1424 }\r
b465a811 1425 }\r
490b5ea1 1426\r
a41b5272 1427 AhciStopCommand (\r
490b5ea1 1428 PciIo,\r
a41b5272 1429 Port,\r
1430 Timeout\r
1431 );\r
1432\r
1433 AhciDisableFisReceive (\r
490b5ea1 1434 PciIo,\r
a41b5272 1435 Port,\r
1436 Timeout\r
1437 );\r
1438\r
a7b3f90f 1439 AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
e519983a 1440\r
91d95113
AM
1441 if (Status == EFI_DEVICE_ERROR) {\r
1442 DEBUG ((DEBUG_ERROR, "Failed to execute command for non data transfer:\n"));\r
1443 //\r
1444 // Repeat command block here to make sure it is printed on\r
1445 // device error debug level.\r
1446 //\r
1447 AhciPrintCommandBlock (AtaCommandBlock, DEBUG_ERROR);\r
1448 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_ERROR);\r
1449 } else {\r
1450 AhciPrintStatusBlock (AtaStatusBlock, DEBUG_VERBOSE);\r
1451 }\r
1452\r
a41b5272 1453 return Status;\r
1454}\r
1455\r
1456/**\r
1457 Stop command running for giving port\r
1aff716a 1458\r
a41b5272 1459 @param PciIo The PCI IO protocol instance.\r
1460 @param Port The number of port.\r
8536cc4b 1461 @param Timeout The timeout value of stop, uses 100ns as a unit.\r
1aff716a 1462\r
a41b5272 1463 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.\r
1464 @retval EFI_TIMEOUT The operation is time out.\r
1465 @retval EFI_SUCCESS The command stop successfully.\r
1466\r
1467**/\r
1468EFI_STATUS\r
1469EFIAPI\r
1470AhciStopCommand (\r
1436aea4
MK
1471 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1472 IN UINT8 Port,\r
1473 IN UINT64 Timeout\r
a41b5272 1474 )\r
1475{\r
1436aea4
MK
1476 UINT32 Offset;\r
1477 UINT32 Data;\r
a41b5272 1478\r
1479 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1480 Data = AhciReadReg (PciIo, Offset);\r
1481\r
1482 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {\r
490b5ea1 1483 return EFI_SUCCESS;\r
a41b5272 1484 }\r
1485\r
1486 if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
1436aea4 1487 AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_ST));\r
a41b5272 1488 }\r
1489\r
8536cc4b 1490 return AhciWaitMmioSet (\r
490b5ea1 1491 PciIo,\r
a41b5272 1492 Offset,\r
1493 EFI_AHCI_PORT_CMD_CR,\r
1494 0,\r
1495 Timeout\r
490b5ea1 1496 );\r
a41b5272 1497}\r
1498\r
1499/**\r
1500 Start command for give slot on specific port.\r
490b5ea1 1501\r
a41b5272 1502 @param PciIo The PCI IO protocol instance.\r
1503 @param Port The number of port.\r
490b5ea1 1504 @param CommandSlot The number of Command Slot.\r
8536cc4b 1505 @param Timeout The timeout value of start, uses 100ns as a unit.\r
490b5ea1 1506\r
a41b5272 1507 @retval EFI_DEVICE_ERROR The command start unsuccessfully.\r
1508 @retval EFI_TIMEOUT The operation is time out.\r
1509 @retval EFI_SUCCESS The command start successfully.\r
1510\r
1511**/\r
1512EFI_STATUS\r
1513EFIAPI\r
1514AhciStartCommand (\r
1436aea4
MK
1515 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1516 IN UINT8 Port,\r
1517 IN UINT8 CommandSlot,\r
1518 IN UINT64 Timeout\r
a41b5272 1519 )\r
1520{\r
1436aea4
MK
1521 UINT32 CmdSlotBit;\r
1522 EFI_STATUS Status;\r
1523 UINT32 PortStatus;\r
1524 UINT32 StartCmd;\r
1525 UINT32 PortTfd;\r
1526 UINT32 Offset;\r
1527 UINT32 Capability;\r
a41b5272 1528\r
1529 //\r
1530 // Collect AHCI controller information\r
1531 //\r
1436aea4 1532 Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
a41b5272 1533\r
1436aea4 1534 CmdSlotBit = (UINT32)(1 << CommandSlot);\r
a41b5272 1535\r
1536 AhciClearPortStatus (\r
1537 PciIo,\r
1538 Port\r
1539 );\r
1540\r
1541 Status = AhciEnableFisReceive (\r
1aff716a 1542 PciIo,\r
a41b5272 1543 Port,\r
1544 Timeout\r
1545 );\r
490b5ea1 1546\r
a41b5272 1547 if (EFI_ERROR (Status)) {\r
1548 return Status;\r
1549 }\r
1550\r
1436aea4 1551 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
a41b5272 1552 PortStatus = AhciReadReg (PciIo, Offset);\r
490b5ea1 1553\r
a41b5272 1554 StartCmd = 0;\r
1555 if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
1436aea4 1556 StartCmd = AhciReadReg (PciIo, Offset);\r
a41b5272 1557 StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;\r
1558 StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;\r
1559 }\r
1560\r
1436aea4 1561 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
a41b5272 1562 PortTfd = AhciReadReg (PciIo, Offset);\r
1563\r
1564 if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
1565 if ((Capability & BIT24) != 0) {\r
1566 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
cbd2a4b3 1567 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);\r
a41b5272 1568\r
8536cc4b 1569 AhciWaitMmioSet (\r
490b5ea1 1570 PciIo,\r
a41b5272 1571 Offset,\r
cbd2a4b3 1572 EFI_AHCI_PORT_CMD_CLO,\r
a41b5272 1573 0,\r
1574 Timeout\r
490b5ea1 1575 );\r
a41b5272 1576 }\r
1577 }\r
1578\r
1579 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1580 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);\r
1581\r
e519983a 1582 //\r
1583 // Setting the command\r
1584 //\r
e519983a 1585 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
1586 AhciAndReg (PciIo, Offset, 0);\r
1587 AhciOrReg (PciIo, Offset, CmdSlotBit);\r
1588\r
a41b5272 1589 return EFI_SUCCESS;\r
1590}\r
1591\r
a41b5272 1592/**\r
1593 Do AHCI HBA reset.\r
490b5ea1 1594\r
a41b5272 1595 @param PciIo The PCI IO protocol instance.\r
8536cc4b 1596 @param Timeout The timeout value of reset, uses 100ns as a unit.\r
490b5ea1 1597\r
a41b5272 1598 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.\r
1599 @retval EFI_TIMEOUT The reset operation is time out.\r
1600 @retval EFI_SUCCESS AHCI controller is reset successfully.\r
1601\r
1602**/\r
1603EFI_STATUS\r
1604EFIAPI\r
1605AhciReset (\r
1436aea4
MK
1606 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1607 IN UINT64 Timeout\r
1aff716a 1608 )\r
a41b5272 1609{\r
1436aea4
MK
1610 UINT64 Delay;\r
1611 UINT32 Value;\r
a41b5272 1612\r
1ff1dd0f 1613 //\r
6052a15f 1614 // Make sure that GHC.AE bit is set before accessing any AHCI registers.\r
1ff1dd0f 1615 //\r
1436aea4 1616 Value = AhciReadReg (PciIo, EFI_AHCI_GHC_OFFSET);\r
6052a15f
MW
1617\r
1618 if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
1ff1dd0f
FT
1619 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
1620 }\r
a41b5272 1621\r
1622 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
1623\r
1436aea4 1624 Delay = DivU64x32 (Timeout, 1000) + 1;\r
a41b5272 1625\r
1626 do {\r
1436aea4 1627 Value = AhciReadReg (PciIo, EFI_AHCI_GHC_OFFSET);\r
a41b5272 1628\r
1629 if ((Value & EFI_AHCI_GHC_RESET) == 0) {\r
1630 break;\r
1631 }\r
1632\r
1633 //\r
1634 // Stall for 100 microseconds.\r
1635 //\r
1436aea4 1636 MicroSecondDelay (100);\r
a41b5272 1637\r
1638 Delay--;\r
1639 } while (Delay > 0);\r
1640\r
1641 if (Delay == 0) {\r
1642 return EFI_TIMEOUT;\r
1643 }\r
1644\r
1645 return EFI_SUCCESS;\r
1646}\r
1647\r
12873d57 1648/**\r
1649 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
1650\r
1651 @param PciIo The PCI IO protocol instance.\r
1652 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1653 @param Port The number of port.\r
79992d6e 1654 @param PortMultiplier The port multiplier port number.\r
12873d57 1655 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1656\r
1657 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.\r
1658 @retval Others Fail to get return status data.\r
1659\r
1660**/\r
1661EFI_STATUS\r
1662EFIAPI\r
1663AhciAtaSmartReturnStatusCheck (\r
1436aea4
MK
1664 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1665 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1666 IN UINT8 Port,\r
1667 IN UINT8 PortMultiplier,\r
1668 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
12873d57 1669 )\r
1670{\r
1436aea4
MK
1671 EFI_STATUS Status;\r
1672 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1673 UINT8 LBAMid;\r
1674 UINT8 LBAHigh;\r
1675 UINTN FisBaseAddr;\r
1676 UINT32 Value;\r
12873d57 1677\r
1678 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1679\r
1680 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1681 AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;\r
1682 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1683 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1684\r
1685 //\r
1686 // Send S.M.A.R.T Read Return Status command to device\r
1687 //\r
1688 Status = AhciNonDataTransfer (\r
1689 PciIo,\r
1690 AhciRegisters,\r
1691 (UINT8)Port,\r
1692 (UINT8)PortMultiplier,\r
1693 NULL,\r
1694 0,\r
1695 &AtaCommandBlock,\r
1696 AtaStatusBlock,\r
490b5ea1 1697 ATA_ATAPI_TIMEOUT,\r
1698 NULL\r
12873d57 1699 );\r
1700\r
1701 if (EFI_ERROR (Status)) {\r
cffd2171
EL
1702 REPORT_STATUS_CODE (\r
1703 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
1704 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
1705 );\r
12873d57 1706 return EFI_DEVICE_ERROR;\r
1707 }\r
1708\r
cffd2171
EL
1709 REPORT_STATUS_CODE (\r
1710 EFI_PROGRESS_CODE,\r
1711 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
1712 );\r
1713\r
12873d57 1714 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1715\r
1436aea4 1716 Value = *(UINT32 *)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
12873d57 1717\r
1718 if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
1719 LBAMid = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];\r
1720 LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];\r
1721\r
1722 if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
1723 //\r
1724 // The threshold exceeded condition is not detected by the device\r
1725 //\r
87000d77 1726 DEBUG ((DEBUG_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
cffd2171 1727 REPORT_STATUS_CODE (\r
1436aea4
MK
1728 EFI_PROGRESS_CODE,\r
1729 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
1730 );\r
12873d57 1731 } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
1732 //\r
1733 // The threshold exceeded condition is detected by the device\r
1734 //\r
87000d77 1735 DEBUG ((DEBUG_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
cffd2171 1736 REPORT_STATUS_CODE (\r
1436aea4
MK
1737 EFI_PROGRESS_CODE,\r
1738 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
1739 );\r
12873d57 1740 }\r
1741 }\r
1742\r
1743 return EFI_SUCCESS;\r
1744}\r
1745\r
1746/**\r
1747 Enable SMART command of the disk if supported.\r
1748\r
1749 @param PciIo The PCI IO protocol instance.\r
1750 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1751 @param Port The number of port.\r
79992d6e 1752 @param PortMultiplier The port multiplier port number.\r
12873d57 1753 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
1754 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1755\r
1756**/\r
1757VOID\r
1758EFIAPI\r
1759AhciAtaSmartSupport (\r
1436aea4
MK
1760 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1761 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1762 IN UINT8 Port,\r
1763 IN UINT8 PortMultiplier,\r
1764 IN EFI_IDENTIFY_DATA *IdentifyData,\r
1765 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
12873d57 1766 )\r
1767{\r
1436aea4
MK
1768 EFI_STATUS Status;\r
1769 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
12873d57 1770\r
1771 //\r
1772 // Detect if the device supports S.M.A.R.T.\r
1773 //\r
1774 if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
1775 //\r
1776 // S.M.A.R.T is not supported by the device\r
1777 //\r
1436aea4
MK
1778 DEBUG ((\r
1779 DEBUG_INFO,\r
1780 "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",\r
1781 Port,\r
1782 PortMultiplier\r
1783 ));\r
cffd2171
EL
1784 REPORT_STATUS_CODE (\r
1785 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
1786 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
1787 );\r
12873d57 1788 } else {\r
1789 //\r
1790 // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
1791 //\r
1792 if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
cffd2171
EL
1793 REPORT_STATUS_CODE (\r
1794 EFI_PROGRESS_CODE,\r
1795 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)\r
1796 );\r
1797\r
12873d57 1798 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1799\r
1800 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1801 AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;\r
1802 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1803 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1804\r
1805 //\r
1806 // Send S.M.A.R.T Enable command to device\r
1807 //\r
1808 Status = AhciNonDataTransfer (\r
1809 PciIo,\r
1810 AhciRegisters,\r
1811 (UINT8)Port,\r
1812 (UINT8)PortMultiplier,\r
1813 NULL,\r
1814 0,\r
1815 &AtaCommandBlock,\r
1816 AtaStatusBlock,\r
490b5ea1 1817 ATA_ATAPI_TIMEOUT,\r
1818 NULL\r
12873d57 1819 );\r
1820\r
12873d57 1821 if (!EFI_ERROR (Status)) {\r
1822 //\r
1823 // Send S.M.A.R.T AutoSave command to device\r
1824 //\r
1825 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1826\r
1827 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1828 AtaCommandBlock.AtaFeatures = 0xD2;\r
1829 AtaCommandBlock.AtaSectorCount = 0xF1;\r
1830 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1831 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1832\r
1833 Status = AhciNonDataTransfer (\r
1834 PciIo,\r
1835 AhciRegisters,\r
1836 (UINT8)Port,\r
1837 (UINT8)PortMultiplier,\r
1838 NULL,\r
1839 0,\r
1840 &AtaCommandBlock,\r
1841 AtaStatusBlock,\r
490b5ea1 1842 ATA_ATAPI_TIMEOUT,\r
1843 NULL\r
12873d57 1844 );\r
12873d57 1845 }\r
1846 }\r
c9742578
LG
1847\r
1848 AhciAtaSmartReturnStatusCheck (\r
1849 PciIo,\r
1850 AhciRegisters,\r
1851 (UINT8)Port,\r
1852 (UINT8)PortMultiplier,\r
1853 AtaStatusBlock\r
1854 );\r
1855\r
1436aea4
MK
1856 DEBUG ((\r
1857 DEBUG_INFO,\r
1858 "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",\r
1859 Port,\r
1860 PortMultiplier\r
1861 ));\r
12873d57 1862 }\r
1863\r
1436aea4 1864 return;\r
12873d57 1865}\r
1866\r
a41b5272 1867/**\r
1868 Send Buffer cmd to specific device.\r
1aff716a 1869\r
aca84419 1870 @param PciIo The PCI IO protocol instance.\r
1871 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1872 @param Port The number of port.\r
79992d6e 1873 @param PortMultiplier The port multiplier port number.\r
aca84419 1874 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1875\r
1876 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1877 @retval EFI_TIMEOUT The operation is time out.\r
1878 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1879 @retval EFI_SUCCESS The cmd executes successfully.\r
1880\r
1881**/\r
1882EFI_STATUS\r
1883EFIAPI\r
1884AhciIdentify (\r
1436aea4
MK
1885 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1886 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1887 IN UINT8 Port,\r
1888 IN UINT8 PortMultiplier,\r
1889 IN OUT EFI_IDENTIFY_DATA *Buffer\r
a41b5272 1890 )\r
1891{\r
1436aea4
MK
1892 EFI_STATUS Status;\r
1893 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1894 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
a41b5272 1895\r
1436aea4 1896 if ((PciIo == NULL) || (AhciRegisters == NULL) || (Buffer == NULL)) {\r
a41b5272 1897 return EFI_INVALID_PARAMETER;\r
1898 }\r
1899\r
1900 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1901 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 1902\r
a41b5272 1903 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
1904 AtaCommandBlock.AtaSectorCount = 1;\r
1905\r
1906 Status = AhciPioTransfer (\r
1907 PciIo,\r
1908 AhciRegisters,\r
1909 Port,\r
1910 PortMultiplier,\r
1911 NULL,\r
1912 0,\r
1913 TRUE,\r
1914 &AtaCommandBlock,\r
1915 &AtaStatusBlock,\r
1916 Buffer,\r
1917 sizeof (EFI_IDENTIFY_DATA),\r
1aff716a 1918 ATA_ATAPI_TIMEOUT,\r
490b5ea1 1919 NULL\r
a41b5272 1920 );\r
1921\r
1922 return Status;\r
1923}\r
1924\r
1925/**\r
1926 Send Buffer cmd to specific device.\r
1aff716a 1927\r
aca84419 1928 @param PciIo The PCI IO protocol instance.\r
1929 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1930 @param Port The number of port.\r
79992d6e 1931 @param PortMultiplier The port multiplier port number.\r
aca84419 1932 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1933\r
1934 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1935 @retval EFI_TIMEOUT The operation is time out.\r
1936 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1937 @retval EFI_SUCCESS The cmd executes successfully.\r
1938\r
1939**/\r
1940EFI_STATUS\r
1941EFIAPI\r
1942AhciIdentifyPacket (\r
1436aea4
MK
1943 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1944 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1945 IN UINT8 Port,\r
1946 IN UINT8 PortMultiplier,\r
1947 IN OUT EFI_IDENTIFY_DATA *Buffer\r
a41b5272 1948 )\r
1949{\r
1436aea4
MK
1950 EFI_STATUS Status;\r
1951 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1952 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
a41b5272 1953\r
1436aea4 1954 if ((PciIo == NULL) || (AhciRegisters == NULL)) {\r
a41b5272 1955 return EFI_INVALID_PARAMETER;\r
1956 }\r
490b5ea1 1957\r
a41b5272 1958 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1959 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1960\r
1961 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DEVICE;\r
1962 AtaCommandBlock.AtaSectorCount = 1;\r
1963\r
1964 Status = AhciPioTransfer (\r
1965 PciIo,\r
1966 AhciRegisters,\r
1967 Port,\r
1968 PortMultiplier,\r
1969 NULL,\r
1970 0,\r
1971 TRUE,\r
1972 &AtaCommandBlock,\r
1973 &AtaStatusBlock,\r
1974 Buffer,\r
1975 sizeof (EFI_IDENTIFY_DATA),\r
490b5ea1 1976 ATA_ATAPI_TIMEOUT,\r
1977 NULL\r
a41b5272 1978 );\r
1979\r
1980 return Status;\r
1981}\r
1982\r
1983/**\r
1984 Send SET FEATURE cmd on specific device.\r
1aff716a 1985\r
aca84419 1986 @param PciIo The PCI IO protocol instance.\r
1987 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1988 @param Port The number of port.\r
79992d6e 1989 @param PortMultiplier The port multiplier port number.\r
aca84419 1990 @param Feature The data to send Feature register.\r
1991 @param FeatureSpecificData The specific data for SET FEATURE cmd.\r
8d3c4b55 1992 @param Timeout The timeout value of SET FEATURE cmd, uses 100ns as a unit.\r
a41b5272 1993\r
1994 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1995 @retval EFI_TIMEOUT The operation is time out.\r
1996 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1997 @retval EFI_SUCCESS The cmd executes successfully.\r
1998\r
1999**/\r
2000EFI_STATUS\r
2001EFIAPI\r
2002AhciDeviceSetFeature (\r
1436aea4
MK
2003 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2004 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2005 IN UINT8 Port,\r
2006 IN UINT8 PortMultiplier,\r
2007 IN UINT16 Feature,\r
2008 IN UINT32 FeatureSpecificData,\r
2009 IN UINT64 Timeout\r
a41b5272 2010 )\r
2011{\r
1436aea4
MK
2012 EFI_STATUS Status;\r
2013 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2014 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
a41b5272 2015\r
2016 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2017 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 2018\r
a41b5272 2019 AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;\r
1436aea4
MK
2020 AtaCommandBlock.AtaFeatures = (UINT8)Feature;\r
2021 AtaCommandBlock.AtaFeaturesExp = (UINT8)(Feature >> 8);\r
2022 AtaCommandBlock.AtaSectorCount = (UINT8)FeatureSpecificData;\r
2023 AtaCommandBlock.AtaSectorNumber = (UINT8)(FeatureSpecificData >> 8);\r
2024 AtaCommandBlock.AtaCylinderLow = (UINT8)(FeatureSpecificData >> 16);\r
2025 AtaCommandBlock.AtaCylinderHigh = (UINT8)(FeatureSpecificData >> 24);\r
a41b5272 2026\r
2027 Status = AhciNonDataTransfer (\r
2028 PciIo,\r
2029 AhciRegisters,\r
2030 (UINT8)Port,\r
2031 (UINT8)PortMultiplier,\r
2032 NULL,\r
2033 0,\r
2034 &AtaCommandBlock,\r
2035 &AtaStatusBlock,\r
8d3c4b55 2036 Timeout,\r
490b5ea1 2037 NULL\r
a41b5272 2038 );\r
2039\r
2040 return Status;\r
2041}\r
2042\r
2043/**\r
1aff716a 2044 This function is used to send out ATAPI commands conforms to the Packet Command\r
a41b5272 2045 with PIO Protocol.\r
2046\r
2047 @param PciIo The PCI IO protocol instance.\r
2048 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1aff716a 2049 @param Port The number of port.\r
a41b5272 2050 @param PortMultiplier The number of port multiplier.\r
2051 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.\r
2052\r
2053 @retval EFI_SUCCESS send out the ATAPI packet command successfully\r
2054 and device sends data successfully.\r
2055 @retval EFI_DEVICE_ERROR the device failed to send data.\r
2056\r
2057**/\r
2058EFI_STATUS\r
2059EFIAPI\r
2060AhciPacketCommandExecute (\r
1436aea4
MK
2061 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2062 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2063 IN UINT8 Port,\r
2064 IN UINT8 PortMultiplier,\r
2065 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
a41b5272 2066 )\r
2067{\r
1436aea4
MK
2068 EFI_STATUS Status;\r
2069 VOID *Buffer;\r
2070 UINT32 Length;\r
2071 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2072 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
2073 BOOLEAN Read;\r
2074\r
2075 if ((Packet == NULL) || (Packet->Cdb == NULL)) {\r
a41b5272 2076 return EFI_INVALID_PARAMETER;\r
2077 }\r
2078\r
2079 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2080 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1436aea4 2081 AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;\r
a41b5272 2082 //\r
2083 // No OVL; No DMA\r
2084 //\r
1436aea4 2085 AtaCommandBlock.AtaFeatures = 0x00;\r
a41b5272 2086 //\r
2087 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
2088 // determine how many data should be transferred.\r
2089 //\r
1436aea4
MK
2090 AtaCommandBlock.AtaCylinderLow = (UINT8)(ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
2091 AtaCommandBlock.AtaCylinderHigh = (UINT8)(ATAPI_MAX_BYTE_COUNT >> 8);\r
a41b5272 2092\r
2093 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
2094 Buffer = Packet->InDataBuffer;\r
2095 Length = Packet->InTransferLength;\r
1436aea4 2096 Read = TRUE;\r
a41b5272 2097 } else {\r
2098 Buffer = Packet->OutDataBuffer;\r
2099 Length = Packet->OutTransferLength;\r
1436aea4 2100 Read = FALSE;\r
a41b5272 2101 }\r
2102\r
490b5ea1 2103 if (Length == 0) {\r
a41b5272 2104 Status = AhciNonDataTransfer (\r
2105 PciIo,\r
2106 AhciRegisters,\r
2107 Port,\r
2108 PortMultiplier,\r
2109 Packet->Cdb,\r
2110 Packet->CdbLength,\r
2111 &AtaCommandBlock,\r
2112 &AtaStatusBlock,\r
1aff716a 2113 Packet->Timeout,\r
490b5ea1 2114 NULL\r
a41b5272 2115 );\r
2116 } else {\r
cbd2a4b3 2117 Status = AhciPioTransfer (\r
2118 PciIo,\r
2119 AhciRegisters,\r
2120 Port,\r
2121 PortMultiplier,\r
2122 Packet->Cdb,\r
2123 Packet->CdbLength,\r
2124 Read,\r
2125 &AtaCommandBlock,\r
2126 &AtaStatusBlock,\r
2127 Buffer,\r
2128 Length,\r
1aff716a 2129 Packet->Timeout,\r
cbd2a4b3 2130 NULL\r
2131 );\r
a41b5272 2132 }\r
1436aea4 2133\r
a41b5272 2134 return Status;\r
2135}\r
2136\r
2137/**\r
2138 Allocate transfer-related data struct which is used at AHCI mode.\r
1aff716a 2139\r
a41b5272 2140 @param PciIo The PCI IO protocol instance.\r
2141 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
2142\r
2143**/\r
2144EFI_STATUS\r
2145EFIAPI\r
2146AhciCreateTransferDescriptor (\r
1436aea4
MK
2147 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2148 IN OUT EFI_AHCI_REGISTERS *AhciRegisters\r
a41b5272 2149 )\r
2150{\r
1436aea4
MK
2151 EFI_STATUS Status;\r
2152 UINTN Bytes;\r
2153 VOID *Buffer;\r
a41b5272 2154\r
2155 UINT32 Capability;\r
467cacbf 2156 UINT32 PortImplementBitMap;\r
a41b5272 2157 UINT8 MaxPortNumber;\r
2158 UINT8 MaxCommandSlotNumber;\r
2159 BOOLEAN Support64Bit;\r
2160 UINT64 MaxReceiveFisSize;\r
2161 UINT64 MaxCommandListSize;\r
2162 UINT64 MaxCommandTableSize;\r
ed365e93 2163 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr;\r
2164 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr;\r
2165 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr;\r
a41b5272 2166\r
2167 Buffer = NULL;\r
2168 //\r
2169 // Collect AHCI controller information\r
2170 //\r
1436aea4 2171 Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
a41b5272 2172 //\r
2173 // Get the number of command slots per port supported by this HBA.\r
2174 //\r
1436aea4
MK
2175 MaxCommandSlotNumber = (UINT8)(((Capability & 0x1F00) >> 8) + 1);\r
2176 Support64Bit = (BOOLEAN)(((Capability & BIT31) != 0) ? TRUE : FALSE);\r
d1102dba 2177\r
1436aea4 2178 PortImplementBitMap = AhciReadReg (PciIo, EFI_AHCI_PI_OFFSET);\r
467cacbf 2179 //\r
8c39253d 2180 // Get the highest bit of implemented ports which decides how many bytes are allocated for received FIS.\r
467cacbf 2181 //\r
1436aea4 2182 MaxPortNumber = (UINT8)(UINTN)(HighBitSet32 (PortImplementBitMap) + 1);\r
467cacbf 2183 if (MaxPortNumber == 0) {\r
2184 return EFI_DEVICE_ERROR;\r
2185 }\r
a41b5272 2186\r
1436aea4
MK
2187 MaxReceiveFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
2188 Status = PciIo->AllocateBuffer (\r
2189 PciIo,\r
2190 AllocateAnyPages,\r
2191 EfiBootServicesData,\r
2192 EFI_SIZE_TO_PAGES ((UINTN)MaxReceiveFisSize),\r
2193 &Buffer,\r
2194 0\r
2195 );\r
a41b5272 2196\r
2197 if (EFI_ERROR (Status)) {\r
2198 return EFI_OUT_OF_RESOURCES;\r
2199 }\r
2200\r
5dec0c68 2201 ZeroMem (Buffer, (UINTN)MaxReceiveFisSize);\r
a41b5272 2202\r
2203 AhciRegisters->AhciRFis = Buffer;\r
2204 AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;\r
1436aea4 2205 Bytes = (UINTN)MaxReceiveFisSize;\r
a41b5272 2206\r
2207 Status = PciIo->Map (\r
2208 PciIo,\r
2209 EfiPciIoOperationBusMasterCommonBuffer,\r
2210 Buffer,\r
2211 &Bytes,\r
ed365e93 2212 &AhciRFisPciAddr,\r
a41b5272 2213 &AhciRegisters->MapRFis\r
2214 );\r
2215\r
2216 if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {\r
2217 //\r
1aff716a 2218 // Map error or unable to map the whole RFis buffer into a contiguous region.\r
a41b5272 2219 //\r
2220 Status = EFI_OUT_OF_RESOURCES;\r
2221 goto Error6;\r
2222 }\r
2223\r
ed365e93 2224 if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {\r
a41b5272 2225 //\r
2226 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2227 //\r
2228 Status = EFI_DEVICE_ERROR;\r
2229 goto Error5;\r
2230 }\r
1436aea4 2231\r
ed365e93 2232 AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;\r
a41b5272 2233\r
2234 //\r
2235 // Allocate memory for command list\r
8c39253d 2236 // Note that the implementation is a single task model which only use a command list for all ports.\r
a41b5272 2237 //\r
1436aea4 2238 Buffer = NULL;\r
a41b5272 2239 MaxCommandListSize = MaxCommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST);\r
1436aea4
MK
2240 Status = PciIo->AllocateBuffer (\r
2241 PciIo,\r
2242 AllocateAnyPages,\r
2243 EfiBootServicesData,\r
2244 EFI_SIZE_TO_PAGES ((UINTN)MaxCommandListSize),\r
2245 &Buffer,\r
2246 0\r
2247 );\r
a41b5272 2248\r
2249 if (EFI_ERROR (Status)) {\r
2250 //\r
1aff716a 2251 // Free mapped resource.\r
a41b5272 2252 //\r
2253 Status = EFI_OUT_OF_RESOURCES;\r
2254 goto Error5;\r
2255 }\r
2256\r
5dec0c68 2257 ZeroMem (Buffer, (UINTN)MaxCommandListSize);\r
a41b5272 2258\r
2259 AhciRegisters->AhciCmdList = Buffer;\r
2260 AhciRegisters->MaxCommandListSize = MaxCommandListSize;\r
1436aea4 2261 Bytes = (UINTN)MaxCommandListSize;\r
a41b5272 2262\r
2263 Status = PciIo->Map (\r
2264 PciIo,\r
2265 EfiPciIoOperationBusMasterCommonBuffer,\r
2266 Buffer,\r
2267 &Bytes,\r
ed365e93 2268 &AhciCmdListPciAddr,\r
a41b5272 2269 &AhciRegisters->MapCmdList\r
2270 );\r
2271\r
2272 if (EFI_ERROR (Status) || (Bytes != MaxCommandListSize)) {\r
2273 //\r
2274 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2275 //\r
2276 Status = EFI_OUT_OF_RESOURCES;\r
2277 goto Error4;\r
2278 }\r
2279\r
ed365e93 2280 if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {\r
a41b5272 2281 //\r
2282 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2283 //\r
2284 Status = EFI_DEVICE_ERROR;\r
2285 goto Error3;\r
2286 }\r
1436aea4 2287\r
ed365e93 2288 AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;\r
a41b5272 2289\r
2290 //\r
2291 // Allocate memory for command table\r
2292 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.\r
2293 //\r
1436aea4 2294 Buffer = NULL;\r
a41b5272 2295 MaxCommandTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);\r
2296\r
2297 Status = PciIo->AllocateBuffer (\r
2298 PciIo,\r
2299 AllocateAnyPages,\r
2300 EfiBootServicesData,\r
1436aea4 2301 EFI_SIZE_TO_PAGES ((UINTN)MaxCommandTableSize),\r
a41b5272 2302 &Buffer,\r
2303 0\r
2304 );\r
2305\r
2306 if (EFI_ERROR (Status)) {\r
2307 //\r
1aff716a 2308 // Free mapped resource.\r
a41b5272 2309 //\r
2310 Status = EFI_OUT_OF_RESOURCES;\r
2311 goto Error3;\r
2312 }\r
2313\r
5dec0c68 2314 ZeroMem (Buffer, (UINTN)MaxCommandTableSize);\r
a41b5272 2315\r
2316 AhciRegisters->AhciCommandTable = Buffer;\r
2317 AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;\r
1436aea4 2318 Bytes = (UINTN)MaxCommandTableSize;\r
a41b5272 2319\r
2320 Status = PciIo->Map (\r
2321 PciIo,\r
2322 EfiPciIoOperationBusMasterCommonBuffer,\r
2323 Buffer,\r
2324 &Bytes,\r
ed365e93 2325 &AhciCommandTablePciAddr,\r
a41b5272 2326 &AhciRegisters->MapCommandTable\r
2327 );\r
2328\r
2329 if (EFI_ERROR (Status) || (Bytes != MaxCommandTableSize)) {\r
2330 //\r
2331 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2332 //\r
2333 Status = EFI_OUT_OF_RESOURCES;\r
2334 goto Error2;\r
2335 }\r
2336\r
ed365e93 2337 if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {\r
a41b5272 2338 //\r
2339 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2340 //\r
2341 Status = EFI_DEVICE_ERROR;\r
2342 goto Error1;\r
2343 }\r
1436aea4 2344\r
ed365e93 2345 AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;\r
a41b5272 2346\r
2347 return EFI_SUCCESS;\r
2348 //\r
1aff716a 2349 // Map error or unable to map the whole CmdList buffer into a contiguous region.\r
a41b5272 2350 //\r
2351Error1:\r
2352 PciIo->Unmap (\r
2353 PciIo,\r
2354 AhciRegisters->MapCommandTable\r
2355 );\r
2356Error2:\r
2357 PciIo->FreeBuffer (\r
2358 PciIo,\r
1436aea4 2359 EFI_SIZE_TO_PAGES ((UINTN)MaxCommandTableSize),\r
a41b5272 2360 AhciRegisters->AhciCommandTable\r
2361 );\r
2362Error3:\r
2363 PciIo->Unmap (\r
2364 PciIo,\r
2365 AhciRegisters->MapCmdList\r
2366 );\r
2367Error4:\r
2368 PciIo->FreeBuffer (\r
2369 PciIo,\r
1436aea4 2370 EFI_SIZE_TO_PAGES ((UINTN)MaxCommandListSize),\r
a41b5272 2371 AhciRegisters->AhciCmdList\r
2372 );\r
2373Error5:\r
2374 PciIo->Unmap (\r
2375 PciIo,\r
2376 AhciRegisters->MapRFis\r
2377 );\r
2378Error6:\r
2379 PciIo->FreeBuffer (\r
2380 PciIo,\r
1436aea4 2381 EFI_SIZE_TO_PAGES ((UINTN)MaxReceiveFisSize),\r
a41b5272 2382 AhciRegisters->AhciRFis\r
2383 );\r
2384\r
2385 return Status;\r
2386}\r
2387\r
f3100a1a
RN
2388/**\r
2389 Read logs from SATA device.\r
2390\r
2391 @param PciIo The PCI IO protocol instance.\r
2392 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
2393 @param Port The number of port.\r
2394 @param PortMultiplier The multiplier of port.\r
2395 @param Buffer The data buffer to store SATA logs.\r
2396 @param LogNumber The address of the log.\r
2397 @param PageNumber The page number of the log.\r
2398\r
2399 @retval EFI_INVALID_PARAMETER PciIo, AhciRegisters or Buffer is NULL.\r
2400 @retval others Return status of AhciPioTransfer().\r
2401**/\r
2402EFI_STATUS\r
2403AhciReadLogExt (\r
1436aea4
MK
2404 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2405 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2406 IN UINT8 Port,\r
2407 IN UINT8 PortMultiplier,\r
2408 IN OUT UINT8 *Buffer,\r
2409 IN UINT8 LogNumber,\r
2410 IN UINT8 PageNumber\r
f3100a1a
RN
2411 )\r
2412{\r
1436aea4
MK
2413 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2414 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
f3100a1a 2415\r
1436aea4 2416 if ((PciIo == NULL) || (AhciRegisters == NULL) || (Buffer == NULL)) {\r
f3100a1a
RN
2417 return EFI_INVALID_PARAMETER;\r
2418 }\r
2419\r
2420 ///\r
2421 /// Read log from device\r
2422 ///\r
2423 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2424 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
2425 ZeroMem (Buffer, 512);\r
2426\r
2427 AtaCommandBlock.AtaCommand = ATA_CMD_READ_LOG_EXT;\r
2428 AtaCommandBlock.AtaSectorCount = 1;\r
2429 AtaCommandBlock.AtaSectorNumber = LogNumber;\r
2430 AtaCommandBlock.AtaCylinderLow = PageNumber;\r
2431\r
2432 return AhciPioTransfer (\r
2433 PciIo,\r
2434 AhciRegisters,\r
2435 Port,\r
2436 PortMultiplier,\r
2437 NULL,\r
2438 0,\r
2439 TRUE,\r
2440 &AtaCommandBlock,\r
2441 &AtaStatusBlock,\r
2442 Buffer,\r
2443 512,\r
2444 ATA_ATAPI_TIMEOUT,\r
2445 NULL\r
2446 );\r
2447}\r
2448\r
2449/**\r
2450 Enable DEVSLP of the disk if supported.\r
2451\r
2452 @param PciIo The PCI IO protocol instance.\r
2453 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
2454 @param Port The number of port.\r
2455 @param PortMultiplier The multiplier of port.\r
2456 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
2457\r
2458 @retval EFI_SUCCESS The DEVSLP is enabled per policy successfully.\r
2459 @retval EFI_UNSUPPORTED The DEVSLP isn't supported by the controller/device and policy requires to enable it.\r
2460**/\r
2461EFI_STATUS\r
2462AhciEnableDevSlp (\r
1436aea4
MK
2463 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2464 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2465 IN UINT8 Port,\r
2466 IN UINT8 PortMultiplier,\r
2467 IN EFI_IDENTIFY_DATA *IdentifyData\r
f3100a1a
RN
2468 )\r
2469{\r
2470 EFI_STATUS Status;\r
2471 UINT32 Offset;\r
2472 UINT32 Capability2;\r
2473 UINT8 LogData[512];\r
2474 DEVSLP_TIMING_VARIABLES DevSlpTiming;\r
2475 UINT32 PortCmd;\r
2476 UINT32 PortDevSlp;\r
2477\r
2478 if (mAtaAtapiPolicy->DeviceSleepEnable != 1) {\r
2479 return EFI_SUCCESS;\r
2480 }\r
2481\r
2482 //\r
2483 // Do not enable DevSlp if DevSlp is not supported.\r
2484 //\r
2485 Capability2 = AhciReadReg (PciIo, AHCI_CAPABILITY2_OFFSET);\r
2486 DEBUG ((DEBUG_INFO, "AHCI CAPABILITY2 = %08x\n", Capability2));\r
2487 if ((Capability2 & AHCI_CAP2_SDS) == 0) {\r
2488 return EFI_UNSUPPORTED;\r
2489 }\r
2490\r
2491 //\r
2492 // Do not enable DevSlp if DevSlp is not present\r
2493 // Do not enable DevSlp if Hot Plug or Mechanical Presence Switch is supported\r
2494 //\r
2495 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH;\r
2496 PortCmd = AhciReadReg (PciIo, Offset + EFI_AHCI_PORT_CMD);\r
2497 PortDevSlp = AhciReadReg (PciIo, Offset + AHCI_PORT_DEVSLP);\r
2498 DEBUG ((DEBUG_INFO, "Port CMD/DEVSLP = %08x / %08x\n", PortCmd, PortDevSlp));\r
2499 if (((PortDevSlp & AHCI_PORT_DEVSLP_DSP) == 0) ||\r
2500 ((PortCmd & (EFI_AHCI_PORT_CMD_HPCP | EFI_AHCI_PORT_CMD_MPSP)) != 0)\r
1436aea4
MK
2501 )\r
2502 {\r
f3100a1a
RN
2503 return EFI_UNSUPPORTED;\r
2504 }\r
2505\r
2506 //\r
2507 // Do not enable DevSlp if the device doesn't support DevSlp\r
2508 //\r
1436aea4
MK
2509 DEBUG ((\r
2510 DEBUG_INFO,\r
2511 "IDENTIFY DEVICE: [77] = %04x, [78] = %04x, [79] = %04x\n",\r
2512 IdentifyData->AtaData.reserved_77,\r
2513 IdentifyData->AtaData.serial_ata_features_supported,\r
2514 IdentifyData->AtaData.serial_ata_features_enabled\r
2515 ));\r
f3100a1a 2516 if ((IdentifyData->AtaData.serial_ata_features_supported & BIT8) == 0) {\r
1436aea4
MK
2517 DEBUG ((\r
2518 DEBUG_INFO,\r
2519 "DevSlp feature is not supported for device at port [%d] PortMultiplier [%d]!\n",\r
2520 Port,\r
2521 PortMultiplier\r
2522 ));\r
f3100a1a
RN
2523 return EFI_UNSUPPORTED;\r
2524 }\r
2525\r
2526 //\r
2527 // Enable DevSlp when it is not enabled.\r
2528 //\r
2529 if ((IdentifyData->AtaData.serial_ata_features_enabled & BIT8) != 0) {\r
2530 Status = AhciDeviceSetFeature (\r
1436aea4
MK
2531 PciIo,\r
2532 AhciRegisters,\r
2533 Port,\r
2534 0,\r
2535 ATA_SUB_CMD_ENABLE_SATA_FEATURE,\r
2536 0x09,\r
2537 ATA_ATAPI_TIMEOUT\r
2538 );\r
2539 DEBUG ((\r
2540 DEBUG_INFO,\r
2541 "DevSlp set feature for device at port [%d] PortMultiplier [%d] - %r\n",\r
2542 Port,\r
2543 PortMultiplier,\r
2544 Status\r
2545 ));\r
f3100a1a
RN
2546 if (EFI_ERROR (Status)) {\r
2547 return Status;\r
2548 }\r
2549 }\r
2550\r
1436aea4 2551 Status = AhciReadLogExt (PciIo, AhciRegisters, Port, PortMultiplier, LogData, 0x30, 0x08);\r
f3100a1a
RN
2552\r
2553 //\r
2554 // Clear PxCMD.ST and PxDEVSLP.ADSE before updating PxDEVSLP.DITO and PxDEVSLP.MDAT.\r
2555 //\r
2556 AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd & ~EFI_AHCI_PORT_CMD_ST);\r
2557 PortDevSlp &= ~AHCI_PORT_DEVSLP_ADSE;\r
2558 AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
2559\r
2560 //\r
2561 // Set PxDEVSLP.DETO and PxDEVSLP.MDAT to 0.\r
2562 //\r
2563 PortDevSlp &= ~AHCI_PORT_DEVSLP_DETO_MASK;\r
2564 PortDevSlp &= ~AHCI_PORT_DEVSLP_MDAT_MASK;\r
2565 AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
2566 DEBUG ((DEBUG_INFO, "Read Log Ext at port [%d] PortMultiplier [%d] - %r\n", Port, PortMultiplier, Status));\r
2567 if (EFI_ERROR (Status)) {\r
2568 //\r
2569 // Assume DEVSLP TIMING VARIABLES is not supported if the Identify Device Data log (30h, 8) fails\r
2570 //\r
4e738cd4 2571 ZeroMem (&DevSlpTiming, sizeof (DevSlpTiming));\r
f3100a1a
RN
2572 } else {\r
2573 CopyMem (&DevSlpTiming, &LogData[48], sizeof (DevSlpTiming));\r
1436aea4
MK
2574 DEBUG ((\r
2575 DEBUG_INFO,\r
2576 "DevSlpTiming: Supported(%d), Deto(%d), Madt(%d)\n",\r
2577 DevSlpTiming.Supported,\r
2578 DevSlpTiming.Deto,\r
2579 DevSlpTiming.Madt\r
2580 ));\r
f3100a1a
RN
2581 }\r
2582\r
2583 //\r
2584 // Use 20ms as default DETO when DEVSLP TIMING VARIABLES is not supported or the DETO is 0.\r
2585 //\r
2586 if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Deto == 0)) {\r
2587 DevSlpTiming.Deto = 20;\r
2588 }\r
2589\r
2590 //\r
2591 // Use 10ms as default MADT when DEVSLP TIMING VARIABLES is not supported or the MADT is 0.\r
2592 //\r
2593 if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Madt == 0)) {\r
2594 DevSlpTiming.Madt = 10;\r
2595 }\r
2596\r
2597 PortDevSlp |= DevSlpTiming.Deto << 2;\r
2598 PortDevSlp |= DevSlpTiming.Madt << 10;\r
2599 AhciOrReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
2600\r
2601 if (mAtaAtapiPolicy->AggressiveDeviceSleepEnable == 1) {\r
2602 if ((Capability2 & AHCI_CAP2_SADM) != 0) {\r
2603 PortDevSlp &= ~AHCI_PORT_DEVSLP_DITO_MASK;\r
2604 PortDevSlp |= (625 << 15);\r
2605 AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
2606\r
2607 PortDevSlp |= AHCI_PORT_DEVSLP_ADSE;\r
2608 AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
2609 }\r
2610 }\r
2611\r
f3100a1a
RN
2612 AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd);\r
2613\r
1436aea4
MK
2614 DEBUG ((\r
2615 DEBUG_INFO,\r
2616 "Enabled DevSlp feature at port [%d] PortMultiplier [%d], Port CMD/DEVSLP = %08x / %08x\n",\r
2617 Port,\r
2618 PortMultiplier,\r
2619 PortCmd,\r
2620 PortDevSlp\r
2621 ));\r
f3100a1a
RN
2622\r
2623 return EFI_SUCCESS;\r
2624}\r
8d3c4b55
RN
2625\r
2626/**\r
2627 Spin-up disk if IDD was incomplete or PUIS feature is enabled\r
2628\r
2629 @param PciIo The PCI IO protocol instance.\r
2630 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
2631 @param Port The number of port.\r
2632 @param PortMultiplier The multiplier of port.\r
2633 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
2634\r
2635**/\r
2636EFI_STATUS\r
2637AhciSpinUpDisk (\r
1436aea4
MK
2638 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2639 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2640 IN UINT8 Port,\r
2641 IN UINT8 PortMultiplier,\r
2642 IN OUT EFI_IDENTIFY_DATA *IdentifyData\r
8d3c4b55
RN
2643 )\r
2644{\r
1436aea4
MK
2645 EFI_STATUS Status;\r
2646 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2647 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
2648 UINT8 Buffer[512];\r
8d3c4b55
RN
2649\r
2650 if (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_REQUIRED_IDD_INCOMPLETE) {\r
2651 //\r
2652 // Use SET_FEATURE subcommand to spin up the device.\r
2653 //\r
2654 Status = AhciDeviceSetFeature (\r
1436aea4
MK
2655 PciIo,\r
2656 AhciRegisters,\r
2657 Port,\r
2658 PortMultiplier,\r
2659 ATA_SUB_CMD_PUIS_SET_DEVICE_SPINUP,\r
2660 0x00,\r
2661 ATA_SPINUP_TIMEOUT\r
8d3c4b55 2662 );\r
1436aea4
MK
2663 DEBUG ((\r
2664 DEBUG_INFO,\r
2665 "CMD_PUIS_SET_DEVICE_SPINUP for device at port [%d] PortMultiplier [%d] - %r!\n",\r
2666 Port,\r
2667 PortMultiplier,\r
2668 Status\r
2669 ));\r
8d3c4b55
RN
2670 if (EFI_ERROR (Status)) {\r
2671 return Status;\r
2672 }\r
2673 } else {\r
2674 ASSERT (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_NOT_REQUIRED_IDD_INCOMPLETE);\r
2675\r
2676 //\r
2677 // Use READ_SECTORS to spin up the device if SpinUp SET FEATURE subcommand is not supported\r
2678 //\r
2679 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2680 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
2681 //\r
2682 // Perform READ SECTORS PIO Data-In command to Read LBA 0\r
2683 //\r
1436aea4
MK
2684 AtaCommandBlock.AtaCommand = ATA_CMD_READ_SECTORS;\r
2685 AtaCommandBlock.AtaSectorCount = 0x1;\r
8d3c4b55
RN
2686\r
2687 Status = AhciPioTransfer (\r
2688 PciIo,\r
2689 AhciRegisters,\r
2690 Port,\r
2691 PortMultiplier,\r
2692 NULL,\r
2693 0,\r
2694 TRUE,\r
2695 &AtaCommandBlock,\r
2696 &AtaStatusBlock,\r
2697 &Buffer,\r
2698 sizeof (Buffer),\r
2699 ATA_SPINUP_TIMEOUT,\r
2700 NULL\r
2701 );\r
1436aea4
MK
2702 DEBUG ((\r
2703 DEBUG_INFO,\r
2704 "Read LBA 0 for device at port [%d] PortMultiplier [%d] - %r!\n",\r
2705 Port,\r
2706 PortMultiplier,\r
2707 Status\r
2708 ));\r
8d3c4b55
RN
2709 if (EFI_ERROR (Status)) {\r
2710 return Status;\r
2711 }\r
2712 }\r
2713\r
2714 //\r
2715 // Read the complete IDENTIFY DEVICE data.\r
2716 //\r
2717 ZeroMem (IdentifyData, sizeof (*IdentifyData));\r
2718 Status = AhciIdentify (PciIo, AhciRegisters, Port, PortMultiplier, IdentifyData);\r
2719 if (EFI_ERROR (Status)) {\r
1436aea4
MK
2720 DEBUG ((\r
2721 DEBUG_ERROR,\r
2722 "Read IDD failed for device at port [%d] PortMultiplier [%d] - %r!\n",\r
2723 Port,\r
2724 PortMultiplier,\r
2725 Status\r
2726 ));\r
8d3c4b55
RN
2727 return Status;\r
2728 }\r
2729\r
1436aea4
MK
2730 DEBUG ((\r
2731 DEBUG_INFO,\r
2732 "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",\r
2733 IdentifyData->AtaData.config,\r
2734 IdentifyData->AtaData.specific_config,\r
2735 IdentifyData->AtaData.command_set_supported_83,\r
2736 IdentifyData->AtaData.command_set_feature_enb_86\r
2737 ));\r
8d3c4b55
RN
2738 //\r
2739 // Check if IDD is incomplete\r
2740 //\r
2741 if ((IdentifyData->AtaData.config & BIT2) != 0) {\r
2742 return EFI_DEVICE_ERROR;\r
2743 }\r
2744\r
2745 return EFI_SUCCESS;\r
2746}\r
2747\r
06766c0e
RN
2748/**\r
2749 Enable/disable/skip PUIS of the disk according to policy.\r
2750\r
2751 @param PciIo The PCI IO protocol instance.\r
2752 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
2753 @param Port The number of port.\r
2754 @param PortMultiplier The multiplier of port.\r
2755\r
2756**/\r
2757EFI_STATUS\r
2758AhciPuisEnable (\r
1436aea4
MK
2759 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2760 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
2761 IN UINT8 Port,\r
2762 IN UINT8 PortMultiplier\r
06766c0e
RN
2763 )\r
2764{\r
1436aea4 2765 EFI_STATUS Status;\r
06766c0e
RN
2766\r
2767 Status = EFI_SUCCESS;\r
2768 if (mAtaAtapiPolicy->PuisEnable == 0) {\r
2769 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, PortMultiplier, ATA_SUB_CMD_DISABLE_PUIS, 0x00, ATA_ATAPI_TIMEOUT);\r
2770 } else if (mAtaAtapiPolicy->PuisEnable == 1) {\r
2771 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, PortMultiplier, ATA_SUB_CMD_ENABLE_PUIS, 0x00, ATA_ATAPI_TIMEOUT);\r
2772 }\r
1436aea4
MK
2773\r
2774 DEBUG ((\r
2775 DEBUG_INFO,\r
2776 "%a PUIS feature at port [%d] PortMultiplier [%d] - %r!\n",\r
06766c0e 2777 (mAtaAtapiPolicy->PuisEnable == 0) ? "Disable" : (\r
1436aea4
MK
2778 (mAtaAtapiPolicy->PuisEnable == 1) ? "Enable" : "Skip"\r
2779 ),\r
2780 Port,\r
2781 PortMultiplier,\r
2782 Status\r
2783 ));\r
06766c0e
RN
2784 return Status;\r
2785}\r
2786\r
a41b5272 2787/**\r
2788 Initialize ATA host controller at AHCI mode.\r
2789\r
1aff716a 2790 The function is designed to initialize ATA host controller.\r
2791\r
a41b5272 2792 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
2793\r
2794**/\r
2795EFI_STATUS\r
2796EFIAPI\r
2797AhciModeInitialization (\r
1436aea4 2798 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance\r
a41b5272 2799 )\r
2800{\r
1436aea4
MK
2801 EFI_STATUS Status;\r
2802 EFI_PCI_IO_PROTOCOL *PciIo;\r
2803 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2804 UINT32 Capability;\r
2805 UINT8 MaxPortNumber;\r
2806 UINT32 PortImplementBitMap;\r
2807\r
2808 EFI_AHCI_REGISTERS *AhciRegisters;\r
2809\r
2810 UINT8 Port;\r
2811 DATA_64 Data64;\r
2812 UINT32 Offset;\r
2813 UINT32 Data;\r
2814 EFI_IDENTIFY_DATA Buffer;\r
2815 EFI_ATA_DEVICE_TYPE DeviceType;\r
2816 EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
2817 EFI_ATA_TRANSFER_MODE TransferMode;\r
2818 UINT32 PhyDetectDelay;\r
2819 UINT32 Value;\r
cbd2a4b3 2820\r
a41b5272 2821 if (Instance == NULL) {\r
2822 return EFI_INVALID_PARAMETER;\r
2823 }\r
2824\r
2825 PciIo = Instance->PciIo;\r
2826 IdeInit = Instance->IdeControllerInit;\r
2827\r
1aff716a 2828 Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT);\r
a41b5272 2829\r
2830 if (EFI_ERROR (Status)) {\r
2831 return EFI_DEVICE_ERROR;\r
2832 }\r
2833\r
2834 //\r
1ff1dd0f 2835 // Collect AHCI controller information\r
a41b5272 2836 //\r
1ff1dd0f 2837 Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
6052a15f 2838\r
a41b5272 2839 //\r
6052a15f 2840 // Make sure that GHC.AE bit is set before accessing any AHCI registers.\r
a41b5272 2841 //\r
1436aea4 2842 Value = AhciReadReg (PciIo, EFI_AHCI_GHC_OFFSET);\r
6052a15f
MW
2843\r
2844 if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
1ff1dd0f
FT
2845 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
2846 }\r
a2c9b087
AB
2847\r
2848 //\r
2849 // Enable 64-bit DMA support in the PCI layer if this controller\r
2850 // supports it.\r
2851 //\r
2852 if ((Capability & EFI_AHCI_CAP_S64A) != 0) {\r
2853 Status = PciIo->Attributes (\r
2854 PciIo,\r
2855 EfiPciIoAttributeOperationEnable,\r
2856 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
2857 NULL\r
2858 );\r
2859 if (EFI_ERROR (Status)) {\r
1436aea4
MK
2860 DEBUG ((\r
2861 DEBUG_WARN,\r
a2c9b087 2862 "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",\r
1436aea4
MK
2863 Status\r
2864 ));\r
a2c9b087
AB
2865 }\r
2866 }\r
2867\r
a41b5272 2868 //\r
2869 // Get the number of command slots per port supported by this HBA.\r
2870 //\r
1436aea4 2871 MaxPortNumber = (UINT8)((Capability & 0x1F) + 1);\r
a41b5272 2872\r
2873 //\r
2874 // Get the bit map of those ports exposed by this HBA.\r
1aff716a 2875 // It indicates which ports that the HBA supports are available for software to use.\r
a41b5272 2876 //\r
1436aea4 2877 PortImplementBitMap = AhciReadReg (PciIo, EFI_AHCI_PI_OFFSET);\r
1aff716a 2878\r
a41b5272 2879 AhciRegisters = &Instance->AhciRegisters;\r
1436aea4 2880 Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
a41b5272 2881\r
2882 if (EFI_ERROR (Status)) {\r
2883 return EFI_OUT_OF_RESOURCES;\r
2884 }\r
2885\r
1436aea4 2886 for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port++) {\r
27daa865 2887 if ((PortImplementBitMap & (((UINT32)BIT0) << Port)) != 0) {\r
6b13aa60 2888 //\r
2889 // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.\r
2890 //\r
2891 if ((MaxPortNumber--) == 0) {\r
2892 //\r
2893 // Should never be here.\r
2894 //\r
2895 ASSERT (FALSE);\r
2896 return EFI_SUCCESS;\r
2897 }\r
2898\r
cbd2a4b3 2899 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
2900\r
2901 //\r
2902 // Initialize FIS Base Address Register and Command List Base Address Register for use.\r
2903 //\r
1436aea4
MK
2904 Data64.Uint64 = (UINTN)(AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
2905 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
cbd2a4b3 2906 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2907 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
2908 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2909\r
1436aea4
MK
2910 Data64.Uint64 = (UINTN)(AhciRegisters->AhciCmdListPciAddr);\r
2911 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
cbd2a4b3 2912 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2913 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
2914 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2915\r
a41b5272 2916 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1436aea4 2917 Data = AhciReadReg (PciIo, Offset);\r
a41b5272 2918 if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
2919 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
2920 }\r
a41b5272 2921\r
cbd2a4b3 2922 if ((Capability & EFI_AHCI_CAP_SSS) != 0) {\r
2923 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
2924 }\r
2925\r
2926 //\r
2927 // Disable aggressive power management.\r
2928 //\r
2929 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
2930 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
2931 //\r
2932 // Disable the reporting of the corresponding interrupt to system software.\r
2933 //\r
2934 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
2935 AhciAndReg (PciIo, Offset, 0);\r
a41b5272 2936\r
cbd2a4b3 2937 //\r
2938 // Now inform the IDE Controller Init Module.\r
2939 //\r
2940 IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
2941\r
2942 //\r
2943 // Enable FIS Receive DMA engine for the first D2H FIS.\r
2944 //\r
2945 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
2946 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
cbd2a4b3 2947\r
a41b5272 2948 //\r
1fb805b1 2949 // Wait for the Phy to detect the presence of a device.\r
a41b5272 2950 //\r
cbd2a4b3 2951 PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;\r
1436aea4 2952 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
cbd2a4b3 2953 do {\r
2954 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
2955 if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {\r
2956 break;\r
a41b5272 2957 }\r
2958\r
cbd2a4b3 2959 MicroSecondDelay (1000);\r
2960 PhyDetectDelay--;\r
2961 } while (PhyDetectDelay > 0);\r
2962\r
2963 if (PhyDetectDelay == 0) {\r
a41b5272 2964 //\r
cbd2a4b3 2965 // No device detected at this port.\r
2721fabc 2966 // Clear PxCMD.SUD for those ports at which there are no device present.\r
a41b5272 2967 //\r
2721fabc 2968 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
2969 AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_SUD));\r
cbd2a4b3 2970 continue;\r
2971 }\r
a41b5272 2972\r
b465a811
AM
2973 Status = AhciWaitDeviceReady (PciIo, Port);\r
2974 if (EFI_ERROR (Status)) {\r
cbd2a4b3 2975 continue;\r
2976 }\r
a41b5272 2977\r
cbd2a4b3 2978 //\r
2979 // When the first D2H register FIS is received, the content of PxSIG register is updated.\r
2980 //\r
2981 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
8536cc4b 2982 Status = AhciWaitMmioSet (\r
1aff716a 2983 PciIo,\r
cbd2a4b3 2984 Offset,\r
2985 0x0000FFFF,\r
2986 0x00000101,\r
1436aea4 2987 EFI_TIMER_PERIOD_SECONDS (16)\r
cbd2a4b3 2988 );\r
2989 if (EFI_ERROR (Status)) {\r
2990 continue;\r
2991 }\r
a41b5272 2992\r
cbd2a4b3 2993 Data = AhciReadReg (PciIo, Offset);\r
2994 if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
2995 Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
a41b5272 2996\r
cbd2a4b3 2997 if (EFI_ERROR (Status)) {\r
a41b5272 2998 continue;\r
2999 }\r
aca84419 3000\r
cbd2a4b3 3001 DeviceType = EfiIdeCdrom;\r
3002 } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
3003 Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
a41b5272 3004\r
a41b5272 3005 if (EFI_ERROR (Status)) {\r
cbd2a4b3 3006 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
a41b5272 3007 continue;\r
3008 }\r
3009\r
8d3c4b55 3010 DEBUG ((\r
1436aea4
MK
3011 DEBUG_INFO,\r
3012 "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",\r
3013 Buffer.AtaData.config,\r
3014 Buffer.AtaData.specific_config,\r
3015 Buffer.AtaData.command_set_supported_83,\r
3016 Buffer.AtaData.command_set_feature_enb_86\r
8d3c4b55
RN
3017 ));\r
3018 if ((Buffer.AtaData.config & BIT2) != 0) {\r
3019 //\r
3020 // SpinUp disk if device reported incomplete IDENTIFY DEVICE.\r
3021 //\r
3022 Status = AhciSpinUpDisk (\r
3023 PciIo,\r
3024 AhciRegisters,\r
3025 Port,\r
3026 0,\r
3027 &Buffer\r
3028 );\r
3029 if (EFI_ERROR (Status)) {\r
3030 DEBUG ((DEBUG_ERROR, "Spin up standby device failed - %r\n", Status));\r
3031 continue;\r
3032 }\r
3033 }\r
3034\r
cbd2a4b3 3035 DeviceType = EfiIdeHarddisk;\r
3036 } else {\r
3037 continue;\r
3038 }\r
1436aea4
MK
3039\r
3040 DEBUG ((\r
3041 DEBUG_INFO,\r
3042 "port [%d] port multitplier [%d] has a [%a]\n",\r
3043 Port,\r
3044 0,\r
3045 DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"\r
3046 ));\r
a41b5272 3047\r
cbd2a4b3 3048 //\r
3049 // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
3050 //\r
fc80ee69 3051 if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {\r
cbd2a4b3 3052 AhciAtaSmartSupport (\r
3053 PciIo,\r
3054 AhciRegisters,\r
3055 Port,\r
3056 0,\r
3057 &Buffer,\r
3058 NULL\r
3059 );\r
3060 }\r
a41b5272 3061\r
cbd2a4b3 3062 //\r
3063 // Submit identify data to IDE controller init driver\r
3064 //\r
3065 IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
aca84419 3066\r
cbd2a4b3 3067 //\r
3068 // Now start to config ide device parameter and transfer mode.\r
3069 //\r
3070 Status = IdeInit->CalculateMode (\r
3071 IdeInit,\r
3072 Port,\r
3073 0,\r
3074 &SupportedModes\r
3075 );\r
3076 if (EFI_ERROR (Status)) {\r
87000d77 3077 DEBUG ((DEBUG_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
cbd2a4b3 3078 continue;\r
3079 }\r
3080\r
3081 //\r
3082 // Set best supported PIO mode on this IDE device\r
3083 //\r
3084 if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
3085 TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
3086 } else {\r
3087 TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
3088 }\r
3089\r
1436aea4 3090 TransferMode.ModeNumber = (UINT8)(SupportedModes->PioMode.Mode);\r
cbd2a4b3 3091\r
3092 //\r
8c39253d 3093 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA can't\r
cbd2a4b3 3094 // be set together. Only one DMA mode can be set to a device. If setting\r
3095 // DMA mode operation fails, we can continue moving on because we only use\r
3096 // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
3097 //\r
3098 if (SupportedModes->UdmaMode.Valid) {\r
3099 TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
1436aea4 3100 TransferMode.ModeNumber = (UINT8)(SupportedModes->UdmaMode.Mode);\r
cbd2a4b3 3101 } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
3102 TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
1436aea4 3103 TransferMode.ModeNumber = (UINT8)SupportedModes->MultiWordDmaMode.Mode;\r
cbd2a4b3 3104 }\r
3105\r
8d3c4b55 3106 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode), ATA_ATAPI_TIMEOUT);\r
cbd2a4b3 3107 if (EFI_ERROR (Status)) {\r
87000d77 3108 DEBUG ((DEBUG_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
cbd2a4b3 3109 continue;\r
3110 }\r
3111\r
3112 //\r
3113 // Found a ATA or ATAPI device, add it into the device list.\r
3114 //\r
23a596db 3115 CreateNewDeviceInfo (Instance, Port, 0xFFFF, DeviceType, &Buffer);\r
cbd2a4b3 3116 if (DeviceType == EfiIdeHarddisk) {\r
3117 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
f3100a1a
RN
3118 AhciEnableDevSlp (\r
3119 PciIo,\r
3120 AhciRegisters,\r
3121 Port,\r
3122 0,\r
3123 &Buffer\r
3124 );\r
a41b5272 3125 }\r
06766c0e
RN
3126\r
3127 //\r
3128 // Enable/disable PUIS according to policy setting if PUIS is capable (Word[83].BIT5 is set).\r
3129 //\r
3130 if ((Buffer.AtaData.command_set_supported_83 & BIT5) != 0) {\r
3131 Status = AhciPuisEnable (\r
3132 PciIo,\r
3133 AhciRegisters,\r
3134 Port,\r
3135 0\r
3136 );\r
3137 if (EFI_ERROR (Status)) {\r
3138 DEBUG ((DEBUG_ERROR, "PUIS enable/disable failed, Status = %r\n", Status));\r
3139 continue;\r
3140 }\r
3141 }\r
a41b5272 3142 }\r
3143 }\r
cbd2a4b3 3144\r
a41b5272 3145 return EFI_SUCCESS;\r
3146}\r