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