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