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