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