]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
EFI_FVB2_ALIGNMNET_512K should be EFI_FVB2_ALIGNMENT_512K.
[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
3 \r
e519983a 4 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
a41b5272 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
9\r
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
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
36 \r
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
98 \r
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
a41b5272 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
158 UINT32 Value; \r
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
187 \r
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
206 UINT32 Value; \r
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
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
266 \r
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
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
288 @retval EFI_SUCCESS The device is attached to port and the transfer data is \r
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
321 \r
322 @param PciIo The PCI IO protocol instance.\r
323 @param Port The number of port.\r
324 \r
325**/ \r
326VOID\r
327EFIAPI\r
328AhciClearPortStatus (\r
329 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
330 IN UINT8 Port\r
331 ) \r
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
391 \r
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
a41b5272 415 PciIo, \r
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
442 ) \r
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
456 \r
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
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
492**/ \r
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
506 IN UINT64 DataLength\r
507 ) \r
508{\r
490b5ea1 509 UINT64 BaseAddr;\r
a41b5272 510 UINT64 PrdtNumber;\r
511 UINT64 PrdtIndex;\r
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
519 // \r
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
532 \r
490b5ea1 533 ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));\r
a41b5272 534 \r
535 ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
536\r
537 CommandFis->AhciCFisPmNum = PortMultiplier;\r
538 \r
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
551 CommandList->AhciCmdC = (DataLength == 0) ? 1 : 0;\r
552\r
553 AhciOrReg (PciIo, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
554 } else {\r
555 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
556 }\r
557 \r
5dec0c68 558 RemainedData = (UINTN) DataLength;\r
a41b5272 559 MemAddr = (UINTN) DataPhysicalAddr;\r
560 CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;\r
561 \r
562 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
490b5ea1 563 if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {\r
a41b5272 564 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;\r
565 } else {\r
566 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;\r
567 }\r
568\r
569 Data64.Uint64 = (UINT64)MemAddr;\r
570 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba = Data64.Uint32.Lower32;\r
571 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;\r
490b5ea1 572 RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;\r
a41b5272 573 MemAddr += EFI_AHCI_MAX_DATA_PER_PRDT;\r
574 }\r
575\r
576 //\r
577 // Set the last PRDT to Interrupt On Complete\r
578 //\r
579 if (PrdtNumber > 0) {\r
580 AhciRegisters->AhciCommandTable->PrdtTable[PrdtNumber - 1].AhciPrdtIoc = 1;\r
581 }\r
582\r
583 CopyMem (\r
584 (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),\r
585 CommandList,\r
586 sizeof (EFI_AHCI_COMMAND_LIST)\r
587 ); \r
588\r
589 Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTablePciAddr;\r
590 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;\r
591 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;\r
592 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;\r
593\r
594}\r
595\r
596/**\r
597 Buid a command FIS.\r
598 \r
aca84419 599 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.\r
a41b5272 600 @param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.\r
601\r
602**/\r
603VOID\r
604EFIAPI\r
605AhciBuildCommandFis (\r
606 IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,\r
607 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock\r
608 )\r
609{\r
610 ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
611\r
612 CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;\r
613 //\r
614 // Indicator it's a command\r
615 //\r
616 CmdFis->AhciCFisCmdInd = 0x1; \r
617 CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;\r
618\r
619 CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;\r
620 CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;\r
621\r
622 CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;\r
623 CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;\r
624\r
625 CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;\r
626 CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;\r
627\r
628 CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;\r
629 CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;\r
630\r
631 CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;\r
632 CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;\r
633\r
aca84419 634 CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);\r
a41b5272 635}\r
636\r
637/**\r
638 Start a PIO data transfer on specific port.\r
639 \r
490b5ea1 640 @param[in] PciIo The PCI IO protocol instance.\r
641 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
642 @param[in] Port The number of port.\r
643 @param[in] PortMultiplier The timeout value of stop.\r
644 @param[in] AtapiCommand The atapi command will be used for the\r
645 transfer.\r
646 @param[in] AtapiCommandLength The length of the atapi command.\r
647 @param[in] Read The transfer direction.\r
648 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
649 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
650 @param[in, out] MemoryAddr The pointer to the data buffer.\r
651 @param[in] DataCount The data count to be transferred.\r
8536cc4b 652 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 653 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
654 used by non-blocking mode.\r
a41b5272 655\r
656 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.\r
657 @retval EFI_TIMEOUT The operation is time out.\r
658 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
659 @retval EFI_SUCCESS The PIO data transfer executes successfully.\r
660\r
661**/\r
662EFI_STATUS\r
aca84419 663EFIAPI\r
a41b5272 664AhciPioTransfer (\r
665 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
666 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
667 IN UINT8 Port,\r
668 IN UINT8 PortMultiplier,\r
669 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
670 IN UINT8 AtapiCommandLength, \r
671 IN BOOLEAN Read, \r
672 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
673 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
674 IN OUT VOID *MemoryAddr,\r
675 IN UINT32 DataCount,\r
490b5ea1 676 IN UINT64 Timeout,\r
677 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 678 )\r
679{\r
680 EFI_STATUS Status;\r
681 UINTN FisBaseAddr;\r
8536cc4b 682 UINTN Offset;\r
a41b5272 683 EFI_PHYSICAL_ADDRESS PhyAddr;\r
684 VOID *Map;\r
685 UINTN MapLength;\r
686 EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
687 UINT32 Delay;\r
688 EFI_AHCI_COMMAND_FIS CFis;\r
8536cc4b 689 EFI_AHCI_COMMAND_LIST CmdList; \r
690 UINT32 PortTfd;\r
691 UINT32 PrdCount;\r
a41b5272 692\r
693 if (Read) {\r
694 Flag = EfiPciIoOperationBusMasterWrite;\r
695 } else {\r
696 Flag = EfiPciIoOperationBusMasterRead;\r
697 }\r
698\r
699 //\r
700 // construct command list and command table with pci bus address\r
701 //\r
702 MapLength = DataCount;\r
703 Status = PciIo->Map (\r
704 PciIo,\r
705 Flag,\r
706 MemoryAddr,\r
707 &MapLength,\r
708 &PhyAddr,\r
709 &Map\r
710 );\r
711\r
712 if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
9e70c18b 713 return EFI_BAD_BUFFER_SIZE;\r
a41b5272 714 }\r
715 \r
716 //\r
717 // Package read needed\r
718 //\r
719 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
720\r
721 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
722\r
723 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
724 CmdList.AhciCmdW = Read ? 0 : 1;\r
725\r
726 AhciBuildCommand (\r
727 PciIo,\r
728 AhciRegisters,\r
729 Port,\r
730 PortMultiplier,\r
731 &CFis,\r
732 &CmdList,\r
733 AtapiCommand,\r
734 AtapiCommandLength,\r
735 0,\r
736 (VOID *)(UINTN)PhyAddr,\r
737 DataCount\r
738 ); \r
739 \r
740 Status = AhciStartCommand (\r
490b5ea1 741 PciIo,\r
742 Port,\r
a41b5272 743 0,\r
744 Timeout\r
745 );\r
746 if (EFI_ERROR (Status)) {\r
747 goto Exit;\r
748 }\r
490b5ea1 749\r
a41b5272 750 //\r
490b5ea1 751 // Check the status and wait the driver sending data\r
a41b5272 752 //\r
753 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
a41b5272 754\r
8536cc4b 755 if (Read && (AtapiCommand == 0)) {\r
a41b5272 756 //\r
8536cc4b 757 // Wait device sends the PIO setup fis before data transfer\r
a41b5272 758 //\r
8536cc4b 759 Status = EFI_TIMEOUT;\r
760 Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
761 do {\r
762 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
763 PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
764\r
765 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
766 Status = EFI_DEVICE_ERROR;\r
767 break;\r
768 }\r
769 Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\r
a41b5272 770\r
8536cc4b 771 Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);\r
772 if (!EFI_ERROR (Status)) {\r
773 PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
774 if (PrdCount == DataCount) {\r
775 break;\r
776 }\r
777 }\r
a41b5272 778\r
8536cc4b 779 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
780 Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);\r
781 if (!EFI_ERROR (Status)) {\r
782 Status = EFI_DEVICE_ERROR;\r
783 break;\r
784 }\r
a41b5272 785\r
8536cc4b 786 //\r
787 // Stall for 100 microseconds.\r
788 //\r
789 MicroSecondDelay(100);\r
a41b5272 790\r
8536cc4b 791 Delay--;\r
792 } while (Delay > 0);\r
793 } else {\r
794 //\r
795 // Wait for D2H Fis is received\r
796 //\r
797 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
798 Status = AhciWaitMemSet (\r
799 Offset,\r
800 EFI_AHCI_FIS_TYPE_MASK,\r
801 EFI_AHCI_FIS_REGISTER_D2H,\r
802 Timeout\r
803 );\r
a41b5272 804\r
8536cc4b 805 if (EFI_ERROR (Status)) {\r
806 goto Exit;\r
807 }\r
808\r
809 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
810 PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
811 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
812 Status = EFI_DEVICE_ERROR;\r
813 }\r
a41b5272 814 }\r
815\r
490b5ea1 816Exit:\r
a41b5272 817 AhciStopCommand (\r
490b5ea1 818 PciIo,\r
a41b5272 819 Port,\r
820 Timeout\r
821 );\r
822 \r
823 AhciDisableFisReceive (\r
490b5ea1 824 PciIo,\r
a41b5272 825 Port,\r
826 Timeout\r
827 );\r
828\r
829 PciIo->Unmap (\r
830 PciIo,\r
831 Map\r
832 );\r
833\r
e519983a 834 AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
835\r
a41b5272 836 return Status;\r
837}\r
838\r
839/**\r
840 Start a DMA data transfer on specific port\r
841\r
490b5ea1 842 @param[in] Instance The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.\r
843 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
844 @param[in] Port The number of port.\r
845 @param[in] PortMultiplier The timeout value of stop.\r
846 @param[in] AtapiCommand The atapi command will be used for the\r
847 transfer.\r
848 @param[in] AtapiCommandLength The length of the atapi command.\r
849 @param[in] Read The transfer direction.\r
850 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
851 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
852 @param[in, out] MemoryAddr The pointer to the data buffer.\r
853 @param[in] DataCount The data count to be transferred.\r
8536cc4b 854 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 855 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
856 used by non-blocking mode.\r
aca84419 857\r
858 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.\r
859 @retval EFI_TIMEOUT The operation is time out.\r
860 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
861 @retval EFI_SUCCESS The DMA data transfer executes successfully.\r
490b5ea1 862\r
a41b5272 863**/\r
864EFI_STATUS\r
865EFIAPI\r
866AhciDmaTransfer (\r
490b5ea1 867 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
a41b5272 868 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
869 IN UINT8 Port,\r
870 IN UINT8 PortMultiplier,\r
871 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
872 IN UINT8 AtapiCommandLength,\r
873 IN BOOLEAN Read, \r
874 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
875 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
876 IN OUT VOID *MemoryAddr,\r
8536cc4b 877 IN UINT32 DataCount,\r
490b5ea1 878 IN UINT64 Timeout,\r
879 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 880 )\r
881{\r
882 EFI_STATUS Status;\r
8536cc4b 883 UINTN Offset;\r
a41b5272 884 EFI_PHYSICAL_ADDRESS PhyAddr;\r
885 VOID *Map;\r
886 UINTN MapLength;\r
887 EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
888 EFI_AHCI_COMMAND_FIS CFis;\r
889 EFI_AHCI_COMMAND_LIST CmdList;\r
8536cc4b 890 UINTN FisBaseAddr;\r
891 UINT32 PortTfd;\r
a41b5272 892\r
8536cc4b 893 EFI_PCI_IO_PROTOCOL *PciIo;\r
894 EFI_TPL OldTpl;\r
a41b5272 895\r
490b5ea1 896 Map = NULL;\r
897 PciIo = Instance->PciIo;\r
a41b5272 898\r
490b5ea1 899 if (PciIo == NULL) {\r
900 return EFI_INVALID_PARAMETER;\r
a41b5272 901 }\r
902\r
903 //\r
490b5ea1 904 // Before starting the Blocking BlockIO operation, push to finish all non-blocking\r
905 // BlockIO tasks.\r
906 // Delay 100us to simulate the blocking time out checking.\r
a41b5272 907 //\r
490b5ea1 908 while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {\r
909 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
910 AsyncNonBlockingTransferRoutine (NULL, Instance);\r
911 gBS->RestoreTPL (OldTpl); \r
912 //\r
913 // Stall for 100us.\r
914 //\r
915 MicroSecondDelay (100);\r
916 }\r
a41b5272 917\r
490b5ea1 918 if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {\r
919 //\r
920 // Mark the Task to indicate that it has been started.\r
921 //\r
922 if (Task != NULL) {\r
923 Task->IsStart = TRUE;\r
924 Task->RetryTimes = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
925 }\r
926 if (Read) {\r
927 Flag = EfiPciIoOperationBusMasterWrite;\r
928 } else {\r
929 Flag = EfiPciIoOperationBusMasterRead;\r
930 }\r
a41b5272 931\r
490b5ea1 932 //\r
933 // Construct command list and command table with pci bus address.\r
934 //\r
935 MapLength = DataCount;\r
936 Status = PciIo->Map (\r
937 PciIo,\r
938 Flag,\r
939 MemoryAddr,\r
940 &MapLength,\r
941 &PhyAddr,\r
942 &Map\r
943 );\r
944\r
945 if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
9e70c18b 946 return EFI_BAD_BUFFER_SIZE;\r
490b5ea1 947 }\r
a41b5272 948\r
490b5ea1 949 if (Task != NULL) {\r
950 Task->Map = Map;\r
951 }\r
952 //\r
953 // Package read needed\r
954 //\r
955 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
956\r
957 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
958\r
959 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
960 CmdList.AhciCmdW = Read ? 0 : 1;\r
961\r
962 AhciBuildCommand (\r
963 PciIo,\r
964 AhciRegisters,\r
965 Port,\r
966 PortMultiplier,\r
967 &CFis,\r
968 &CmdList,\r
969 AtapiCommand,\r
970 AtapiCommandLength,\r
971 0,\r
972 (VOID *)(UINTN)PhyAddr,\r
973 DataCount\r
974 );\r
975\r
976 Status = AhciStartCommand (\r
977 PciIo,\r
978 Port,\r
979 0,\r
980 Timeout\r
981 );\r
982 if (EFI_ERROR (Status)) {\r
983 goto Exit;\r
984 }\r
a41b5272 985 }\r
986\r
987 //\r
988 // Wait for command compelte\r
989 //\r
8536cc4b 990 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
991 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
490b5ea1 992 if (Task != NULL) {\r
993 //\r
994 // For Non-blocking\r
995 //\r
996 Status = AhciCheckMemSet (\r
490b5ea1 997 Offset,\r
8536cc4b 998 EFI_AHCI_FIS_TYPE_MASK,\r
999 EFI_AHCI_FIS_REGISTER_D2H,\r
490b5ea1 1000 (UINTN *) (&Task->RetryTimes)\r
1001 );\r
1002 } else {\r
1003 Status = AhciWaitMemSet (\r
490b5ea1 1004 Offset,\r
8536cc4b 1005 EFI_AHCI_FIS_TYPE_MASK,\r
1006 EFI_AHCI_FIS_REGISTER_D2H,\r
490b5ea1 1007 Timeout\r
1008 );\r
1009 }\r
1010\r
a41b5272 1011 if (EFI_ERROR (Status)) {\r
1012 goto Exit;\r
1013 }\r
1014\r
8536cc4b 1015 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
1016 PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
1017 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
1018 Status = EFI_DEVICE_ERROR;\r
a41b5272 1019 }\r
1020\r
490b5ea1 1021Exit:\r
1022 //\r
1023 // For Blocking mode, the command should be stopped, the Fis should be disabled\r
1024 // and the PciIo should be unmapped.\r
1025 // For non-blocking mode, only when a error is happened (if the return status is \r
1026 // EFI_NOT_READY that means the command doesn't finished, try again.), first do the \r
1027 // context cleanup, then set the packet's Asb status.\r
1028 //\r
1029 if (Task == NULL ||\r
1030 ((Task != NULL) && (Status != EFI_NOT_READY))\r
1031 ) {\r
1032 AhciStopCommand (\r
1033 PciIo, \r
1034 Port,\r
1035 Timeout\r
1036 );\r
a41b5272 1037\r
490b5ea1 1038 AhciDisableFisReceive (\r
1039 PciIo, \r
1040 Port,\r
1041 Timeout\r
1042 );\r
a41b5272 1043\r
490b5ea1 1044 PciIo->Unmap (\r
1045 PciIo,\r
1046 (Task != NULL) ? Task->Map : Map\r
1047 );\r
e519983a 1048\r
490b5ea1 1049 if (Task != NULL) {\r
1050 Task->Packet->Asb->AtaStatus = 0x01;\r
1051 }\r
1052 }\r
1053\r
1054 AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
a41b5272 1055 return Status;\r
1056}\r
1057\r
1058/**\r
1059 Start a non data transfer on specific port.\r
1060 \r
490b5ea1 1061 @param[in] PciIo The PCI IO protocol instance.\r
1062 @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1063 @param[in] Port The number of port.\r
1064 @param[in] PortMultiplier The timeout value of stop.\r
1065 @param[in] AtapiCommand The atapi command will be used for the\r
1066 transfer.\r
1067 @param[in] AtapiCommandLength The length of the atapi command.\r
1068 @param[in] AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
1069 @param[in, out] AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
8536cc4b 1070 @param[in] Timeout The timeout value of non data transfer, uses 100ns as a unit.\r
490b5ea1 1071 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1072 used by non-blocking mode.\r
a41b5272 1073\r
1074 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.\r
1075 @retval EFI_TIMEOUT The operation is time out.\r
1076 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
1077 @retval EFI_SUCCESS The non data transfer executes successfully.\r
1078\r
1079**/ \r
1080EFI_STATUS\r
1081EFIAPI\r
1082AhciNonDataTransfer (\r
1083 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1084 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1085 IN UINT8 Port,\r
1086 IN UINT8 PortMultiplier,\r
1087 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
1088 IN UINT8 AtapiCommandLength,\r
1089 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
1090 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
490b5ea1 1091 IN UINT64 Timeout,\r
1092 IN ATA_NONBLOCK_TASK *Task\r
1093 )\r
a41b5272 1094{\r
490b5ea1 1095 EFI_STATUS Status;\r
a41b5272 1096 UINTN FisBaseAddr;\r
8536cc4b 1097 UINTN Offset;\r
1098 UINT32 PortTfd;\r
a41b5272 1099 EFI_AHCI_COMMAND_FIS CFis;\r
1100 EFI_AHCI_COMMAND_LIST CmdList;\r
1101\r
1102 //\r
1103 // Package read needed\r
1104 //\r
1105 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
1106\r
1107 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
1108\r
1109 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
1110\r
1111 AhciBuildCommand (\r
1112 PciIo,\r
1113 AhciRegisters,\r
1114 Port,\r
1115 PortMultiplier,\r
1116 &CFis,\r
1117 &CmdList,\r
1118 AtapiCommand,\r
1119 AtapiCommandLength,\r
1120 0,\r
1121 NULL,\r
1122 0\r
490b5ea1 1123 );\r
1124\r
a41b5272 1125 Status = AhciStartCommand (\r
490b5ea1 1126 PciIo,\r
1127 Port,\r
a41b5272 1128 0,\r
1129 Timeout\r
1130 );\r
1131 if (EFI_ERROR (Status)) {\r
1132 goto Exit;\r
1133 }\r
490b5ea1 1134\r
a41b5272 1135 //\r
1136 // Wait device sends the Response Fis\r
1137 //\r
1138 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
8536cc4b 1139 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
1140 Status = AhciWaitMemSet (\r
1141 Offset,\r
1142 EFI_AHCI_FIS_TYPE_MASK,\r
1143 EFI_AHCI_FIS_REGISTER_D2H,\r
1144 Timeout\r
1145 );\r
a41b5272 1146\r
8536cc4b 1147 if (EFI_ERROR (Status)) {\r
a41b5272 1148 goto Exit;\r
1149 }\r
1150\r
8536cc4b 1151 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
1152 PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
1153 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
1154 Status = EFI_DEVICE_ERROR;\r
1155 }\r
490b5ea1 1156\r
1157Exit:\r
a41b5272 1158 AhciStopCommand (\r
490b5ea1 1159 PciIo,\r
a41b5272 1160 Port,\r
1161 Timeout\r
1162 );\r
1163\r
1164 AhciDisableFisReceive (\r
490b5ea1 1165 PciIo,\r
a41b5272 1166 Port,\r
1167 Timeout\r
1168 );\r
1169\r
e519983a 1170 AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
1171\r
a41b5272 1172 return Status;\r
1173}\r
1174\r
1175/**\r
1176 Stop command running for giving port\r
1177 \r
1178 @param PciIo The PCI IO protocol instance.\r
1179 @param Port The number of port.\r
8536cc4b 1180 @param Timeout The timeout value of stop, uses 100ns as a unit.\r
a41b5272 1181 \r
1182 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.\r
1183 @retval EFI_TIMEOUT The operation is time out.\r
1184 @retval EFI_SUCCESS The command stop successfully.\r
1185\r
1186**/\r
1187EFI_STATUS\r
1188EFIAPI\r
1189AhciStopCommand (\r
1190 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1191 IN UINT8 Port,\r
1192 IN UINT64 Timeout\r
1193 )\r
1194{\r
1195 UINT32 Offset;\r
1196 UINT32 Data;\r
1197\r
1198 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1199 Data = AhciReadReg (PciIo, Offset);\r
1200\r
1201 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {\r
490b5ea1 1202 return EFI_SUCCESS;\r
a41b5272 1203 }\r
1204\r
1205 if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
1206 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));\r
1207 }\r
1208\r
8536cc4b 1209 return AhciWaitMmioSet (\r
490b5ea1 1210 PciIo,\r
a41b5272 1211 Offset,\r
1212 EFI_AHCI_PORT_CMD_CR,\r
1213 0,\r
1214 Timeout\r
490b5ea1 1215 );\r
a41b5272 1216}\r
1217\r
1218/**\r
1219 Start command for give slot on specific port.\r
490b5ea1 1220\r
a41b5272 1221 @param PciIo The PCI IO protocol instance.\r
1222 @param Port The number of port.\r
490b5ea1 1223 @param CommandSlot The number of Command Slot.\r
8536cc4b 1224 @param Timeout The timeout value of start, uses 100ns as a unit.\r
490b5ea1 1225\r
a41b5272 1226 @retval EFI_DEVICE_ERROR The command start unsuccessfully.\r
1227 @retval EFI_TIMEOUT The operation is time out.\r
1228 @retval EFI_SUCCESS The command start successfully.\r
1229\r
1230**/\r
1231EFI_STATUS\r
1232EFIAPI\r
1233AhciStartCommand (\r
1234 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1235 IN UINT8 Port,\r
1236 IN UINT8 CommandSlot,\r
1237 IN UINT64 Timeout\r
1238 )\r
1239{\r
1240 UINT32 CmdSlotBit;\r
1241 EFI_STATUS Status;\r
1242 UINT32 PortStatus;\r
1243 UINT32 StartCmd;\r
1244 UINT32 PortTfd;\r
1245 UINT32 Offset;\r
1246 UINT32 Capability;\r
1247\r
1248 //\r
1249 // Collect AHCI controller information\r
1250 //\r
1251 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
1252\r
1253 CmdSlotBit = (UINT32) (1 << CommandSlot);\r
1254\r
1255 AhciClearPortStatus (\r
1256 PciIo,\r
1257 Port\r
1258 );\r
1259\r
1260 Status = AhciEnableFisReceive (\r
1261 PciIo, \r
1262 Port,\r
1263 Timeout\r
1264 );\r
490b5ea1 1265\r
a41b5272 1266 if (EFI_ERROR (Status)) {\r
1267 return Status;\r
1268 }\r
1269\r
a41b5272 1270 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1271 PortStatus = AhciReadReg (PciIo, Offset);\r
490b5ea1 1272\r
a41b5272 1273 StartCmd = 0;\r
1274 if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
1275 StartCmd = AhciReadReg (PciIo, Offset);\r
1276 StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;\r
1277 StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;\r
1278 }\r
1279\r
1280 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
1281 PortTfd = AhciReadReg (PciIo, Offset);\r
1282\r
1283 if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
1284 if ((Capability & BIT24) != 0) {\r
1285 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
cbd2a4b3 1286 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);\r
a41b5272 1287\r
8536cc4b 1288 AhciWaitMmioSet (\r
490b5ea1 1289 PciIo,\r
a41b5272 1290 Offset,\r
cbd2a4b3 1291 EFI_AHCI_PORT_CMD_CLO,\r
a41b5272 1292 0,\r
1293 Timeout\r
490b5ea1 1294 );\r
a41b5272 1295 }\r
1296 }\r
1297\r
1298 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1299 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);\r
1300\r
e519983a 1301 //\r
1302 // Setting the command\r
1303 //\r
1304 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
1305 AhciAndReg (PciIo, Offset, 0);\r
1306 AhciOrReg (PciIo, Offset, CmdSlotBit);\r
1307\r
1308 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
1309 AhciAndReg (PciIo, Offset, 0);\r
1310 AhciOrReg (PciIo, Offset, CmdSlotBit);\r
1311\r
a41b5272 1312 return EFI_SUCCESS;\r
1313}\r
1314\r
1315/**\r
1316 Do AHCI port reset.\r
1317\r
1318 @param PciIo The PCI IO protocol instance.\r
1319 @param Port The number of port.\r
8536cc4b 1320 @param Timeout The timeout value of reset, uses 100ns as a unit.\r
a41b5272 1321 \r
1322 @retval EFI_DEVICE_ERROR The port reset unsuccessfully\r
1323 @retval EFI_TIMEOUT The reset operation is time out.\r
1324 @retval EFI_SUCCESS The port reset successfully.\r
1325\r
1326**/\r
1327EFI_STATUS\r
1328EFIAPI\r
1329AhciPortReset (\r
1330 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1331 IN UINT8 Port,\r
1332 IN UINT64 Timeout\r
1333 )\r
1334{\r
1335 EFI_STATUS Status;\r
490b5ea1 1336 UINT32 Offset;\r
1337\r
a41b5272 1338 AhciClearPortStatus (PciIo, Port);\r
1339\r
1340 AhciStopCommand (PciIo, Port, Timeout);\r
1341\r
1342 AhciDisableFisReceive (PciIo, Port, Timeout);\r
1343\r
1344 AhciEnableFisReceive (PciIo, Port, Timeout);\r
1345\r
1346 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
1347\r
1348 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);\r
1349\r
1350 //\r
490b5ea1 1351 // wait 5 millisecond before de-assert DET\r
a41b5272 1352 //\r
1353 MicroSecondDelay (5000);\r
1354\r
1355 AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK);\r
1356\r
1357 //\r
490b5ea1 1358 // wait 5 millisecond before de-assert DET\r
a41b5272 1359 //\r
1360 MicroSecondDelay (5000);\r
1361\r
1362 //\r
1363 // Wait for communication to be re-established\r
1364 //\r
1365 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
8536cc4b 1366 Status = AhciWaitMmioSet (\r
a41b5272 1367 PciIo,\r
1368 Offset,\r
1369 EFI_AHCI_PORT_SSTS_DET_MASK,\r
1370 EFI_AHCI_PORT_SSTS_DET_PCE,\r
1371 Timeout\r
490b5ea1 1372 );\r
a41b5272 1373\r
1374 if (EFI_ERROR (Status)) {\r
1375 return Status;\r
1376 }\r
1377\r
1378 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
1379 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_ERR_CLEAR);\r
1380\r
1381 return EFI_SUCCESS;\r
1382}\r
1383\r
1384/**\r
1385 Do AHCI HBA reset.\r
490b5ea1 1386\r
a41b5272 1387 @param PciIo The PCI IO protocol instance.\r
8536cc4b 1388 @param Timeout The timeout value of reset, uses 100ns as a unit.\r
490b5ea1 1389\r
a41b5272 1390 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.\r
1391 @retval EFI_TIMEOUT The reset operation is time out.\r
1392 @retval EFI_SUCCESS AHCI controller is reset successfully.\r
1393\r
1394**/\r
1395EFI_STATUS\r
1396EFIAPI\r
1397AhciReset (\r
1398 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1399 IN UINT64 Timeout\r
1400 ) \r
1401{\r
a41b5272 1402 UINT32 Delay;\r
1403 UINT32 Value;\r
1404\r
1405 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
1406\r
1407 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
1408\r
a41b5272 1409 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
1410\r
1411 do {\r
1412 Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
1413\r
1414 if ((Value & EFI_AHCI_GHC_RESET) == 0) {\r
1415 break;\r
1416 }\r
1417\r
1418 //\r
1419 // Stall for 100 microseconds.\r
1420 //\r
1421 MicroSecondDelay(100);\r
1422\r
1423 Delay--;\r
1424 } while (Delay > 0);\r
1425\r
1426 if (Delay == 0) {\r
1427 return EFI_TIMEOUT;\r
1428 }\r
1429\r
1430 return EFI_SUCCESS;\r
1431}\r
1432\r
12873d57 1433/**\r
1434 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
1435\r
1436 @param PciIo The PCI IO protocol instance.\r
1437 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1438 @param Port The number of port.\r
1439 @param PortMultiplier The timeout value of stop.\r
1440 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1441\r
1442 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.\r
1443 @retval Others Fail to get return status data.\r
1444\r
1445**/\r
1446EFI_STATUS\r
1447EFIAPI\r
1448AhciAtaSmartReturnStatusCheck (\r
1449 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1450 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1451 IN UINT8 Port,\r
1452 IN UINT8 PortMultiplier,\r
1453 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
1454 )\r
1455{\r
1456 EFI_STATUS Status;\r
1457 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1458 UINT8 LBAMid;\r
1459 UINT8 LBAHigh;\r
1460 UINTN FisBaseAddr;\r
1461 UINT32 Value;\r
1462\r
1463 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1464\r
1465 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1466 AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;\r
1467 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1468 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1469\r
1470 //\r
1471 // Send S.M.A.R.T Read Return Status command to device\r
1472 //\r
1473 Status = AhciNonDataTransfer (\r
1474 PciIo,\r
1475 AhciRegisters,\r
1476 (UINT8)Port,\r
1477 (UINT8)PortMultiplier,\r
1478 NULL,\r
1479 0,\r
1480 &AtaCommandBlock,\r
1481 AtaStatusBlock,\r
490b5ea1 1482 ATA_ATAPI_TIMEOUT,\r
1483 NULL\r
12873d57 1484 );\r
1485\r
1486 if (EFI_ERROR (Status)) {\r
1487 return EFI_DEVICE_ERROR;\r
1488 }\r
1489\r
1490 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1491\r
1492 Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
1493\r
1494 if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
1495 LBAMid = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];\r
1496 LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];\r
1497\r
1498 if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
1499 //\r
1500 // The threshold exceeded condition is not detected by the device\r
1501 //\r
1502 DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
1503\r
1504 } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
1505 //\r
1506 // The threshold exceeded condition is detected by the device\r
1507 //\r
1508 DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
1509 }\r
1510 }\r
1511\r
1512 return EFI_SUCCESS;\r
1513}\r
1514\r
1515/**\r
1516 Enable SMART command of the disk if supported.\r
1517\r
1518 @param PciIo The PCI IO protocol instance.\r
1519 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1520 @param Port The number of port.\r
1521 @param PortMultiplier The timeout value of stop.\r
1522 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
1523 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1524\r
1525**/\r
1526VOID\r
1527EFIAPI\r
1528AhciAtaSmartSupport (\r
1529 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1530 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1531 IN UINT8 Port,\r
1532 IN UINT8 PortMultiplier,\r
490b5ea1 1533 IN EFI_IDENTIFY_DATA *IdentifyData,\r
12873d57 1534 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
1535 )\r
1536{\r
1537 EFI_STATUS Status;\r
1538 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1539\r
1540 //\r
1541 // Detect if the device supports S.M.A.R.T.\r
1542 //\r
1543 if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
1544 //\r
1545 // S.M.A.R.T is not supported by the device\r
1546 //\r
1547 DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n", \r
1548 Port, PortMultiplier));\r
1549 } else {\r
1550 //\r
1551 // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
1552 //\r
1553 if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
1554 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1555\r
1556 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1557 AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;\r
1558 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1559 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1560\r
1561 //\r
1562 // Send S.M.A.R.T Enable command to device\r
1563 //\r
1564 Status = AhciNonDataTransfer (\r
1565 PciIo,\r
1566 AhciRegisters,\r
1567 (UINT8)Port,\r
1568 (UINT8)PortMultiplier,\r
1569 NULL,\r
1570 0,\r
1571 &AtaCommandBlock,\r
1572 AtaStatusBlock,\r
490b5ea1 1573 ATA_ATAPI_TIMEOUT,\r
1574 NULL\r
12873d57 1575 );\r
1576\r
1577\r
1578 if (!EFI_ERROR (Status)) {\r
1579 //\r
1580 // Send S.M.A.R.T AutoSave command to device\r
1581 //\r
1582 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1583\r
1584 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1585 AtaCommandBlock.AtaFeatures = 0xD2;\r
1586 AtaCommandBlock.AtaSectorCount = 0xF1;\r
1587 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1588 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1589\r
1590 Status = AhciNonDataTransfer (\r
1591 PciIo,\r
1592 AhciRegisters,\r
1593 (UINT8)Port,\r
1594 (UINT8)PortMultiplier,\r
1595 NULL,\r
1596 0,\r
1597 &AtaCommandBlock,\r
1598 AtaStatusBlock,\r
490b5ea1 1599 ATA_ATAPI_TIMEOUT,\r
1600 NULL\r
12873d57 1601 );\r
1602\r
1603 if (!EFI_ERROR (Status)) {\r
1604 Status = AhciAtaSmartReturnStatusCheck (\r
1605 PciIo,\r
1606 AhciRegisters,\r
1607 (UINT8)Port,\r
1608 (UINT8)PortMultiplier,\r
1609 AtaStatusBlock\r
1610 );\r
1611 }\r
1612 }\r
1613 }\r
490b5ea1 1614 DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",\r
12873d57 1615 Port, PortMultiplier));\r
1616 }\r
1617\r
1618 return ;\r
1619}\r
1620\r
a41b5272 1621/**\r
1622 Send Buffer cmd to specific device.\r
1623 \r
aca84419 1624 @param PciIo The PCI IO protocol instance.\r
1625 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1626 @param Port The number of port.\r
a41b5272 1627 @param PortMultiplier The timeout value of stop.\r
aca84419 1628 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1629\r
1630 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1631 @retval EFI_TIMEOUT The operation is time out.\r
1632 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1633 @retval EFI_SUCCESS The cmd executes successfully.\r
1634\r
1635**/\r
1636EFI_STATUS\r
1637EFIAPI\r
1638AhciIdentify (\r
1639 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1640 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1641 IN UINT8 Port,\r
1642 IN UINT8 PortMultiplier,\r
1643 IN OUT EFI_IDENTIFY_DATA *Buffer \r
1644 )\r
1645{\r
1646 EFI_STATUS Status;\r
1647 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1648 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1649\r
1650 if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {\r
1651 return EFI_INVALID_PARAMETER;\r
1652 }\r
1653\r
1654 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1655 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 1656\r
a41b5272 1657 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
1658 AtaCommandBlock.AtaSectorCount = 1;\r
1659\r
1660 Status = AhciPioTransfer (\r
1661 PciIo,\r
1662 AhciRegisters,\r
1663 Port,\r
1664 PortMultiplier,\r
1665 NULL,\r
1666 0,\r
1667 TRUE,\r
1668 &AtaCommandBlock,\r
1669 &AtaStatusBlock,\r
1670 Buffer,\r
1671 sizeof (EFI_IDENTIFY_DATA),\r
490b5ea1 1672 ATA_ATAPI_TIMEOUT, \r
1673 NULL\r
a41b5272 1674 );\r
1675\r
1676 return Status;\r
1677}\r
1678\r
1679/**\r
1680 Send Buffer cmd to specific device.\r
1681 \r
aca84419 1682 @param PciIo The PCI IO protocol instance.\r
1683 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1684 @param Port The number of port.\r
a41b5272 1685 @param PortMultiplier The timeout value of stop.\r
aca84419 1686 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1687\r
1688 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1689 @retval EFI_TIMEOUT The operation is time out.\r
1690 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1691 @retval EFI_SUCCESS The cmd executes successfully.\r
1692\r
1693**/\r
1694EFI_STATUS\r
1695EFIAPI\r
1696AhciIdentifyPacket (\r
1697 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1698 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1699 IN UINT8 Port,\r
1700 IN UINT8 PortMultiplier,\r
1701 IN OUT EFI_IDENTIFY_DATA *Buffer \r
1702 )\r
1703{\r
1704 EFI_STATUS Status;\r
1705 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1706 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1707\r
1708 if (PciIo == NULL || AhciRegisters == NULL) {\r
1709 return EFI_INVALID_PARAMETER;\r
1710 }\r
490b5ea1 1711\r
a41b5272 1712 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1713 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1714\r
1715 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DEVICE;\r
1716 AtaCommandBlock.AtaSectorCount = 1;\r
1717\r
1718 Status = AhciPioTransfer (\r
1719 PciIo,\r
1720 AhciRegisters,\r
1721 Port,\r
1722 PortMultiplier,\r
1723 NULL,\r
1724 0,\r
1725 TRUE,\r
1726 &AtaCommandBlock,\r
1727 &AtaStatusBlock,\r
1728 Buffer,\r
1729 sizeof (EFI_IDENTIFY_DATA),\r
490b5ea1 1730 ATA_ATAPI_TIMEOUT,\r
1731 NULL\r
a41b5272 1732 );\r
1733\r
1734 return Status;\r
1735}\r
1736\r
1737/**\r
1738 Send SET FEATURE cmd on specific device.\r
1739 \r
aca84419 1740 @param PciIo The PCI IO protocol instance.\r
1741 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1742 @param Port The number of port.\r
a41b5272 1743 @param PortMultiplier The timeout value of stop.\r
aca84419 1744 @param Feature The data to send Feature register.\r
1745 @param FeatureSpecificData The specific data for SET FEATURE cmd.\r
a41b5272 1746\r
1747 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1748 @retval EFI_TIMEOUT The operation is time out.\r
1749 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1750 @retval EFI_SUCCESS The cmd executes successfully.\r
1751\r
1752**/\r
1753EFI_STATUS\r
1754EFIAPI\r
1755AhciDeviceSetFeature (\r
1756 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1757 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1758 IN UINT8 Port,\r
1759 IN UINT8 PortMultiplier,\r
1760 IN UINT16 Feature,\r
1761 IN UINT32 FeatureSpecificData\r
1762 )\r
1763{\r
1764 EFI_STATUS Status;\r
1765 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1766 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1767\r
1768 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1769 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 1770\r
a41b5272 1771 AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;\r
1772 AtaCommandBlock.AtaFeatures = (UINT8) Feature;\r
1773 AtaCommandBlock.AtaFeaturesExp = (UINT8) (Feature >> 8);\r
1774 AtaCommandBlock.AtaSectorCount = (UINT8) FeatureSpecificData;\r
1775 AtaCommandBlock.AtaSectorNumber = (UINT8) (FeatureSpecificData >> 8);\r
1776 AtaCommandBlock.AtaCylinderLow = (UINT8) (FeatureSpecificData >> 16);\r
1777 AtaCommandBlock.AtaCylinderHigh = (UINT8) (FeatureSpecificData >> 24);\r
1778\r
1779 Status = AhciNonDataTransfer (\r
1780 PciIo,\r
1781 AhciRegisters,\r
1782 (UINT8)Port,\r
1783 (UINT8)PortMultiplier,\r
1784 NULL,\r
1785 0,\r
1786 &AtaCommandBlock,\r
1787 &AtaStatusBlock,\r
490b5ea1 1788 ATA_ATAPI_TIMEOUT, \r
1789 NULL\r
a41b5272 1790 );\r
1791\r
1792 return Status;\r
1793}\r
1794\r
1795/**\r
1796 This function is used to send out ATAPI commands conforms to the Packet Command \r
1797 with PIO Protocol.\r
1798\r
1799 @param PciIo The PCI IO protocol instance.\r
1800 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1801 @param Port The number of port. \r
1802 @param PortMultiplier The number of port multiplier.\r
1803 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.\r
1804\r
1805 @retval EFI_SUCCESS send out the ATAPI packet command successfully\r
1806 and device sends data successfully.\r
1807 @retval EFI_DEVICE_ERROR the device failed to send data.\r
1808\r
1809**/\r
1810EFI_STATUS\r
1811EFIAPI\r
1812AhciPacketCommandExecute (\r
1813 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1814 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1815 IN UINT8 Port,\r
1816 IN UINT8 PortMultiplier,\r
1817 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
1818 )\r
1819{\r
1820 EFI_STATUS Status;\r
1821 VOID *Buffer;\r
1822 UINT32 Length;\r
1823 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1824 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1825 BOOLEAN Read;\r
a41b5272 1826\r
1827 if (Packet == NULL || Packet->Cdb == NULL) {\r
1828 return EFI_INVALID_PARAMETER;\r
1829 }\r
1830\r
1831 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1832 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1833 AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;\r
1834 //\r
1835 // No OVL; No DMA\r
1836 //\r
1837 AtaCommandBlock.AtaFeatures = 0x00;\r
1838 //\r
1839 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
1840 // determine how many data should be transferred.\r
1841 //\r
1842 AtaCommandBlock.AtaCylinderLow = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
1843 AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);\r
1844\r
1845 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1846 Buffer = Packet->InDataBuffer;\r
1847 Length = Packet->InTransferLength;\r
1848 Read = TRUE;\r
1849 } else {\r
1850 Buffer = Packet->OutDataBuffer;\r
1851 Length = Packet->OutTransferLength;\r
1852 Read = FALSE;\r
1853 }\r
1854\r
490b5ea1 1855 if (Length == 0) {\r
a41b5272 1856 Status = AhciNonDataTransfer (\r
1857 PciIo,\r
1858 AhciRegisters,\r
1859 Port,\r
1860 PortMultiplier,\r
1861 Packet->Cdb,\r
1862 Packet->CdbLength,\r
1863 &AtaCommandBlock,\r
1864 &AtaStatusBlock,\r
490b5ea1 1865 Packet->Timeout, \r
1866 NULL\r
a41b5272 1867 );\r
1868 } else {\r
cbd2a4b3 1869 Status = AhciPioTransfer (\r
1870 PciIo,\r
1871 AhciRegisters,\r
1872 Port,\r
1873 PortMultiplier,\r
1874 Packet->Cdb,\r
1875 Packet->CdbLength,\r
1876 Read,\r
1877 &AtaCommandBlock,\r
1878 &AtaStatusBlock,\r
1879 Buffer,\r
1880 Length,\r
1881 Packet->Timeout, \r
1882 NULL\r
1883 );\r
a41b5272 1884 }\r
1885 return Status;\r
1886}\r
1887\r
1888/**\r
1889 Allocate transfer-related data struct which is used at AHCI mode.\r
1890 \r
1891 @param PciIo The PCI IO protocol instance.\r
1892 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1893\r
1894**/\r
1895EFI_STATUS\r
1896EFIAPI\r
1897AhciCreateTransferDescriptor (\r
1898 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1899 IN OUT EFI_AHCI_REGISTERS *AhciRegisters\r
1900 )\r
1901{\r
1902 EFI_STATUS Status;\r
1903 UINTN Bytes;\r
1904 VOID *Buffer;\r
1905\r
1906 UINT32 Capability;\r
1907 UINT8 MaxPortNumber;\r
1908 UINT8 MaxCommandSlotNumber;\r
1909 BOOLEAN Support64Bit;\r
1910 UINT64 MaxReceiveFisSize;\r
1911 UINT64 MaxCommandListSize;\r
1912 UINT64 MaxCommandTableSize;\r
ed365e93 1913 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr;\r
1914 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr;\r
1915 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr;\r
a41b5272 1916\r
1917 Buffer = NULL;\r
1918 //\r
1919 // Collect AHCI controller information\r
1920 //\r
1921 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
1922 MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
1923 //\r
1924 // Get the number of command slots per port supported by this HBA.\r
1925 //\r
1926 MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
aca84419 1927 Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
a41b5272 1928\r
1929 MaxReceiveFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1930 Status = PciIo->AllocateBuffer (\r
1931 PciIo,\r
1932 AllocateAnyPages,\r
1933 EfiBootServicesData,\r
ed365e93 1934 EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
a41b5272 1935 &Buffer,\r
1936 0\r
1937 );\r
1938\r
1939 if (EFI_ERROR (Status)) {\r
1940 return EFI_OUT_OF_RESOURCES;\r
1941 }\r
1942\r
5dec0c68 1943 ZeroMem (Buffer, (UINTN)MaxReceiveFisSize);\r
a41b5272 1944\r
1945 AhciRegisters->AhciRFis = Buffer;\r
1946 AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;\r
5dec0c68 1947 Bytes = (UINTN)MaxReceiveFisSize;\r
a41b5272 1948\r
1949 Status = PciIo->Map (\r
1950 PciIo,\r
1951 EfiPciIoOperationBusMasterCommonBuffer,\r
1952 Buffer,\r
1953 &Bytes,\r
ed365e93 1954 &AhciRFisPciAddr,\r
a41b5272 1955 &AhciRegisters->MapRFis\r
1956 );\r
1957\r
1958 if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {\r
1959 //\r
1960 // Map error or unable to map the whole RFis buffer into a contiguous region. \r
1961 //\r
1962 Status = EFI_OUT_OF_RESOURCES;\r
1963 goto Error6;\r
1964 }\r
1965\r
ed365e93 1966 if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {\r
a41b5272 1967 //\r
1968 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
1969 //\r
1970 Status = EFI_DEVICE_ERROR;\r
1971 goto Error5;\r
1972 }\r
ed365e93 1973 AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;\r
a41b5272 1974\r
1975 //\r
1976 // Allocate memory for command list\r
1977 // Note that the implemenation is a single task model which only use a command list for all ports.\r
1978 //\r
1979 Buffer = NULL;\r
1980 MaxCommandListSize = MaxCommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST);\r
1981 Status = PciIo->AllocateBuffer (\r
1982 PciIo,\r
1983 AllocateAnyPages,\r
1984 EfiBootServicesData,\r
ed365e93 1985 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
a41b5272 1986 &Buffer,\r
1987 0\r
1988 );\r
1989\r
1990 if (EFI_ERROR (Status)) {\r
1991 //\r
1992 // Free mapped resource. \r
1993 //\r
1994 Status = EFI_OUT_OF_RESOURCES;\r
1995 goto Error5;\r
1996 }\r
1997\r
5dec0c68 1998 ZeroMem (Buffer, (UINTN)MaxCommandListSize);\r
a41b5272 1999\r
2000 AhciRegisters->AhciCmdList = Buffer;\r
2001 AhciRegisters->MaxCommandListSize = MaxCommandListSize;\r
5dec0c68 2002 Bytes = (UINTN)MaxCommandListSize;\r
a41b5272 2003\r
2004 Status = PciIo->Map (\r
2005 PciIo,\r
2006 EfiPciIoOperationBusMasterCommonBuffer,\r
2007 Buffer,\r
2008 &Bytes,\r
ed365e93 2009 &AhciCmdListPciAddr,\r
a41b5272 2010 &AhciRegisters->MapCmdList\r
2011 );\r
2012\r
2013 if (EFI_ERROR (Status) || (Bytes != MaxCommandListSize)) {\r
2014 //\r
2015 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2016 //\r
2017 Status = EFI_OUT_OF_RESOURCES;\r
2018 goto Error4;\r
2019 }\r
2020\r
ed365e93 2021 if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {\r
a41b5272 2022 //\r
2023 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2024 //\r
2025 Status = EFI_DEVICE_ERROR;\r
2026 goto Error3;\r
2027 }\r
ed365e93 2028 AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;\r
a41b5272 2029\r
2030 //\r
2031 // Allocate memory for command table\r
2032 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.\r
2033 //\r
2034 Buffer = NULL;\r
2035 MaxCommandTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);\r
2036\r
2037 Status = PciIo->AllocateBuffer (\r
2038 PciIo,\r
2039 AllocateAnyPages,\r
2040 EfiBootServicesData,\r
ed365e93 2041 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
a41b5272 2042 &Buffer,\r
2043 0\r
2044 );\r
2045\r
2046 if (EFI_ERROR (Status)) {\r
2047 //\r
2048 // Free mapped resource. \r
2049 //\r
2050 Status = EFI_OUT_OF_RESOURCES;\r
2051 goto Error3;\r
2052 }\r
2053\r
5dec0c68 2054 ZeroMem (Buffer, (UINTN)MaxCommandTableSize);\r
a41b5272 2055\r
2056 AhciRegisters->AhciCommandTable = Buffer;\r
2057 AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;\r
5dec0c68 2058 Bytes = (UINTN)MaxCommandTableSize;\r
a41b5272 2059\r
2060 Status = PciIo->Map (\r
2061 PciIo,\r
2062 EfiPciIoOperationBusMasterCommonBuffer,\r
2063 Buffer,\r
2064 &Bytes,\r
ed365e93 2065 &AhciCommandTablePciAddr,\r
a41b5272 2066 &AhciRegisters->MapCommandTable\r
2067 );\r
2068\r
2069 if (EFI_ERROR (Status) || (Bytes != MaxCommandTableSize)) {\r
2070 //\r
2071 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2072 //\r
2073 Status = EFI_OUT_OF_RESOURCES;\r
2074 goto Error2;\r
2075 }\r
2076\r
ed365e93 2077 if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {\r
a41b5272 2078 //\r
2079 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2080 //\r
2081 Status = EFI_DEVICE_ERROR;\r
2082 goto Error1;\r
2083 }\r
ed365e93 2084 AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;\r
a41b5272 2085\r
2086 return EFI_SUCCESS;\r
2087 //\r
2088 // Map error or unable to map the whole CmdList buffer into a contiguous region. \r
2089 //\r
2090Error1:\r
2091 PciIo->Unmap (\r
2092 PciIo,\r
2093 AhciRegisters->MapCommandTable\r
2094 );\r
2095Error2:\r
2096 PciIo->FreeBuffer (\r
2097 PciIo,\r
ed365e93 2098 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
a41b5272 2099 AhciRegisters->AhciCommandTable\r
2100 );\r
2101Error3:\r
2102 PciIo->Unmap (\r
2103 PciIo,\r
2104 AhciRegisters->MapCmdList\r
2105 );\r
2106Error4:\r
2107 PciIo->FreeBuffer (\r
2108 PciIo,\r
ed365e93 2109 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
a41b5272 2110 AhciRegisters->AhciCmdList\r
2111 );\r
2112Error5:\r
2113 PciIo->Unmap (\r
2114 PciIo,\r
2115 AhciRegisters->MapRFis\r
2116 );\r
2117Error6:\r
2118 PciIo->FreeBuffer (\r
2119 PciIo,\r
ed365e93 2120 EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
a41b5272 2121 AhciRegisters->AhciRFis\r
2122 );\r
2123\r
2124 return Status;\r
2125}\r
2126\r
2127/**\r
2128 Initialize ATA host controller at AHCI mode.\r
2129\r
2130 The function is designed to initialize ATA host controller. \r
2131 \r
2132 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
2133\r
2134**/\r
2135EFI_STATUS\r
2136EFIAPI\r
2137AhciModeInitialization (\r
2138 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance\r
2139 )\r
2140{\r
2141 EFI_STATUS Status;\r
2142 EFI_PCI_IO_PROTOCOL *PciIo;\r
2143 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2144 UINT32 Capability;\r
2145 UINT8 MaxPortNumber;\r
2146 UINT32 PortImplementBitMap;\r
a41b5272 2147\r
2148 EFI_AHCI_REGISTERS *AhciRegisters;\r
2149\r
2150 UINT8 Port;\r
2151 DATA_64 Data64;\r
2152 UINT32 Offset;\r
2153 UINT32 Data;\r
2154 EFI_IDENTIFY_DATA Buffer;\r
2155 EFI_ATA_DEVICE_TYPE DeviceType;\r
2156 EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
2157 EFI_ATA_TRANSFER_MODE TransferMode;\r
cbd2a4b3 2158 UINT32 PhyDetectDelay;\r
2159\r
a41b5272 2160 if (Instance == NULL) {\r
2161 return EFI_INVALID_PARAMETER;\r
2162 }\r
2163\r
2164 PciIo = Instance->PciIo;\r
2165 IdeInit = Instance->IdeControllerInit;\r
2166\r
cbd2a4b3 2167 Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT); \r
a41b5272 2168\r
2169 if (EFI_ERROR (Status)) {\r
2170 return EFI_DEVICE_ERROR;\r
2171 }\r
2172\r
2173 //\r
2174 // Enable AE before accessing any AHCI registers\r
2175 //\r
2176 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
2177\r
2178 //\r
2179 // Collect AHCI controller information\r
2180 //\r
2181 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
2182\r
2183 //\r
2184 // Get the number of command slots per port supported by this HBA.\r
2185 //\r
cbd2a4b3 2186 MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
a41b5272 2187\r
2188 //\r
2189 // Get the bit map of those ports exposed by this HBA.\r
2190 // It indicates which ports that the HBA supports are available for software to use. \r
2191 //\r
2192 PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
a41b5272 2193 \r
2194 AhciRegisters = &Instance->AhciRegisters;\r
2195 Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
2196\r
2197 if (EFI_ERROR (Status)) {\r
2198 return EFI_OUT_OF_RESOURCES;\r
2199 }\r
2200\r
2201 for (Port = 0; Port < MaxPortNumber; Port ++) { \r
a41b5272 2202 if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
cbd2a4b3 2203 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
2204\r
2205 //\r
2206 // Initialize FIS Base Address Register and Command List Base Address Register for use.\r
2207 //\r
2208 Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
2209 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
2210 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2211 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
2212 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2213\r
2214 Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
2215 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
2216 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2217 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
2218 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2219\r
a41b5272 2220 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
a41b5272 2221 Data = AhciReadReg (PciIo, Offset);\r
2222 if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
2223 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
2224 }\r
a41b5272 2225\r
cbd2a4b3 2226 if ((Capability & EFI_AHCI_CAP_SSS) != 0) {\r
2227 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
2228 }\r
2229\r
2230 //\r
2231 // Disable aggressive power management.\r
2232 //\r
2233 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
2234 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
2235 //\r
2236 // Disable the reporting of the corresponding interrupt to system software.\r
2237 //\r
2238 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
2239 AhciAndReg (PciIo, Offset, 0);\r
a41b5272 2240\r
cbd2a4b3 2241 //\r
2242 // Now inform the IDE Controller Init Module.\r
2243 //\r
2244 IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
2245\r
2246 //\r
2247 // Enable FIS Receive DMA engine for the first D2H FIS.\r
2248 //\r
2249 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
2250 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
8536cc4b 2251 Status = AhciWaitMmioSet (\r
cbd2a4b3 2252 PciIo, \r
2253 Offset,\r
2254 EFI_AHCI_PORT_CMD_FR,\r
2255 EFI_AHCI_PORT_CMD_FR,\r
2256 EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT\r
2257 );\r
2258 if (EFI_ERROR (Status)) {\r
a41b5272 2259 continue;\r
2260 }\r
cbd2a4b3 2261\r
a41b5272 2262 //\r
cbd2a4b3 2263 // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.\r
2264 // It's the requirment from SATA1.0a spec section 5.2.\r
a41b5272 2265 //\r
cbd2a4b3 2266 PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;\r
2267 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
2268 do {\r
2269 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
2270 if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {\r
2271 break;\r
a41b5272 2272 }\r
2273\r
cbd2a4b3 2274 MicroSecondDelay (1000);\r
2275 PhyDetectDelay--;\r
2276 } while (PhyDetectDelay > 0);\r
2277\r
2278 if (PhyDetectDelay == 0) {\r
a41b5272 2279 //\r
cbd2a4b3 2280 // No device detected at this port.\r
a41b5272 2281 //\r
cbd2a4b3 2282 continue;\r
2283 }\r
a41b5272 2284\r
cbd2a4b3 2285 //\r
2286 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ\r
2287 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.\r
2288 //\r
2289 PhyDetectDelay = 16 * 1000;\r
2290 do {\r
2291 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
2292 if (AhciReadReg(PciIo, Offset) != 0) {\r
2293 AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset));\r
2294 }\r
2295 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
a41b5272 2296\r
cbd2a4b3 2297 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;\r
2298 if (Data == 0) {\r
2299 break;\r
2300 }\r
a41b5272 2301\r
cbd2a4b3 2302 MicroSecondDelay (1000);\r
2303 PhyDetectDelay--;\r
2304 } while (PhyDetectDelay > 0);\r
2305 \r
2306 if (PhyDetectDelay == 0) {\r
2307 continue;\r
2308 }\r
a41b5272 2309\r
cbd2a4b3 2310 //\r
2311 // When the first D2H register FIS is received, the content of PxSIG register is updated.\r
2312 //\r
2313 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
8536cc4b 2314 Status = AhciWaitMmioSet (\r
cbd2a4b3 2315 PciIo, \r
2316 Offset,\r
2317 0x0000FFFF,\r
2318 0x00000101,\r
2319 EFI_TIMER_PERIOD_SECONDS(16)\r
2320 );\r
2321 if (EFI_ERROR (Status)) {\r
2322 continue;\r
2323 }\r
a41b5272 2324\r
cbd2a4b3 2325 Data = AhciReadReg (PciIo, Offset);\r
2326 if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
2327 Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
a41b5272 2328\r
cbd2a4b3 2329 if (EFI_ERROR (Status)) {\r
a41b5272 2330 continue;\r
2331 }\r
aca84419 2332\r
cbd2a4b3 2333 DeviceType = EfiIdeCdrom;\r
2334 } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
2335 Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
a41b5272 2336\r
a41b5272 2337 if (EFI_ERROR (Status)) {\r
cbd2a4b3 2338 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
a41b5272 2339 continue;\r
2340 }\r
2341\r
cbd2a4b3 2342 DeviceType = EfiIdeHarddisk;\r
2343 } else {\r
2344 continue;\r
2345 }\r
2346 DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
2347 Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
a41b5272 2348\r
cbd2a4b3 2349 //\r
2350 // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
2351 //\r
2352 if (DeviceType == EfiIdeHarddisk) {\r
2353 AhciAtaSmartSupport (\r
2354 PciIo,\r
2355 AhciRegisters,\r
2356 Port,\r
2357 0,\r
2358 &Buffer,\r
2359 NULL\r
2360 );\r
2361 }\r
a41b5272 2362\r
cbd2a4b3 2363 //\r
2364 // Submit identify data to IDE controller init driver\r
2365 //\r
2366 IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
aca84419 2367\r
cbd2a4b3 2368 //\r
2369 // Now start to config ide device parameter and transfer mode.\r
2370 //\r
2371 Status = IdeInit->CalculateMode (\r
2372 IdeInit,\r
2373 Port,\r
2374 0,\r
2375 &SupportedModes\r
2376 );\r
2377 if (EFI_ERROR (Status)) {\r
2378 DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
2379 continue;\r
2380 }\r
2381\r
2382 //\r
2383 // Set best supported PIO mode on this IDE device\r
2384 //\r
2385 if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
2386 TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
2387 } else {\r
2388 TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
2389 }\r
2390\r
2391 TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
2392\r
2393 //\r
2394 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
2395 // be set together. Only one DMA mode can be set to a device. If setting\r
2396 // DMA mode operation fails, we can continue moving on because we only use\r
2397 // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
2398 //\r
2399 if (SupportedModes->UdmaMode.Valid) {\r
2400 TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
2401 TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
2402 } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
2403 TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
2404 TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode; \r
2405 }\r
2406\r
2407 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
2408 if (EFI_ERROR (Status)) {\r
2409 DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
2410 continue;\r
2411 }\r
2412\r
2413 //\r
2414 // Found a ATA or ATAPI device, add it into the device list.\r
2415 //\r
2416 CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
2417 if (DeviceType == EfiIdeHarddisk) {\r
2418 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
a41b5272 2419 }\r
2420 }\r
2421 }\r
cbd2a4b3 2422\r
a41b5272 2423 return EFI_SUCCESS;\r
2424}\r
2425\r