]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
Add new adding ATA related status code in PI 1.3 to definition and ATA modules.
[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
cffd2171 4 Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>\r
1aff716a 5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
a41b5272 9\r
1aff716a 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
a41b5272 12\r
13**/\r
14\r
15#include "AtaAtapiPassThru.h"\r
16\r
17/**\r
18 Read AHCI Operation register.\r
19\r
20 @param PciIo The PCI IO protocol instance.\r
21 @param Offset The operation register offset.\r
22\r
23 @return The register content read.\r
24\r
25**/\r
26UINT32\r
27EFIAPI\r
28AhciReadReg (\r
29 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
30 IN UINT32 Offset\r
31 )\r
32{\r
33 UINT32 Data;\r
34\r
35 ASSERT (PciIo != NULL);\r
1aff716a 36\r
a41b5272 37 Data = 0;\r
38\r
39 PciIo->Mem.Read (\r
40 PciIo,\r
41 EfiPciIoWidthUint32,\r
42 EFI_AHCI_BAR_INDEX,\r
43 (UINT64) Offset,\r
44 1,\r
45 &Data\r
46 );\r
47\r
48 return Data;\r
49}\r
50\r
51/**\r
52 Write AHCI Operation register.\r
53\r
54 @param PciIo The PCI IO protocol instance.\r
55 @param Offset The operation register offset.\r
56 @param Data The data used to write down.\r
57\r
58**/\r
59VOID\r
60EFIAPI\r
61AhciWriteReg (\r
62 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
63 IN UINT32 Offset,\r
64 IN UINT32 Data\r
65 )\r
66{\r
67 ASSERT (PciIo != NULL);\r
68\r
69 PciIo->Mem.Write (\r
70 PciIo,\r
71 EfiPciIoWidthUint32,\r
72 EFI_AHCI_BAR_INDEX,\r
73 (UINT64) Offset,\r
74 1,\r
75 &Data\r
76 );\r
77\r
78 return ;\r
79}\r
80\r
81/**\r
82 Do AND operation with the value of AHCI Operation register.\r
83\r
84 @param PciIo The PCI IO protocol instance.\r
85 @param Offset The operation register offset.\r
86 @param AndData The data used to do AND operation.\r
87\r
88**/\r
89VOID\r
90EFIAPI\r
91AhciAndReg (\r
92 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
93 IN UINT32 Offset,\r
94 IN UINT32 AndData\r
95 )\r
96{\r
97 UINT32 Data;\r
1aff716a 98\r
a41b5272 99 ASSERT (PciIo != NULL);\r
100\r
101 Data = AhciReadReg (PciIo, Offset);\r
102\r
103 Data &= AndData;\r
104\r
105 AhciWriteReg (PciIo, Offset, Data);\r
106}\r
107\r
108/**\r
109 Do OR operation with the value of AHCI Operation register.\r
110\r
111 @param PciIo The PCI IO protocol instance.\r
112 @param Offset The operation register offset.\r
113 @param OrData The data used to do OR operation.\r
114\r
115**/\r
116VOID\r
117EFIAPI\r
118AhciOrReg (\r
119 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
120 IN UINT32 Offset,\r
121 IN UINT32 OrData\r
122 )\r
123{\r
124 UINT32 Data;\r
125\r
126 ASSERT (PciIo != NULL);\r
127\r
128 Data = AhciReadReg (PciIo, Offset);\r
129\r
130 Data |= OrData;\r
131\r
132 AhciWriteReg (PciIo, Offset, Data);\r
133}\r
134\r
135/**\r
8536cc4b 136 Wait for the value of the specified MMIO register set to the test value.\r
1aff716a 137\r
aca84419 138 @param PciIo The PCI IO protocol instance.\r
8536cc4b 139 @param Offset The MMIO address to test.\r
aca84419 140 @param MaskValue The mask value of memory.\r
141 @param TestValue The test value of memory.\r
8536cc4b 142 @param Timeout The time out value for wait memory set, uses 100ns as a unit.\r
a41b5272 143\r
8536cc4b 144 @retval EFI_TIMEOUT The MMIO setting is time out.\r
145 @retval EFI_SUCCESS The MMIO is correct set.\r
a41b5272 146\r
147**/\r
148EFI_STATUS\r
149EFIAPI\r
8536cc4b 150AhciWaitMmioSet (\r
a41b5272 151 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
8536cc4b 152 IN UINTN Offset,\r
a41b5272 153 IN UINT32 MaskValue,\r
154 IN UINT32 TestValue,\r
155 IN UINT64 Timeout\r
156 )\r
157{\r
1aff716a 158 UINT32 Value;\r
a41b5272 159 UINT32 Delay;\r
160\r
8536cc4b 161 Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
a41b5272 162\r
163 do {\r
8536cc4b 164 //\r
165 // Access PCI MMIO space to see if the value is the tested one.\r
166 //\r
167 Value = AhciReadReg (PciIo, (UINT32) Offset) & MaskValue;\r
a41b5272 168\r
169 if (Value == TestValue) {\r
170 return EFI_SUCCESS;\r
171 }\r
172\r
173 //\r
174 // Stall for 100 microseconds.\r
175 //\r
176 MicroSecondDelay (100);\r
177\r
178 Delay--;\r
179\r
180 } while (Delay > 0);\r
181\r
8536cc4b 182 return EFI_TIMEOUT;\r
183}\r
184\r
185/**\r
186 Wait for the value of the specified system memory set to the test value.\r
1aff716a 187\r
8536cc4b 188 @param Address The system memory address to test.\r
189 @param MaskValue The mask value of memory.\r
190 @param TestValue The test value of memory.\r
191 @param Timeout The time out value for wait memory set, uses 100ns as a unit.\r
192\r
193 @retval EFI_TIMEOUT The system memory setting is time out.\r
194 @retval EFI_SUCCESS The system memory is correct set.\r
195\r
196**/\r
197EFI_STATUS\r
198EFIAPI\r
199AhciWaitMemSet (\r
200 IN EFI_PHYSICAL_ADDRESS Address,\r
201 IN UINT32 MaskValue,\r
202 IN UINT32 TestValue,\r
203 IN UINT64 Timeout\r
204 )\r
205{\r
1aff716a 206 UINT32 Value;\r
8536cc4b 207 UINT32 Delay;\r
208\r
209 Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
210\r
211 do {\r
212 //\r
213 // Access sytem memory to see if the value is the tested one.\r
214 //\r
215 // The system memory pointed by Address will be updated by the\r
216 // SATA Host Controller, "volatile" is introduced to prevent\r
217 // compiler from optimizing the access to the memory address\r
218 // to only read once.\r
219 //\r
220 Value = *(volatile UINT32 *) (UINTN) Address;\r
221 Value &= MaskValue;\r
222\r
223 if (Value == TestValue) {\r
224 return EFI_SUCCESS;\r
225 }\r
226\r
227 //\r
228 // Stall for 100 microseconds.\r
229 //\r
230 MicroSecondDelay (100);\r
231\r
232 Delay--;\r
a41b5272 233\r
8536cc4b 234 } while (Delay > 0);\r
235\r
236 return EFI_TIMEOUT;\r
a41b5272 237}\r
238\r
490b5ea1 239/**\r
240 Check the memory status to the test value.\r
1aff716a 241\r
8536cc4b 242 @param[in] Address The memory address to test.\r
490b5ea1 243 @param[in] MaskValue The mask value of memory.\r
244 @param[in] TestValue The test value of memory.\r
8536cc4b 245 @param[in, out] RetryTimes The retry times value for waitting memory set. If 0, then just try once.\r
490b5ea1 246\r
247 @retval EFI_NOTREADY The memory is not set.\r
248 @retval EFI_TIMEOUT The memory setting retry times out.\r
249 @retval EFI_SUCCESS The memory is correct set.\r
250\r
251**/\r
252EFI_STATUS\r
253EFIAPI\r
254AhciCheckMemSet (\r
8536cc4b 255 IN UINTN Address,\r
86d8e199 256 IN UINT32 MaskValue,\r
257 IN UINT32 TestValue,\r
8536cc4b 258 IN OUT UINTN *RetryTimes OPTIONAL\r
490b5ea1 259 )\r
260{\r
261 UINT32 Value;\r
262\r
8536cc4b 263 if (RetryTimes != NULL) {\r
264 (*RetryTimes)--;\r
265 }\r
1aff716a 266\r
8536cc4b 267 Value = *(volatile UINT32 *) Address;\r
268 Value &= MaskValue;\r
490b5ea1 269\r
270 if (Value == TestValue) {\r
271 return EFI_SUCCESS;\r
272 }\r
273\r
8536cc4b 274 if ((RetryTimes != NULL) && (*RetryTimes == 0)) {\r
490b5ea1 275 return EFI_TIMEOUT;\r
276 } else {\r
277 return EFI_NOT_READY;\r
278 }\r
279}\r
280\r
a41b5272 281/**\r
1aff716a 282 Check if the device is still on port. It also checks if the AHCI controller\r
490b5ea1 283 supports the address and data count will be transferred.\r
a41b5272 284\r
aca84419 285 @param PciIo The PCI IO protocol instance.\r
286 @param Port The number of port.\r
a41b5272 287\r
1aff716a 288 @retval EFI_SUCCESS The device is attached to port and the transfer data is\r
a41b5272 289 supported by AHCI controller.\r
290 @retval EFI_UNSUPPORTED The transfer address and count is not supported by AHCI\r
291 controller.\r
292 @retval EFI_NOT_READY The physical communication between AHCI controller and device\r
293 is not ready.\r
294\r
295**/\r
296EFI_STATUS\r
297EFIAPI\r
298AhciCheckDeviceStatus (\r
299 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
300 IN UINT8 Port\r
301 )\r
302{\r
490b5ea1 303 UINT32 Data;\r
a41b5272 304 UINT32 Offset;\r
305\r
306 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
307\r
308 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
309\r
310 if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
490b5ea1 311 return EFI_SUCCESS;\r
a41b5272 312 }\r
313\r
314 return EFI_NOT_READY;\r
315}\r
316\r
317/**\r
318\r
319 Clear the port interrupt and error status. It will also clear\r
320 HBA interrupt status.\r
1aff716a 321\r
a41b5272 322 @param PciIo The PCI IO protocol instance.\r
323 @param Port The number of port.\r
1aff716a 324\r
325**/\r
a41b5272 326VOID\r
327EFIAPI\r
328AhciClearPortStatus (\r
329 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
330 IN UINT8 Port\r
1aff716a 331 )\r
a41b5272 332{\r
333 UINT32 Offset;\r
334\r
335 //\r
336 // Clear any error status\r
490b5ea1 337 //\r
a41b5272 338 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
339 AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
340\r
341 //\r
342 // Clear any port interrupt status\r
343 //\r
344 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
345 AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
346\r
347 //\r
348 // Clear any HBA interrupt status\r
349 //\r
350 AhciWriteReg (PciIo, EFI_AHCI_IS_OFFSET, AhciReadReg (PciIo, EFI_AHCI_IS_OFFSET));\r
351}\r
352\r
e519983a 353/**\r
354 This function is used to dump the Status Registers and if there is ERR bit set\r
355 in the Status Register, the Error Register's value is also be dumped.\r
356\r
357 @param PciIo The PCI IO protocol instance.\r
358 @param Port The number of port.\r
359 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
360\r
361**/\r
362VOID\r
363EFIAPI\r
364AhciDumpPortStatus (\r
365 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
366 IN UINT8 Port,\r
367 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
368 )\r
369{\r
370 UINT32 Offset;\r
371 UINT32 Data;\r
372\r
373 ASSERT (PciIo != NULL);\r
374\r
375 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
376 Data = AhciReadReg (PciIo, Offset);\r
377\r
378 if (AtaStatusBlock != NULL) {\r
379 ZeroMem (AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
380\r
381 AtaStatusBlock->AtaStatus = (UINT8)Data;\r
382 if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {\r
383 AtaStatusBlock->AtaError = (UINT8)(Data >> 8);\r
384 }\r
385 }\r
386}\r
387\r
388\r
a41b5272 389/**\r
390 Enable the FIS running for giving port.\r
1aff716a 391\r
a41b5272 392 @param PciIo The PCI IO protocol instance.\r
393 @param Port The number of port.\r
8536cc4b 394 @param Timeout The timeout value of enabling FIS, uses 100ns as a unit.\r
a41b5272 395\r
396 @retval EFI_DEVICE_ERROR The FIS enable setting fails.\r
397 @retval EFI_TIMEOUT The FIS enable setting is time out.\r
398 @retval EFI_SUCCESS The FIS enable successfully.\r
399\r
400**/\r
401EFI_STATUS\r
402EFIAPI\r
403AhciEnableFisReceive (\r
404 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
405 IN UINT8 Port,\r
406 IN UINT64 Timeout\r
490b5ea1 407 )\r
408{\r
a41b5272 409 UINT32 Offset;\r
410\r
411 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
412 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
413\r
8536cc4b 414 return AhciWaitMmioSet (\r
1aff716a 415 PciIo,\r
a41b5272 416 Offset,\r
417 EFI_AHCI_PORT_CMD_FR,\r
418 EFI_AHCI_PORT_CMD_FR,\r
419 Timeout\r
420 );\r
421}\r
422\r
423/**\r
424 Disable the FIS running for giving port.\r
425\r
426 @param PciIo The PCI IO protocol instance.\r
427 @param Port The number of port.\r
8536cc4b 428 @param Timeout The timeout value of disabling FIS, uses 100ns as a unit.\r
a41b5272 429\r
430 @retval EFI_DEVICE_ERROR The FIS disable setting fails.\r
431 @retval EFI_TIMEOUT The FIS disable setting is time out.\r
432 @retval EFI_UNSUPPORTED The port is in running state.\r
433 @retval EFI_SUCCESS The FIS disable successfully.\r
434\r
435**/\r
436EFI_STATUS\r
437EFIAPI\r
438AhciDisableFisReceive (\r
439 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
440 IN UINT8 Port,\r
441 IN UINT64 Timeout\r
1aff716a 442 )\r
a41b5272 443{\r
444 UINT32 Offset;\r
445 UINT32 Data;\r
446\r
447 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
448 Data = AhciReadReg (PciIo, Offset);\r
449\r
450 //\r
451 // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.\r
452 //\r
453 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {\r
454 return EFI_UNSUPPORTED;\r
455 }\r
1aff716a 456\r
a41b5272 457 //\r
458 // Check if the Fis receive DMA engine for the port is running.\r
459 //\r
460 if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {\r
461 return EFI_SUCCESS;\r
462 }\r
463\r
464 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));\r
465\r
8536cc4b 466 return AhciWaitMmioSet (\r
490b5ea1 467 PciIo,\r
a41b5272 468 Offset,\r
469 EFI_AHCI_PORT_CMD_FR,\r
470 0,\r
471 Timeout\r
490b5ea1 472 );\r
a41b5272 473}\r
474\r
475\r
476\r
477/**\r
478 Build the command list, command table and prepare the fis receiver.\r
1aff716a 479\r
aca84419 480 @param PciIo The PCI IO protocol instance.\r
a41b5272 481 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
aca84419 482 @param Port The number of port.\r
483 @param PortMultiplier The timeout value of stop.\r
484 @param CommandFis The control fis will be used for the transfer.\r
485 @param CommandList The command list will be used for the transfer.\r
486 @param AtapiCommand The atapi command will be used for the transfer.\r
487 @param AtapiCommandLength The length of the atapi command.\r
488 @param CommandSlotNumber The command slot will be used for the transfer.\r
a41b5272 489 @param DataPhysicalAddr The pointer to the data buffer pci bus master address.\r
490 @param DataLength The data count to be transferred.\r
491\r
1aff716a 492**/\r
a41b5272 493VOID\r
494EFIAPI\r
495AhciBuildCommand (\r
496 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
497 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
498 IN UINT8 Port,\r
499 IN UINT8 PortMultiplier,\r
500 IN EFI_AHCI_COMMAND_FIS *CommandFis,\r
501 IN EFI_AHCI_COMMAND_LIST *CommandList,\r
502 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
503 IN UINT8 AtapiCommandLength,\r
504 IN UINT8 CommandSlotNumber,\r
505 IN OUT VOID *DataPhysicalAddr,\r
e0e7f80c 506 IN UINT32 DataLength\r
1aff716a 507 )\r
a41b5272 508{\r
490b5ea1 509 UINT64 BaseAddr;\r
e0e7f80c
LG
510 UINT32 PrdtNumber;\r
511 UINT32 PrdtIndex;\r
a41b5272 512 UINTN RemainedData;\r
513 UINTN MemAddr;\r
514 DATA_64 Data64;\r
515 UINT32 Offset;\r
516\r
517 //\r
518 // Filling the PRDT\r
1aff716a 519 //\r
a41b5272 520 PrdtNumber = (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1) / EFI_AHCI_MAX_DATA_PER_PRDT;\r
521\r
522 //\r
523 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.\r
524 // It also limits that the maximum amount of the PRDT entry in the command table\r
525 // is 65535.\r
526 //\r
527 ASSERT (PrdtNumber <= 65535);\r
528\r
529 Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
530\r
531 BaseAddr = Data64.Uint64;\r
1aff716a 532\r
490b5ea1 533 ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));\r
1aff716a 534\r
a41b5272 535 ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
536\r
537 CommandFis->AhciCFisPmNum = PortMultiplier;\r
1aff716a 538\r
a41b5272 539 CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
540\r
541 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
542 if (AtapiCommand != NULL) {\r
543 CopyMem (\r
544 &AhciRegisters->AhciCommandTable->AtapiCmd,\r
545 AtapiCommand,\r
546 AtapiCommandLength\r
547 );\r
548\r
549 CommandList->AhciCmdA = 1;\r
550 CommandList->AhciCmdP = 1;\r
a41b5272 551\r
552 AhciOrReg (PciIo, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
553 } else {\r
554 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
555 }\r
1aff716a 556\r
5dec0c68 557 RemainedData = (UINTN) DataLength;\r
a41b5272 558 MemAddr = (UINTN) DataPhysicalAddr;\r
e0e7f80c 559 CommandList->AhciCmdPrdtl = PrdtNumber;\r
1aff716a 560\r
a41b5272 561 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
490b5ea1 562 if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {\r
a41b5272 563 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;\r
564 } else {\r
565 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;\r
566 }\r
567\r
568 Data64.Uint64 = (UINT64)MemAddr;\r
569 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba = Data64.Uint32.Lower32;\r
570 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;\r
490b5ea1 571 RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;\r
a41b5272 572 MemAddr += EFI_AHCI_MAX_DATA_PER_PRDT;\r
573 }\r
574\r
575 //\r
576 // Set the last PRDT to Interrupt On Complete\r
577 //\r
578 if (PrdtNumber > 0) {\r
579 AhciRegisters->AhciCommandTable->PrdtTable[PrdtNumber - 1].AhciPrdtIoc = 1;\r
580 }\r
581\r
582 CopyMem (\r
583 (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),\r
584 CommandList,\r
585 sizeof (EFI_AHCI_COMMAND_LIST)\r
1aff716a 586 );\r
a41b5272 587\r
588 Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTablePciAddr;\r
589 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;\r
590 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;\r
591 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;\r
592\r
593}\r
594\r
595/**\r
596 Buid a command FIS.\r
1aff716a 597\r
aca84419 598 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.\r
a41b5272 599 @param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.\r
600\r
601**/\r
602VOID\r
603EFIAPI\r
604AhciBuildCommandFis (\r
605 IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,\r
606 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock\r
607 )\r
608{\r
609 ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
610\r
611 CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;\r
612 //\r
613 // Indicator it's a command\r
614 //\r
1aff716a 615 CmdFis->AhciCFisCmdInd = 0x1;\r
a41b5272 616 CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;\r
617\r
618 CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;\r
619 CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;\r
620\r
621 CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;\r
622 CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;\r
623\r
624 CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;\r
625 CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;\r
626\r
627 CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;\r
628 CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;\r
629\r
630 CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;\r
631 CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;\r
632\r
aca84419 633 CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);\r
a41b5272 634}\r
635\r
636/**\r
637 Start a PIO data transfer on specific port.\r
1aff716a 638\r
490b5ea1 639 @param[in] PciIo The PCI IO protocol instance.\r
640 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
641 @param[in] Port The number of port.\r
642 @param[in] PortMultiplier The timeout value of stop.\r
643 @param[in] AtapiCommand The atapi command will be used for the\r
644 transfer.\r
645 @param[in] AtapiCommandLength The length of the atapi command.\r
646 @param[in] Read The transfer direction.\r
647 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
648 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
649 @param[in, out] MemoryAddr The pointer to the data buffer.\r
650 @param[in] DataCount The data count to be transferred.\r
8536cc4b 651 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 652 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
653 used by non-blocking mode.\r
a41b5272 654\r
655 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.\r
656 @retval EFI_TIMEOUT The operation is time out.\r
657 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
658 @retval EFI_SUCCESS The PIO data transfer executes successfully.\r
659\r
660**/\r
661EFI_STATUS\r
aca84419 662EFIAPI\r
a41b5272 663AhciPioTransfer (\r
664 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
665 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
666 IN UINT8 Port,\r
667 IN UINT8 PortMultiplier,\r
668 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
1aff716a 669 IN UINT8 AtapiCommandLength,\r
670 IN BOOLEAN Read,\r
a41b5272 671 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
672 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
673 IN OUT VOID *MemoryAddr,\r
674 IN UINT32 DataCount,\r
490b5ea1 675 IN UINT64 Timeout,\r
676 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 677 )\r
678{\r
679 EFI_STATUS Status;\r
680 UINTN FisBaseAddr;\r
8536cc4b 681 UINTN Offset;\r
a41b5272 682 EFI_PHYSICAL_ADDRESS PhyAddr;\r
683 VOID *Map;\r
684 UINTN MapLength;\r
685 EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
686 UINT32 Delay;\r
687 EFI_AHCI_COMMAND_FIS CFis;\r
1aff716a 688 EFI_AHCI_COMMAND_LIST CmdList;\r
8536cc4b 689 UINT32 PortTfd;\r
690 UINT32 PrdCount;\r
a41b5272 691\r
692 if (Read) {\r
693 Flag = EfiPciIoOperationBusMasterWrite;\r
694 } else {\r
695 Flag = EfiPciIoOperationBusMasterRead;\r
696 }\r
697\r
698 //\r
699 // construct command list and command table with pci bus address\r
700 //\r
701 MapLength = DataCount;\r
702 Status = PciIo->Map (\r
703 PciIo,\r
704 Flag,\r
705 MemoryAddr,\r
706 &MapLength,\r
707 &PhyAddr,\r
708 &Map\r
709 );\r
710\r
711 if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
9e70c18b 712 return EFI_BAD_BUFFER_SIZE;\r
a41b5272 713 }\r
1aff716a 714\r
a41b5272 715 //\r
716 // Package read needed\r
717 //\r
718 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
719\r
720 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
721\r
722 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
723 CmdList.AhciCmdW = Read ? 0 : 1;\r
724\r
725 AhciBuildCommand (\r
726 PciIo,\r
727 AhciRegisters,\r
728 Port,\r
729 PortMultiplier,\r
730 &CFis,\r
731 &CmdList,\r
732 AtapiCommand,\r
733 AtapiCommandLength,\r
734 0,\r
735 (VOID *)(UINTN)PhyAddr,\r
736 DataCount\r
1aff716a 737 );\r
738\r
a41b5272 739 Status = AhciStartCommand (\r
490b5ea1 740 PciIo,\r
741 Port,\r
a41b5272 742 0,\r
743 Timeout\r
744 );\r
745 if (EFI_ERROR (Status)) {\r
746 goto Exit;\r
747 }\r
490b5ea1 748\r
a41b5272 749 //\r
490b5ea1 750 // Check the status and wait the driver sending data\r
a41b5272 751 //\r
752 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
a41b5272 753\r
8536cc4b 754 if (Read && (AtapiCommand == 0)) {\r
a41b5272 755 //\r
8536cc4b 756 // Wait device sends the PIO setup fis before data transfer\r
a41b5272 757 //\r
8536cc4b 758 Status = EFI_TIMEOUT;\r
759 Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
760 do {\r
8536cc4b 761 Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\r
a41b5272 762\r
8536cc4b 763 Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);\r
764 if (!EFI_ERROR (Status)) {\r
7fb60a98 765 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
766 PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
767 //\r
768 // PxTFD will be updated if there is a D2H or SetupFIS received. \r
769 // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.\r
770 //\r
771 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
772 Status = EFI_DEVICE_ERROR;\r
773 break;\r
774 }\r
775\r
8536cc4b 776 PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
777 if (PrdCount == DataCount) {\r
778 break;\r
779 }\r
780 }\r
a41b5272 781\r
8536cc4b 782 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
783 Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);\r
784 if (!EFI_ERROR (Status)) {\r
785 Status = EFI_DEVICE_ERROR;\r
786 break;\r
787 }\r
a41b5272 788\r
8536cc4b 789 //\r
790 // Stall for 100 microseconds.\r
791 //\r
792 MicroSecondDelay(100);\r
a41b5272 793\r
8536cc4b 794 Delay--;\r
795 } while (Delay > 0);\r
796 } else {\r
797 //\r
798 // Wait for D2H Fis is received\r
799 //\r
800 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
801 Status = AhciWaitMemSet (\r
802 Offset,\r
803 EFI_AHCI_FIS_TYPE_MASK,\r
804 EFI_AHCI_FIS_REGISTER_D2H,\r
805 Timeout\r
806 );\r
a41b5272 807\r
8536cc4b 808 if (EFI_ERROR (Status)) {\r
809 goto Exit;\r
810 }\r
811\r
812 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
813 PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
814 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
815 Status = EFI_DEVICE_ERROR;\r
816 }\r
a41b5272 817 }\r
818\r
490b5ea1 819Exit:\r
a41b5272 820 AhciStopCommand (\r
490b5ea1 821 PciIo,\r
a41b5272 822 Port,\r
823 Timeout\r
824 );\r
1aff716a 825\r
a41b5272 826 AhciDisableFisReceive (\r
490b5ea1 827 PciIo,\r
a41b5272 828 Port,\r
829 Timeout\r
830 );\r
831\r
832 PciIo->Unmap (\r
833 PciIo,\r
834 Map\r
835 );\r
836\r
e519983a 837 AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
838\r
a41b5272 839 return Status;\r
840}\r
841\r
842/**\r
843 Start a DMA data transfer on specific port\r
844\r
490b5ea1 845 @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.\r
846 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
847 @param[in] Port The number of port.\r
848 @param[in] PortMultiplier The timeout value of stop.\r
849 @param[in] AtapiCommand The atapi command will be used for the\r
850 transfer.\r
851 @param[in] AtapiCommandLength The length of the atapi command.\r
852 @param[in] Read The transfer direction.\r
853 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
854 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
855 @param[in, out] MemoryAddr The pointer to the data buffer.\r
856 @param[in] DataCount The data count to be transferred.\r
8536cc4b 857 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 858 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
859 used by non-blocking mode.\r
aca84419 860\r
861 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.\r
862 @retval EFI_TIMEOUT The operation is time out.\r
863 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
864 @retval EFI_SUCCESS The DMA data transfer executes successfully.\r
490b5ea1 865\r
a41b5272 866**/\r
867EFI_STATUS\r
868EFIAPI\r
869AhciDmaTransfer (\r
490b5ea1 870 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
a41b5272 871 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
872 IN UINT8 Port,\r
873 IN UINT8 PortMultiplier,\r
874 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
875 IN UINT8 AtapiCommandLength,\r
1aff716a 876 IN BOOLEAN Read,\r
a41b5272 877 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
878 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
879 IN OUT VOID *MemoryAddr,\r
8536cc4b 880 IN UINT32 DataCount,\r
490b5ea1 881 IN UINT64 Timeout,\r
882 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 883 )\r
884{\r
885 EFI_STATUS Status;\r
8536cc4b 886 UINTN Offset;\r
a41b5272 887 EFI_PHYSICAL_ADDRESS PhyAddr;\r
888 VOID *Map;\r
889 UINTN MapLength;\r
890 EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
891 EFI_AHCI_COMMAND_FIS CFis;\r
892 EFI_AHCI_COMMAND_LIST CmdList;\r
8536cc4b 893 UINTN FisBaseAddr;\r
894 UINT32 PortTfd;\r
a41b5272 895\r
8536cc4b 896 EFI_PCI_IO_PROTOCOL *PciIo;\r
897 EFI_TPL OldTpl;\r
a41b5272 898\r
490b5ea1 899 Map = NULL;\r
900 PciIo = Instance->PciIo;\r
a41b5272 901\r
490b5ea1 902 if (PciIo == NULL) {\r
903 return EFI_INVALID_PARAMETER;\r
a41b5272 904 }\r
905\r
906 //\r
490b5ea1 907 // Before starting the Blocking BlockIO operation, push to finish all non-blocking\r
908 // BlockIO tasks.\r
909 // Delay 100us to simulate the blocking time out checking.\r
a41b5272 910 //\r
1aff716a 911 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
490b5ea1 912 while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {\r
490b5ea1 913 AsyncNonBlockingTransferRoutine (NULL, Instance);\r
490b5ea1 914 //\r
915 // Stall for 100us.\r
916 //\r
917 MicroSecondDelay (100);\r
918 }\r
1aff716a 919 gBS->RestoreTPL (OldTpl);\r
a41b5272 920\r
490b5ea1 921 if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {\r
922 //\r
923 // Mark the Task to indicate that it has been started.\r
924 //\r
925 if (Task != NULL) {\r
926 Task->IsStart = TRUE;\r
927 Task->RetryTimes = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
928 }\r
929 if (Read) {\r
930 Flag = EfiPciIoOperationBusMasterWrite;\r
931 } else {\r
932 Flag = EfiPciIoOperationBusMasterRead;\r
933 }\r
a41b5272 934\r
490b5ea1 935 //\r
936 // Construct command list and command table with pci bus address.\r
937 //\r
938 MapLength = DataCount;\r
939 Status = PciIo->Map (\r
940 PciIo,\r
941 Flag,\r
942 MemoryAddr,\r
943 &MapLength,\r
944 &PhyAddr,\r
945 &Map\r
946 );\r
947\r
948 if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
9e70c18b 949 return EFI_BAD_BUFFER_SIZE;\r
490b5ea1 950 }\r
a41b5272 951\r
490b5ea1 952 if (Task != NULL) {\r
953 Task->Map = Map;\r
954 }\r
955 //\r
956 // Package read needed\r
957 //\r
958 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
959\r
960 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
961\r
962 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
963 CmdList.AhciCmdW = Read ? 0 : 1;\r
964\r
965 AhciBuildCommand (\r
966 PciIo,\r
967 AhciRegisters,\r
968 Port,\r
969 PortMultiplier,\r
970 &CFis,\r
971 &CmdList,\r
972 AtapiCommand,\r
973 AtapiCommandLength,\r
974 0,\r
975 (VOID *)(UINTN)PhyAddr,\r
976 DataCount\r
977 );\r
978\r
979 Status = AhciStartCommand (\r
980 PciIo,\r
981 Port,\r
982 0,\r
983 Timeout\r
984 );\r
985 if (EFI_ERROR (Status)) {\r
986 goto Exit;\r
987 }\r
a41b5272 988 }\r
989\r
990 //\r
991 // Wait for command compelte\r
992 //\r
8536cc4b 993 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
994 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
490b5ea1 995 if (Task != NULL) {\r
996 //\r
997 // For Non-blocking\r
998 //\r
999 Status = AhciCheckMemSet (\r
490b5ea1 1000 Offset,\r
8536cc4b 1001 EFI_AHCI_FIS_TYPE_MASK,\r
1002 EFI_AHCI_FIS_REGISTER_D2H,\r
490b5ea1 1003 (UINTN *) (&Task->RetryTimes)\r
1004 );\r
1005 } else {\r
1006 Status = AhciWaitMemSet (\r
490b5ea1 1007 Offset,\r
8536cc4b 1008 EFI_AHCI_FIS_TYPE_MASK,\r
1009 EFI_AHCI_FIS_REGISTER_D2H,\r
490b5ea1 1010 Timeout\r
1011 );\r
1012 }\r
1013\r
a41b5272 1014 if (EFI_ERROR (Status)) {\r
1015 goto Exit;\r
1016 }\r
1017\r
8536cc4b 1018 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
1019 PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
1020 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
1021 Status = EFI_DEVICE_ERROR;\r
a41b5272 1022 }\r
1023\r
490b5ea1 1024Exit:\r
1025 //\r
1026 // For Blocking mode, the command should be stopped, the Fis should be disabled\r
1027 // and the PciIo should be unmapped.\r
1aff716a 1028 // For non-blocking mode, only when a error is happened (if the return status is\r
1029 // EFI_NOT_READY that means the command doesn't finished, try again.), first do the\r
490b5ea1 1030 // context cleanup, then set the packet's Asb status.\r
1031 //\r
1032 if (Task == NULL ||\r
1033 ((Task != NULL) && (Status != EFI_NOT_READY))\r
1034 ) {\r
1035 AhciStopCommand (\r
1aff716a 1036 PciIo,\r
490b5ea1 1037 Port,\r
1038 Timeout\r
1039 );\r
a41b5272 1040\r
490b5ea1 1041 AhciDisableFisReceive (\r
1aff716a 1042 PciIo,\r
490b5ea1 1043 Port,\r
1044 Timeout\r
1045 );\r
a41b5272 1046\r
490b5ea1 1047 PciIo->Unmap (\r
1048 PciIo,\r
1049 (Task != NULL) ? Task->Map : Map\r
1050 );\r
e519983a 1051\r
490b5ea1 1052 if (Task != NULL) {\r
1053 Task->Packet->Asb->AtaStatus = 0x01;\r
1054 }\r
1055 }\r
1056\r
1057 AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
a41b5272 1058 return Status;\r
1059}\r
1060\r
1061/**\r
1062 Start a non data transfer on specific port.\r
1aff716a 1063\r
490b5ea1 1064 @param[in] PciIo The PCI IO protocol instance.\r
1065 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1066 @param[in] Port The number of port.\r
1067 @param[in] PortMultiplier The timeout value of stop.\r
1068 @param[in] AtapiCommand The atapi command will be used for the\r
1069 transfer.\r
1070 @param[in] AtapiCommandLength The length of the atapi command.\r
1071 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
1072 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
8536cc4b 1073 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 1074 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1075 used by non-blocking mode.\r
a41b5272 1076\r
1077 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.\r
1078 @retval EFI_TIMEOUT The operation is time out.\r
1079 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
1080 @retval EFI_SUCCESS The non data transfer executes successfully.\r
1081\r
1aff716a 1082**/\r
a41b5272 1083EFI_STATUS\r
1084EFIAPI\r
1085AhciNonDataTransfer (\r
1086 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1087 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1088 IN UINT8 Port,\r
1089 IN UINT8 PortMultiplier,\r
1090 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
1091 IN UINT8 AtapiCommandLength,\r
1092 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
1093 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
490b5ea1 1094 IN UINT64 Timeout,\r
1095 IN ATA_NONBLOCK_TASK *Task\r
1096 )\r
a41b5272 1097{\r
490b5ea1 1098 EFI_STATUS Status;\r
a41b5272 1099 UINTN FisBaseAddr;\r
8536cc4b 1100 UINTN Offset;\r
1101 UINT32 PortTfd;\r
a41b5272 1102 EFI_AHCI_COMMAND_FIS CFis;\r
1103 EFI_AHCI_COMMAND_LIST CmdList;\r
1104\r
1105 //\r
1106 // Package read needed\r
1107 //\r
1108 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
1109\r
1110 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
1111\r
1112 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
1113\r
1114 AhciBuildCommand (\r
1115 PciIo,\r
1116 AhciRegisters,\r
1117 Port,\r
1118 PortMultiplier,\r
1119 &CFis,\r
1120 &CmdList,\r
1121 AtapiCommand,\r
1122 AtapiCommandLength,\r
1123 0,\r
1124 NULL,\r
1125 0\r
490b5ea1 1126 );\r
1127\r
a41b5272 1128 Status = AhciStartCommand (\r
490b5ea1 1129 PciIo,\r
1130 Port,\r
a41b5272 1131 0,\r
1132 Timeout\r
1133 );\r
1134 if (EFI_ERROR (Status)) {\r
1135 goto Exit;\r
1136 }\r
490b5ea1 1137\r
a41b5272 1138 //\r
1139 // Wait device sends the Response Fis\r
1140 //\r
1141 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
8536cc4b 1142 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
1143 Status = AhciWaitMemSet (\r
1144 Offset,\r
1145 EFI_AHCI_FIS_TYPE_MASK,\r
1146 EFI_AHCI_FIS_REGISTER_D2H,\r
1147 Timeout\r
1148 );\r
a41b5272 1149\r
8536cc4b 1150 if (EFI_ERROR (Status)) {\r
a41b5272 1151 goto Exit;\r
1152 }\r
1153\r
8536cc4b 1154 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
1155 PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
1156 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
1157 Status = EFI_DEVICE_ERROR;\r
1158 }\r
490b5ea1 1159\r
1160Exit:\r
a41b5272 1161 AhciStopCommand (\r
490b5ea1 1162 PciIo,\r
a41b5272 1163 Port,\r
1164 Timeout\r
1165 );\r
1166\r
1167 AhciDisableFisReceive (\r
490b5ea1 1168 PciIo,\r
a41b5272 1169 Port,\r
1170 Timeout\r
1171 );\r
1172\r
e519983a 1173 AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
1174\r
a41b5272 1175 return Status;\r
1176}\r
1177\r
1178/**\r
1179 Stop command running for giving port\r
1aff716a 1180\r
a41b5272 1181 @param PciIo The PCI IO protocol instance.\r
1182 @param Port The number of port.\r
8536cc4b 1183 @param Timeout The timeout value of stop, uses 100ns as a unit.\r
1aff716a 1184\r
a41b5272 1185 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.\r
1186 @retval EFI_TIMEOUT The operation is time out.\r
1187 @retval EFI_SUCCESS The command stop successfully.\r
1188\r
1189**/\r
1190EFI_STATUS\r
1191EFIAPI\r
1192AhciStopCommand (\r
1193 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1194 IN UINT8 Port,\r
1195 IN UINT64 Timeout\r
1196 )\r
1197{\r
1198 UINT32 Offset;\r
1199 UINT32 Data;\r
1200\r
1201 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1202 Data = AhciReadReg (PciIo, Offset);\r
1203\r
1204 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {\r
490b5ea1 1205 return EFI_SUCCESS;\r
a41b5272 1206 }\r
1207\r
1208 if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
1209 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));\r
1210 }\r
1211\r
8536cc4b 1212 return AhciWaitMmioSet (\r
490b5ea1 1213 PciIo,\r
a41b5272 1214 Offset,\r
1215 EFI_AHCI_PORT_CMD_CR,\r
1216 0,\r
1217 Timeout\r
490b5ea1 1218 );\r
a41b5272 1219}\r
1220\r
1221/**\r
1222 Start command for give slot on specific port.\r
490b5ea1 1223\r
a41b5272 1224 @param PciIo The PCI IO protocol instance.\r
1225 @param Port The number of port.\r
490b5ea1 1226 @param CommandSlot The number of Command Slot.\r
8536cc4b 1227 @param Timeout The timeout value of start, uses 100ns as a unit.\r
490b5ea1 1228\r
a41b5272 1229 @retval EFI_DEVICE_ERROR The command start unsuccessfully.\r
1230 @retval EFI_TIMEOUT The operation is time out.\r
1231 @retval EFI_SUCCESS The command start successfully.\r
1232\r
1233**/\r
1234EFI_STATUS\r
1235EFIAPI\r
1236AhciStartCommand (\r
1237 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1238 IN UINT8 Port,\r
1239 IN UINT8 CommandSlot,\r
1240 IN UINT64 Timeout\r
1241 )\r
1242{\r
1243 UINT32 CmdSlotBit;\r
1244 EFI_STATUS Status;\r
1245 UINT32 PortStatus;\r
1246 UINT32 StartCmd;\r
1247 UINT32 PortTfd;\r
1248 UINT32 Offset;\r
1249 UINT32 Capability;\r
1250\r
1251 //\r
1252 // Collect AHCI controller information\r
1253 //\r
1254 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
1255\r
1256 CmdSlotBit = (UINT32) (1 << CommandSlot);\r
1257\r
1258 AhciClearPortStatus (\r
1259 PciIo,\r
1260 Port\r
1261 );\r
1262\r
1263 Status = AhciEnableFisReceive (\r
1aff716a 1264 PciIo,\r
a41b5272 1265 Port,\r
1266 Timeout\r
1267 );\r
490b5ea1 1268\r
a41b5272 1269 if (EFI_ERROR (Status)) {\r
1270 return Status;\r
1271 }\r
1272\r
a41b5272 1273 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1274 PortStatus = AhciReadReg (PciIo, Offset);\r
490b5ea1 1275\r
a41b5272 1276 StartCmd = 0;\r
1277 if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
1278 StartCmd = AhciReadReg (PciIo, Offset);\r
1279 StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;\r
1280 StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;\r
1281 }\r
1282\r
1283 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
1284 PortTfd = AhciReadReg (PciIo, Offset);\r
1285\r
1286 if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
1287 if ((Capability & BIT24) != 0) {\r
1288 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
cbd2a4b3 1289 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);\r
a41b5272 1290\r
8536cc4b 1291 AhciWaitMmioSet (\r
490b5ea1 1292 PciIo,\r
a41b5272 1293 Offset,\r
cbd2a4b3 1294 EFI_AHCI_PORT_CMD_CLO,\r
a41b5272 1295 0,\r
1296 Timeout\r
490b5ea1 1297 );\r
a41b5272 1298 }\r
1299 }\r
1300\r
1301 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1302 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);\r
1303\r
e519983a 1304 //\r
1305 // Setting the command\r
1306 //\r
1307 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
1308 AhciAndReg (PciIo, Offset, 0);\r
1309 AhciOrReg (PciIo, Offset, CmdSlotBit);\r
1310\r
1311 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
1312 AhciAndReg (PciIo, Offset, 0);\r
1313 AhciOrReg (PciIo, Offset, CmdSlotBit);\r
1314\r
a41b5272 1315 return EFI_SUCCESS;\r
1316}\r
1317\r
1318/**\r
1319 Do AHCI port reset.\r
1320\r
1321 @param PciIo The PCI IO protocol instance.\r
1322 @param Port The number of port.\r
8536cc4b 1323 @param Timeout The timeout value of reset, uses 100ns as a unit.\r
1aff716a 1324\r
a41b5272 1325 @retval EFI_DEVICE_ERROR The port reset unsuccessfully\r
1326 @retval EFI_TIMEOUT The reset operation is time out.\r
1327 @retval EFI_SUCCESS The port reset successfully.\r
1328\r
1329**/\r
1330EFI_STATUS\r
1331EFIAPI\r
1332AhciPortReset (\r
1333 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1334 IN UINT8 Port,\r
1335 IN UINT64 Timeout\r
1336 )\r
1337{\r
1338 EFI_STATUS Status;\r
490b5ea1 1339 UINT32 Offset;\r
1340\r
a41b5272 1341 AhciClearPortStatus (PciIo, Port);\r
1342\r
1343 AhciStopCommand (PciIo, Port, Timeout);\r
1344\r
1345 AhciDisableFisReceive (PciIo, Port, Timeout);\r
1346\r
1347 AhciEnableFisReceive (PciIo, Port, Timeout);\r
1348\r
1349 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
1350\r
1351 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);\r
1352\r
1353 //\r
490b5ea1 1354 // wait 5 millisecond before de-assert DET\r
a41b5272 1355 //\r
1356 MicroSecondDelay (5000);\r
1357\r
1358 AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK);\r
1359\r
1360 //\r
490b5ea1 1361 // wait 5 millisecond before de-assert DET\r
a41b5272 1362 //\r
1363 MicroSecondDelay (5000);\r
1364\r
1365 //\r
1366 // Wait for communication to be re-established\r
1367 //\r
1368 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
8536cc4b 1369 Status = AhciWaitMmioSet (\r
a41b5272 1370 PciIo,\r
1371 Offset,\r
1372 EFI_AHCI_PORT_SSTS_DET_MASK,\r
1373 EFI_AHCI_PORT_SSTS_DET_PCE,\r
1374 Timeout\r
490b5ea1 1375 );\r
a41b5272 1376\r
1377 if (EFI_ERROR (Status)) {\r
1378 return Status;\r
1379 }\r
1380\r
1381 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
1382 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_ERR_CLEAR);\r
1383\r
1384 return EFI_SUCCESS;\r
1385}\r
1386\r
1387/**\r
1388 Do AHCI HBA reset.\r
490b5ea1 1389\r
a41b5272 1390 @param PciIo The PCI IO protocol instance.\r
8536cc4b 1391 @param Timeout The timeout value of reset, uses 100ns as a unit.\r
490b5ea1 1392\r
a41b5272 1393 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.\r
1394 @retval EFI_TIMEOUT The reset operation is time out.\r
1395 @retval EFI_SUCCESS AHCI controller is reset successfully.\r
1396\r
1397**/\r
1398EFI_STATUS\r
1399EFIAPI\r
1400AhciReset (\r
1401 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1402 IN UINT64 Timeout\r
1aff716a 1403 )\r
a41b5272 1404{\r
a41b5272 1405 UINT32 Delay;\r
1406 UINT32 Value;\r
1407\r
1408 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
1409\r
1410 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
1411\r
a41b5272 1412 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
1413\r
1414 do {\r
1415 Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
1416\r
1417 if ((Value & EFI_AHCI_GHC_RESET) == 0) {\r
1418 break;\r
1419 }\r
1420\r
1421 //\r
1422 // Stall for 100 microseconds.\r
1423 //\r
1424 MicroSecondDelay(100);\r
1425\r
1426 Delay--;\r
1427 } while (Delay > 0);\r
1428\r
1429 if (Delay == 0) {\r
1430 return EFI_TIMEOUT;\r
1431 }\r
1432\r
1433 return EFI_SUCCESS;\r
1434}\r
1435\r
12873d57 1436/**\r
1437 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
1438\r
1439 @param PciIo The PCI IO protocol instance.\r
1440 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1441 @param Port The number of port.\r
1442 @param PortMultiplier The timeout value of stop.\r
1443 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1444\r
1445 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.\r
1446 @retval Others Fail to get return status data.\r
1447\r
1448**/\r
1449EFI_STATUS\r
1450EFIAPI\r
1451AhciAtaSmartReturnStatusCheck (\r
1452 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1453 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1454 IN UINT8 Port,\r
1455 IN UINT8 PortMultiplier,\r
1456 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
1457 )\r
1458{\r
1459 EFI_STATUS Status;\r
1460 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1461 UINT8 LBAMid;\r
1462 UINT8 LBAHigh;\r
1463 UINTN FisBaseAddr;\r
1464 UINT32 Value;\r
1465\r
1466 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1467\r
1468 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1469 AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;\r
1470 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1471 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1472\r
1473 //\r
1474 // Send S.M.A.R.T Read Return Status command to device\r
1475 //\r
1476 Status = AhciNonDataTransfer (\r
1477 PciIo,\r
1478 AhciRegisters,\r
1479 (UINT8)Port,\r
1480 (UINT8)PortMultiplier,\r
1481 NULL,\r
1482 0,\r
1483 &AtaCommandBlock,\r
1484 AtaStatusBlock,\r
490b5ea1 1485 ATA_ATAPI_TIMEOUT,\r
1486 NULL\r
12873d57 1487 );\r
1488\r
1489 if (EFI_ERROR (Status)) {\r
cffd2171
EL
1490 REPORT_STATUS_CODE (\r
1491 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
1492 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
1493 );\r
12873d57 1494 return EFI_DEVICE_ERROR;\r
1495 }\r
1496\r
cffd2171
EL
1497 REPORT_STATUS_CODE (\r
1498 EFI_PROGRESS_CODE,\r
1499 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
1500 );\r
1501\r
12873d57 1502 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1503\r
1504 Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
1505\r
1506 if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
1507 LBAMid = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];\r
1508 LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];\r
1509\r
1510 if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
1511 //\r
1512 // The threshold exceeded condition is not detected by the device\r
1513 //\r
1514 DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
cffd2171
EL
1515 REPORT_STATUS_CODE (\r
1516 EFI_PROGRESS_CODE,\r
1517 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
1518 );\r
12873d57 1519 } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
1520 //\r
1521 // The threshold exceeded condition is detected by the device\r
1522 //\r
1523 DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
cffd2171
EL
1524 REPORT_STATUS_CODE (\r
1525 EFI_PROGRESS_CODE,\r
1526 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
1527 );\r
12873d57 1528 }\r
1529 }\r
1530\r
1531 return EFI_SUCCESS;\r
1532}\r
1533\r
1534/**\r
1535 Enable SMART command of the disk if supported.\r
1536\r
1537 @param PciIo The PCI IO protocol instance.\r
1538 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1539 @param Port The number of port.\r
1540 @param PortMultiplier The timeout value of stop.\r
1541 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
1542 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1543\r
1544**/\r
1545VOID\r
1546EFIAPI\r
1547AhciAtaSmartSupport (\r
1548 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1549 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1550 IN UINT8 Port,\r
1551 IN UINT8 PortMultiplier,\r
490b5ea1 1552 IN EFI_IDENTIFY_DATA *IdentifyData,\r
12873d57 1553 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
1554 )\r
1555{\r
1556 EFI_STATUS Status;\r
1557 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1558\r
1559 //\r
1560 // Detect if the device supports S.M.A.R.T.\r
1561 //\r
1562 if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
1563 //\r
1564 // S.M.A.R.T is not supported by the device\r
1565 //\r
1aff716a 1566 DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",\r
12873d57 1567 Port, PortMultiplier));\r
cffd2171
EL
1568 REPORT_STATUS_CODE (\r
1569 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
1570 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
1571 );\r
12873d57 1572 } else {\r
1573 //\r
1574 // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
1575 //\r
1576 if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
cffd2171
EL
1577\r
1578 REPORT_STATUS_CODE (\r
1579 EFI_PROGRESS_CODE,\r
1580 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)\r
1581 );\r
1582\r
12873d57 1583 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1584\r
1585 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1586 AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;\r
1587 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1588 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1589\r
1590 //\r
1591 // Send S.M.A.R.T Enable command to device\r
1592 //\r
1593 Status = AhciNonDataTransfer (\r
1594 PciIo,\r
1595 AhciRegisters,\r
1596 (UINT8)Port,\r
1597 (UINT8)PortMultiplier,\r
1598 NULL,\r
1599 0,\r
1600 &AtaCommandBlock,\r
1601 AtaStatusBlock,\r
490b5ea1 1602 ATA_ATAPI_TIMEOUT,\r
1603 NULL\r
12873d57 1604 );\r
1605\r
1606\r
1607 if (!EFI_ERROR (Status)) {\r
1608 //\r
1609 // Send S.M.A.R.T AutoSave command to device\r
1610 //\r
1611 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1612\r
1613 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1614 AtaCommandBlock.AtaFeatures = 0xD2;\r
1615 AtaCommandBlock.AtaSectorCount = 0xF1;\r
1616 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1617 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1618\r
1619 Status = AhciNonDataTransfer (\r
1620 PciIo,\r
1621 AhciRegisters,\r
1622 (UINT8)Port,\r
1623 (UINT8)PortMultiplier,\r
1624 NULL,\r
1625 0,\r
1626 &AtaCommandBlock,\r
1627 AtaStatusBlock,\r
490b5ea1 1628 ATA_ATAPI_TIMEOUT,\r
1629 NULL\r
12873d57 1630 );\r
1631\r
1632 if (!EFI_ERROR (Status)) {\r
1633 Status = AhciAtaSmartReturnStatusCheck (\r
1634 PciIo,\r
1635 AhciRegisters,\r
1636 (UINT8)Port,\r
1637 (UINT8)PortMultiplier,\r
1638 AtaStatusBlock\r
1639 );\r
1640 }\r
1641 }\r
1642 }\r
490b5ea1 1643 DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",\r
12873d57 1644 Port, PortMultiplier));\r
1645 }\r
1646\r
1647 return ;\r
1648}\r
1649\r
a41b5272 1650/**\r
1651 Send Buffer cmd to specific device.\r
1aff716a 1652\r
aca84419 1653 @param PciIo The PCI IO protocol instance.\r
1654 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1655 @param Port The number of port.\r
a41b5272 1656 @param PortMultiplier The timeout value of stop.\r
aca84419 1657 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1658\r
1659 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1660 @retval EFI_TIMEOUT The operation is time out.\r
1661 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1662 @retval EFI_SUCCESS The cmd executes successfully.\r
1663\r
1664**/\r
1665EFI_STATUS\r
1666EFIAPI\r
1667AhciIdentify (\r
1668 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1669 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1670 IN UINT8 Port,\r
1671 IN UINT8 PortMultiplier,\r
1aff716a 1672 IN OUT EFI_IDENTIFY_DATA *Buffer\r
a41b5272 1673 )\r
1674{\r
1675 EFI_STATUS Status;\r
1676 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1677 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1678\r
1679 if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {\r
1680 return EFI_INVALID_PARAMETER;\r
1681 }\r
1682\r
1683 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1684 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 1685\r
a41b5272 1686 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
1687 AtaCommandBlock.AtaSectorCount = 1;\r
1688\r
1689 Status = AhciPioTransfer (\r
1690 PciIo,\r
1691 AhciRegisters,\r
1692 Port,\r
1693 PortMultiplier,\r
1694 NULL,\r
1695 0,\r
1696 TRUE,\r
1697 &AtaCommandBlock,\r
1698 &AtaStatusBlock,\r
1699 Buffer,\r
1700 sizeof (EFI_IDENTIFY_DATA),\r
1aff716a 1701 ATA_ATAPI_TIMEOUT,\r
490b5ea1 1702 NULL\r
a41b5272 1703 );\r
1704\r
1705 return Status;\r
1706}\r
1707\r
1708/**\r
1709 Send Buffer cmd to specific device.\r
1aff716a 1710\r
aca84419 1711 @param PciIo The PCI IO protocol instance.\r
1712 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1713 @param Port The number of port.\r
a41b5272 1714 @param PortMultiplier The timeout value of stop.\r
aca84419 1715 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1716\r
1717 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1718 @retval EFI_TIMEOUT The operation is time out.\r
1719 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1720 @retval EFI_SUCCESS The cmd executes successfully.\r
1721\r
1722**/\r
1723EFI_STATUS\r
1724EFIAPI\r
1725AhciIdentifyPacket (\r
1726 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1727 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1728 IN UINT8 Port,\r
1729 IN UINT8 PortMultiplier,\r
1aff716a 1730 IN OUT EFI_IDENTIFY_DATA *Buffer\r
a41b5272 1731 )\r
1732{\r
1733 EFI_STATUS Status;\r
1734 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1735 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1736\r
1737 if (PciIo == NULL || AhciRegisters == NULL) {\r
1738 return EFI_INVALID_PARAMETER;\r
1739 }\r
490b5ea1 1740\r
a41b5272 1741 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1742 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1743\r
1744 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DEVICE;\r
1745 AtaCommandBlock.AtaSectorCount = 1;\r
1746\r
1747 Status = AhciPioTransfer (\r
1748 PciIo,\r
1749 AhciRegisters,\r
1750 Port,\r
1751 PortMultiplier,\r
1752 NULL,\r
1753 0,\r
1754 TRUE,\r
1755 &AtaCommandBlock,\r
1756 &AtaStatusBlock,\r
1757 Buffer,\r
1758 sizeof (EFI_IDENTIFY_DATA),\r
490b5ea1 1759 ATA_ATAPI_TIMEOUT,\r
1760 NULL\r
a41b5272 1761 );\r
1762\r
1763 return Status;\r
1764}\r
1765\r
1766/**\r
1767 Send SET FEATURE cmd on specific device.\r
1aff716a 1768\r
aca84419 1769 @param PciIo The PCI IO protocol instance.\r
1770 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1771 @param Port The number of port.\r
a41b5272 1772 @param PortMultiplier The timeout value of stop.\r
aca84419 1773 @param Feature The data to send Feature register.\r
1774 @param FeatureSpecificData The specific data for SET FEATURE cmd.\r
a41b5272 1775\r
1776 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1777 @retval EFI_TIMEOUT The operation is time out.\r
1778 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1779 @retval EFI_SUCCESS The cmd executes successfully.\r
1780\r
1781**/\r
1782EFI_STATUS\r
1783EFIAPI\r
1784AhciDeviceSetFeature (\r
1785 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1786 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1787 IN UINT8 Port,\r
1788 IN UINT8 PortMultiplier,\r
1789 IN UINT16 Feature,\r
1790 IN UINT32 FeatureSpecificData\r
1791 )\r
1792{\r
1793 EFI_STATUS Status;\r
1794 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1795 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1796\r
1797 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1798 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 1799\r
a41b5272 1800 AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;\r
1801 AtaCommandBlock.AtaFeatures = (UINT8) Feature;\r
1802 AtaCommandBlock.AtaFeaturesExp = (UINT8) (Feature >> 8);\r
1803 AtaCommandBlock.AtaSectorCount = (UINT8) FeatureSpecificData;\r
1804 AtaCommandBlock.AtaSectorNumber = (UINT8) (FeatureSpecificData >> 8);\r
1805 AtaCommandBlock.AtaCylinderLow = (UINT8) (FeatureSpecificData >> 16);\r
1806 AtaCommandBlock.AtaCylinderHigh = (UINT8) (FeatureSpecificData >> 24);\r
1807\r
1808 Status = AhciNonDataTransfer (\r
1809 PciIo,\r
1810 AhciRegisters,\r
1811 (UINT8)Port,\r
1812 (UINT8)PortMultiplier,\r
1813 NULL,\r
1814 0,\r
1815 &AtaCommandBlock,\r
1816 &AtaStatusBlock,\r
1aff716a 1817 ATA_ATAPI_TIMEOUT,\r
490b5ea1 1818 NULL\r
a41b5272 1819 );\r
1820\r
1821 return Status;\r
1822}\r
1823\r
1824/**\r
1aff716a 1825 This function is used to send out ATAPI commands conforms to the Packet Command\r
a41b5272 1826 with PIO Protocol.\r
1827\r
1828 @param PciIo The PCI IO protocol instance.\r
1829 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1aff716a 1830 @param Port The number of port.\r
a41b5272 1831 @param PortMultiplier The number of port multiplier.\r
1832 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.\r
1833\r
1834 @retval EFI_SUCCESS send out the ATAPI packet command successfully\r
1835 and device sends data successfully.\r
1836 @retval EFI_DEVICE_ERROR the device failed to send data.\r
1837\r
1838**/\r
1839EFI_STATUS\r
1840EFIAPI\r
1841AhciPacketCommandExecute (\r
1842 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1843 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1844 IN UINT8 Port,\r
1845 IN UINT8 PortMultiplier,\r
1846 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
1847 )\r
1848{\r
1849 EFI_STATUS Status;\r
1850 VOID *Buffer;\r
1851 UINT32 Length;\r
1852 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1853 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1854 BOOLEAN Read;\r
a41b5272 1855\r
1856 if (Packet == NULL || Packet->Cdb == NULL) {\r
1857 return EFI_INVALID_PARAMETER;\r
1858 }\r
1859\r
1860 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1861 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1862 AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;\r
1863 //\r
1864 // No OVL; No DMA\r
1865 //\r
1866 AtaCommandBlock.AtaFeatures = 0x00;\r
1867 //\r
1868 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
1869 // determine how many data should be transferred.\r
1870 //\r
1871 AtaCommandBlock.AtaCylinderLow = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
1872 AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);\r
1873\r
1874 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1875 Buffer = Packet->InDataBuffer;\r
1876 Length = Packet->InTransferLength;\r
1877 Read = TRUE;\r
1878 } else {\r
1879 Buffer = Packet->OutDataBuffer;\r
1880 Length = Packet->OutTransferLength;\r
1881 Read = FALSE;\r
1882 }\r
1883\r
490b5ea1 1884 if (Length == 0) {\r
a41b5272 1885 Status = AhciNonDataTransfer (\r
1886 PciIo,\r
1887 AhciRegisters,\r
1888 Port,\r
1889 PortMultiplier,\r
1890 Packet->Cdb,\r
1891 Packet->CdbLength,\r
1892 &AtaCommandBlock,\r
1893 &AtaStatusBlock,\r
1aff716a 1894 Packet->Timeout,\r
490b5ea1 1895 NULL\r
a41b5272 1896 );\r
1897 } else {\r
cbd2a4b3 1898 Status = AhciPioTransfer (\r
1899 PciIo,\r
1900 AhciRegisters,\r
1901 Port,\r
1902 PortMultiplier,\r
1903 Packet->Cdb,\r
1904 Packet->CdbLength,\r
1905 Read,\r
1906 &AtaCommandBlock,\r
1907 &AtaStatusBlock,\r
1908 Buffer,\r
1909 Length,\r
1aff716a 1910 Packet->Timeout,\r
cbd2a4b3 1911 NULL\r
1912 );\r
a41b5272 1913 }\r
1914 return Status;\r
1915}\r
1916\r
1917/**\r
1918 Allocate transfer-related data struct which is used at AHCI mode.\r
1aff716a 1919\r
a41b5272 1920 @param PciIo The PCI IO protocol instance.\r
1921 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1922\r
1923**/\r
1924EFI_STATUS\r
1925EFIAPI\r
1926AhciCreateTransferDescriptor (\r
1927 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1928 IN OUT EFI_AHCI_REGISTERS *AhciRegisters\r
1929 )\r
1930{\r
1931 EFI_STATUS Status;\r
1932 UINTN Bytes;\r
1933 VOID *Buffer;\r
1934\r
1935 UINT32 Capability;\r
467cacbf 1936 UINT32 PortImplementBitMap;\r
a41b5272 1937 UINT8 MaxPortNumber;\r
1938 UINT8 MaxCommandSlotNumber;\r
1939 BOOLEAN Support64Bit;\r
1940 UINT64 MaxReceiveFisSize;\r
1941 UINT64 MaxCommandListSize;\r
1942 UINT64 MaxCommandTableSize;\r
ed365e93 1943 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr;\r
1944 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr;\r
1945 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr;\r
a41b5272 1946\r
1947 Buffer = NULL;\r
1948 //\r
1949 // Collect AHCI controller information\r
1950 //\r
1951 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
a41b5272 1952 //\r
1953 // Get the number of command slots per port supported by this HBA.\r
1954 //\r
1955 MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
aca84419 1956 Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
467cacbf 1957 \r
1958 PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
1959 //\r
1960 // Get the highest bit of implemented ports which decides how many bytes are allocated for recived FIS.\r
1961 //\r
1962 MaxPortNumber = (UINT8)(UINTN)(HighBitSet32(PortImplementBitMap) + 1);\r
1963 if (MaxPortNumber == 0) {\r
1964 return EFI_DEVICE_ERROR;\r
1965 }\r
a41b5272 1966\r
1967 MaxReceiveFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1968 Status = PciIo->AllocateBuffer (\r
1969 PciIo,\r
1970 AllocateAnyPages,\r
1971 EfiBootServicesData,\r
ed365e93 1972 EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
a41b5272 1973 &Buffer,\r
1974 0\r
1975 );\r
1976\r
1977 if (EFI_ERROR (Status)) {\r
1978 return EFI_OUT_OF_RESOURCES;\r
1979 }\r
1980\r
5dec0c68 1981 ZeroMem (Buffer, (UINTN)MaxReceiveFisSize);\r
a41b5272 1982\r
1983 AhciRegisters->AhciRFis = Buffer;\r
1984 AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;\r
5dec0c68 1985 Bytes = (UINTN)MaxReceiveFisSize;\r
a41b5272 1986\r
1987 Status = PciIo->Map (\r
1988 PciIo,\r
1989 EfiPciIoOperationBusMasterCommonBuffer,\r
1990 Buffer,\r
1991 &Bytes,\r
ed365e93 1992 &AhciRFisPciAddr,\r
a41b5272 1993 &AhciRegisters->MapRFis\r
1994 );\r
1995\r
1996 if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {\r
1997 //\r
1aff716a 1998 // Map error or unable to map the whole RFis buffer into a contiguous region.\r
a41b5272 1999 //\r
2000 Status = EFI_OUT_OF_RESOURCES;\r
2001 goto Error6;\r
2002 }\r
2003\r
ed365e93 2004 if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {\r
a41b5272 2005 //\r
2006 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2007 //\r
2008 Status = EFI_DEVICE_ERROR;\r
2009 goto Error5;\r
2010 }\r
ed365e93 2011 AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;\r
a41b5272 2012\r
2013 //\r
2014 // Allocate memory for command list\r
2015 // Note that the implemenation is a single task model which only use a command list for all ports.\r
2016 //\r
2017 Buffer = NULL;\r
2018 MaxCommandListSize = MaxCommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST);\r
2019 Status = PciIo->AllocateBuffer (\r
2020 PciIo,\r
2021 AllocateAnyPages,\r
2022 EfiBootServicesData,\r
ed365e93 2023 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
a41b5272 2024 &Buffer,\r
2025 0\r
2026 );\r
2027\r
2028 if (EFI_ERROR (Status)) {\r
2029 //\r
1aff716a 2030 // Free mapped resource.\r
a41b5272 2031 //\r
2032 Status = EFI_OUT_OF_RESOURCES;\r
2033 goto Error5;\r
2034 }\r
2035\r
5dec0c68 2036 ZeroMem (Buffer, (UINTN)MaxCommandListSize);\r
a41b5272 2037\r
2038 AhciRegisters->AhciCmdList = Buffer;\r
2039 AhciRegisters->MaxCommandListSize = MaxCommandListSize;\r
5dec0c68 2040 Bytes = (UINTN)MaxCommandListSize;\r
a41b5272 2041\r
2042 Status = PciIo->Map (\r
2043 PciIo,\r
2044 EfiPciIoOperationBusMasterCommonBuffer,\r
2045 Buffer,\r
2046 &Bytes,\r
ed365e93 2047 &AhciCmdListPciAddr,\r
a41b5272 2048 &AhciRegisters->MapCmdList\r
2049 );\r
2050\r
2051 if (EFI_ERROR (Status) || (Bytes != MaxCommandListSize)) {\r
2052 //\r
2053 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2054 //\r
2055 Status = EFI_OUT_OF_RESOURCES;\r
2056 goto Error4;\r
2057 }\r
2058\r
ed365e93 2059 if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {\r
a41b5272 2060 //\r
2061 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2062 //\r
2063 Status = EFI_DEVICE_ERROR;\r
2064 goto Error3;\r
2065 }\r
ed365e93 2066 AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;\r
a41b5272 2067\r
2068 //\r
2069 // Allocate memory for command table\r
2070 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.\r
2071 //\r
2072 Buffer = NULL;\r
2073 MaxCommandTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);\r
2074\r
2075 Status = PciIo->AllocateBuffer (\r
2076 PciIo,\r
2077 AllocateAnyPages,\r
2078 EfiBootServicesData,\r
ed365e93 2079 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
a41b5272 2080 &Buffer,\r
2081 0\r
2082 );\r
2083\r
2084 if (EFI_ERROR (Status)) {\r
2085 //\r
1aff716a 2086 // Free mapped resource.\r
a41b5272 2087 //\r
2088 Status = EFI_OUT_OF_RESOURCES;\r
2089 goto Error3;\r
2090 }\r
2091\r
5dec0c68 2092 ZeroMem (Buffer, (UINTN)MaxCommandTableSize);\r
a41b5272 2093\r
2094 AhciRegisters->AhciCommandTable = Buffer;\r
2095 AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;\r
5dec0c68 2096 Bytes = (UINTN)MaxCommandTableSize;\r
a41b5272 2097\r
2098 Status = PciIo->Map (\r
2099 PciIo,\r
2100 EfiPciIoOperationBusMasterCommonBuffer,\r
2101 Buffer,\r
2102 &Bytes,\r
ed365e93 2103 &AhciCommandTablePciAddr,\r
a41b5272 2104 &AhciRegisters->MapCommandTable\r
2105 );\r
2106\r
2107 if (EFI_ERROR (Status) || (Bytes != MaxCommandTableSize)) {\r
2108 //\r
2109 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2110 //\r
2111 Status = EFI_OUT_OF_RESOURCES;\r
2112 goto Error2;\r
2113 }\r
2114\r
ed365e93 2115 if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {\r
a41b5272 2116 //\r
2117 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2118 //\r
2119 Status = EFI_DEVICE_ERROR;\r
2120 goto Error1;\r
2121 }\r
ed365e93 2122 AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;\r
a41b5272 2123\r
2124 return EFI_SUCCESS;\r
2125 //\r
1aff716a 2126 // Map error or unable to map the whole CmdList buffer into a contiguous region.\r
a41b5272 2127 //\r
2128Error1:\r
2129 PciIo->Unmap (\r
2130 PciIo,\r
2131 AhciRegisters->MapCommandTable\r
2132 );\r
2133Error2:\r
2134 PciIo->FreeBuffer (\r
2135 PciIo,\r
ed365e93 2136 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
a41b5272 2137 AhciRegisters->AhciCommandTable\r
2138 );\r
2139Error3:\r
2140 PciIo->Unmap (\r
2141 PciIo,\r
2142 AhciRegisters->MapCmdList\r
2143 );\r
2144Error4:\r
2145 PciIo->FreeBuffer (\r
2146 PciIo,\r
ed365e93 2147 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
a41b5272 2148 AhciRegisters->AhciCmdList\r
2149 );\r
2150Error5:\r
2151 PciIo->Unmap (\r
2152 PciIo,\r
2153 AhciRegisters->MapRFis\r
2154 );\r
2155Error6:\r
2156 PciIo->FreeBuffer (\r
2157 PciIo,\r
ed365e93 2158 EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
a41b5272 2159 AhciRegisters->AhciRFis\r
2160 );\r
2161\r
2162 return Status;\r
2163}\r
2164\r
2165/**\r
2166 Initialize ATA host controller at AHCI mode.\r
2167\r
1aff716a 2168 The function is designed to initialize ATA host controller.\r
2169\r
a41b5272 2170 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
2171\r
2172**/\r
2173EFI_STATUS\r
2174EFIAPI\r
2175AhciModeInitialization (\r
2176 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance\r
2177 )\r
2178{\r
2179 EFI_STATUS Status;\r
2180 EFI_PCI_IO_PROTOCOL *PciIo;\r
2181 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2182 UINT32 Capability;\r
2183 UINT8 MaxPortNumber;\r
2184 UINT32 PortImplementBitMap;\r
a41b5272 2185\r
2186 EFI_AHCI_REGISTERS *AhciRegisters;\r
2187\r
2188 UINT8 Port;\r
2189 DATA_64 Data64;\r
2190 UINT32 Offset;\r
2191 UINT32 Data;\r
2192 EFI_IDENTIFY_DATA Buffer;\r
2193 EFI_ATA_DEVICE_TYPE DeviceType;\r
2194 EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
2195 EFI_ATA_TRANSFER_MODE TransferMode;\r
cbd2a4b3 2196 UINT32 PhyDetectDelay;\r
2197\r
a41b5272 2198 if (Instance == NULL) {\r
2199 return EFI_INVALID_PARAMETER;\r
2200 }\r
2201\r
2202 PciIo = Instance->PciIo;\r
2203 IdeInit = Instance->IdeControllerInit;\r
2204\r
1aff716a 2205 Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT);\r
a41b5272 2206\r
2207 if (EFI_ERROR (Status)) {\r
2208 return EFI_DEVICE_ERROR;\r
2209 }\r
2210\r
2211 //\r
2212 // Enable AE before accessing any AHCI registers\r
2213 //\r
2214 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
2215\r
2216 //\r
2217 // Collect AHCI controller information\r
2218 //\r
2219 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
2220\r
2221 //\r
2222 // Get the number of command slots per port supported by this HBA.\r
2223 //\r
cbd2a4b3 2224 MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
a41b5272 2225\r
2226 //\r
2227 // Get the bit map of those ports exposed by this HBA.\r
1aff716a 2228 // It indicates which ports that the HBA supports are available for software to use.\r
a41b5272 2229 //\r
2230 PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
1aff716a 2231\r
a41b5272 2232 AhciRegisters = &Instance->AhciRegisters;\r
2233 Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
2234\r
2235 if (EFI_ERROR (Status)) {\r
2236 return EFI_OUT_OF_RESOURCES;\r
2237 }\r
2238\r
6b13aa60 2239 for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port ++) {\r
a41b5272 2240 if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
6b13aa60 2241 //\r
2242 // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.\r
2243 //\r
2244 if ((MaxPortNumber--) == 0) {\r
2245 //\r
2246 // Should never be here.\r
2247 //\r
2248 ASSERT (FALSE);\r
2249 return EFI_SUCCESS;\r
2250 }\r
2251\r
cbd2a4b3 2252 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
2253\r
2254 //\r
2255 // Initialize FIS Base Address Register and Command List Base Address Register for use.\r
2256 //\r
2257 Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
2258 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
2259 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2260 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
2261 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2262\r
2263 Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
2264 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
2265 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2266 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
2267 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2268\r
a41b5272 2269 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
a41b5272 2270 Data = AhciReadReg (PciIo, Offset);\r
2271 if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
2272 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
2273 }\r
a41b5272 2274\r
cbd2a4b3 2275 if ((Capability & EFI_AHCI_CAP_SSS) != 0) {\r
2276 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
2277 }\r
2278\r
2279 //\r
2280 // Disable aggressive power management.\r
2281 //\r
2282 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
2283 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
2284 //\r
2285 // Disable the reporting of the corresponding interrupt to system software.\r
2286 //\r
2287 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
2288 AhciAndReg (PciIo, Offset, 0);\r
a41b5272 2289\r
cbd2a4b3 2290 //\r
2291 // Now inform the IDE Controller Init Module.\r
2292 //\r
2293 IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
2294\r
2295 //\r
2296 // Enable FIS Receive DMA engine for the first D2H FIS.\r
2297 //\r
2298 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
2299 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
8536cc4b 2300 Status = AhciWaitMmioSet (\r
1aff716a 2301 PciIo,\r
cbd2a4b3 2302 Offset,\r
2303 EFI_AHCI_PORT_CMD_FR,\r
2304 EFI_AHCI_PORT_CMD_FR,\r
2305 EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT\r
2306 );\r
2307 if (EFI_ERROR (Status)) {\r
a41b5272 2308 continue;\r
2309 }\r
cbd2a4b3 2310\r
a41b5272 2311 //\r
cbd2a4b3 2312 // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.\r
2313 // It's the requirment from SATA1.0a spec section 5.2.\r
a41b5272 2314 //\r
cbd2a4b3 2315 PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;\r
2316 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
2317 do {\r
2318 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
2319 if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {\r
2320 break;\r
a41b5272 2321 }\r
2322\r
cbd2a4b3 2323 MicroSecondDelay (1000);\r
2324 PhyDetectDelay--;\r
2325 } while (PhyDetectDelay > 0);\r
2326\r
2327 if (PhyDetectDelay == 0) {\r
a41b5272 2328 //\r
cbd2a4b3 2329 // No device detected at this port.\r
2721fabc 2330 // Clear PxCMD.SUD for those ports at which there are no device present.\r
a41b5272 2331 //\r
2721fabc 2332 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
2333 AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_SUD));\r
cbd2a4b3 2334 continue;\r
2335 }\r
a41b5272 2336\r
cbd2a4b3 2337 //\r
2338 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ\r
2339 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.\r
2340 //\r
2341 PhyDetectDelay = 16 * 1000;\r
2342 do {\r
2343 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
2344 if (AhciReadReg(PciIo, Offset) != 0) {\r
2345 AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset));\r
2346 }\r
2347 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
a41b5272 2348\r
cbd2a4b3 2349 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;\r
2350 if (Data == 0) {\r
2351 break;\r
2352 }\r
a41b5272 2353\r
cbd2a4b3 2354 MicroSecondDelay (1000);\r
2355 PhyDetectDelay--;\r
2356 } while (PhyDetectDelay > 0);\r
1aff716a 2357\r
cbd2a4b3 2358 if (PhyDetectDelay == 0) {\r
2359 continue;\r
2360 }\r
a41b5272 2361\r
cbd2a4b3 2362 //\r
2363 // When the first D2H register FIS is received, the content of PxSIG register is updated.\r
2364 //\r
2365 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
8536cc4b 2366 Status = AhciWaitMmioSet (\r
1aff716a 2367 PciIo,\r
cbd2a4b3 2368 Offset,\r
2369 0x0000FFFF,\r
2370 0x00000101,\r
2371 EFI_TIMER_PERIOD_SECONDS(16)\r
2372 );\r
2373 if (EFI_ERROR (Status)) {\r
2374 continue;\r
2375 }\r
a41b5272 2376\r
cbd2a4b3 2377 Data = AhciReadReg (PciIo, Offset);\r
2378 if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
2379 Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
a41b5272 2380\r
cbd2a4b3 2381 if (EFI_ERROR (Status)) {\r
a41b5272 2382 continue;\r
2383 }\r
aca84419 2384\r
cbd2a4b3 2385 DeviceType = EfiIdeCdrom;\r
2386 } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
2387 Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
a41b5272 2388\r
a41b5272 2389 if (EFI_ERROR (Status)) {\r
cbd2a4b3 2390 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
a41b5272 2391 continue;\r
2392 }\r
2393\r
cbd2a4b3 2394 DeviceType = EfiIdeHarddisk;\r
2395 } else {\r
2396 continue;\r
2397 }\r
1aff716a 2398 DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n",\r
cbd2a4b3 2399 Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
a41b5272 2400\r
cbd2a4b3 2401 //\r
2402 // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
2403 //\r
fc80ee69 2404 if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {\r
cbd2a4b3 2405 AhciAtaSmartSupport (\r
2406 PciIo,\r
2407 AhciRegisters,\r
2408 Port,\r
2409 0,\r
2410 &Buffer,\r
2411 NULL\r
2412 );\r
2413 }\r
a41b5272 2414\r
cbd2a4b3 2415 //\r
2416 // Submit identify data to IDE controller init driver\r
2417 //\r
2418 IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
aca84419 2419\r
cbd2a4b3 2420 //\r
2421 // Now start to config ide device parameter and transfer mode.\r
2422 //\r
2423 Status = IdeInit->CalculateMode (\r
2424 IdeInit,\r
2425 Port,\r
2426 0,\r
2427 &SupportedModes\r
2428 );\r
2429 if (EFI_ERROR (Status)) {\r
2430 DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
2431 continue;\r
2432 }\r
2433\r
2434 //\r
2435 // Set best supported PIO mode on this IDE device\r
2436 //\r
2437 if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
2438 TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
2439 } else {\r
2440 TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
2441 }\r
2442\r
2443 TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
2444\r
2445 //\r
2446 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
2447 // be set together. Only one DMA mode can be set to a device. If setting\r
2448 // DMA mode operation fails, we can continue moving on because we only use\r
2449 // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
2450 //\r
2451 if (SupportedModes->UdmaMode.Valid) {\r
2452 TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
2453 TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
2454 } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
2455 TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
1aff716a 2456 TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;\r
cbd2a4b3 2457 }\r
2458\r
2459 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
2460 if (EFI_ERROR (Status)) {\r
2461 DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
2462 continue;\r
2463 }\r
2464\r
2465 //\r
2466 // Found a ATA or ATAPI device, add it into the device list.\r
2467 //\r
2468 CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
2469 if (DeviceType == EfiIdeHarddisk) {\r
2470 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
a41b5272 2471 }\r
2472 }\r
2473 }\r
cbd2a4b3 2474\r
a41b5272 2475 return EFI_SUCCESS;\r
2476}\r
2477\r