]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
update due to a DSC error.
[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
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 UINTN *RetryTimes\r
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
659 return EFI_OUT_OF_RESOURCES;\r
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
880 return EFI_OUT_OF_RESOURCES;\r
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
1276 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL);\r
1277\r
1278 AhciWaitMemSet (\r
490b5ea1 1279 PciIo,\r
a41b5272 1280 Offset,\r
1281 EFI_AHCI_PORT_CMD_COL,\r
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
1819 UINT8 Retry;\r
1820\r
1821 if (Packet == NULL || Packet->Cdb == NULL) {\r
1822 return EFI_INVALID_PARAMETER;\r
1823 }\r
1824\r
1825 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1826 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1827 AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;\r
1828 //\r
1829 // No OVL; No DMA\r
1830 //\r
1831 AtaCommandBlock.AtaFeatures = 0x00;\r
1832 //\r
1833 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
1834 // determine how many data should be transferred.\r
1835 //\r
1836 AtaCommandBlock.AtaCylinderLow = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
1837 AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);\r
1838\r
1839 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1840 Buffer = Packet->InDataBuffer;\r
1841 Length = Packet->InTransferLength;\r
1842 Read = TRUE;\r
1843 } else {\r
1844 Buffer = Packet->OutDataBuffer;\r
1845 Length = Packet->OutTransferLength;\r
1846 Read = FALSE;\r
1847 }\r
1848\r
490b5ea1 1849 if (Length == 0) {\r
a41b5272 1850 Status = AhciNonDataTransfer (\r
1851 PciIo,\r
1852 AhciRegisters,\r
1853 Port,\r
1854 PortMultiplier,\r
1855 Packet->Cdb,\r
1856 Packet->CdbLength,\r
1857 &AtaCommandBlock,\r
1858 &AtaStatusBlock,\r
490b5ea1 1859 Packet->Timeout, \r
1860 NULL\r
a41b5272 1861 );\r
1862 } else {\r
1863 //\r
1864 // READ_CAPACITY cmd may execute failure. Retry 5 times\r
1865 //\r
1866 if (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_READ_CAPACITY) {\r
1867 Retry = 5;\r
1868 } else {\r
1869 Retry = 1;\r
1870 }\r
1871 do {\r
1872 Status = AhciPioTransfer (\r
1873 PciIo,\r
1874 AhciRegisters,\r
1875 Port,\r
1876 PortMultiplier,\r
1877 Packet->Cdb,\r
1878 Packet->CdbLength,\r
1879 Read,\r
1880 &AtaCommandBlock,\r
1881 &AtaStatusBlock,\r
1882 Buffer,\r
1883 Length,\r
490b5ea1 1884 Packet->Timeout, \r
1885 NULL\r
a41b5272 1886 );\r
1887 if (!EFI_ERROR (Status)) {\r
1888 break;\r
1889 }\r
1890 Retry--;\r
1891 } while (Retry != 0);\r
1892 }\r
1893 return Status;\r
1894}\r
1895\r
1896/**\r
1897 Allocate transfer-related data struct which is used at AHCI mode.\r
1898 \r
1899 @param PciIo The PCI IO protocol instance.\r
1900 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1901\r
1902**/\r
1903EFI_STATUS\r
1904EFIAPI\r
1905AhciCreateTransferDescriptor (\r
1906 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1907 IN OUT EFI_AHCI_REGISTERS *AhciRegisters\r
1908 )\r
1909{\r
1910 EFI_STATUS Status;\r
1911 UINTN Bytes;\r
1912 VOID *Buffer;\r
1913\r
1914 UINT32 Capability;\r
1915 UINT8 MaxPortNumber;\r
1916 UINT8 MaxCommandSlotNumber;\r
1917 BOOLEAN Support64Bit;\r
1918 UINT64 MaxReceiveFisSize;\r
1919 UINT64 MaxCommandListSize;\r
1920 UINT64 MaxCommandTableSize;\r
ed365e93 1921 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr;\r
1922 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr;\r
1923 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr;\r
a41b5272 1924\r
1925 Buffer = NULL;\r
1926 //\r
1927 // Collect AHCI controller information\r
1928 //\r
1929 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
1930 MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
1931 //\r
1932 // Get the number of command slots per port supported by this HBA.\r
1933 //\r
1934 MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
aca84419 1935 Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
a41b5272 1936\r
1937 MaxReceiveFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1938 Status = PciIo->AllocateBuffer (\r
1939 PciIo,\r
1940 AllocateAnyPages,\r
1941 EfiBootServicesData,\r
ed365e93 1942 EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
a41b5272 1943 &Buffer,\r
1944 0\r
1945 );\r
1946\r
1947 if (EFI_ERROR (Status)) {\r
1948 return EFI_OUT_OF_RESOURCES;\r
1949 }\r
1950\r
5dec0c68 1951 ZeroMem (Buffer, (UINTN)MaxReceiveFisSize);\r
a41b5272 1952\r
1953 AhciRegisters->AhciRFis = Buffer;\r
1954 AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;\r
5dec0c68 1955 Bytes = (UINTN)MaxReceiveFisSize;\r
a41b5272 1956\r
1957 Status = PciIo->Map (\r
1958 PciIo,\r
1959 EfiPciIoOperationBusMasterCommonBuffer,\r
1960 Buffer,\r
1961 &Bytes,\r
ed365e93 1962 &AhciRFisPciAddr,\r
a41b5272 1963 &AhciRegisters->MapRFis\r
1964 );\r
1965\r
1966 if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {\r
1967 //\r
1968 // Map error or unable to map the whole RFis buffer into a contiguous region. \r
1969 //\r
1970 Status = EFI_OUT_OF_RESOURCES;\r
1971 goto Error6;\r
1972 }\r
1973\r
ed365e93 1974 if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {\r
a41b5272 1975 //\r
1976 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
1977 //\r
1978 Status = EFI_DEVICE_ERROR;\r
1979 goto Error5;\r
1980 }\r
ed365e93 1981 AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;\r
a41b5272 1982\r
1983 //\r
1984 // Allocate memory for command list\r
1985 // Note that the implemenation is a single task model which only use a command list for all ports.\r
1986 //\r
1987 Buffer = NULL;\r
1988 MaxCommandListSize = MaxCommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST);\r
1989 Status = PciIo->AllocateBuffer (\r
1990 PciIo,\r
1991 AllocateAnyPages,\r
1992 EfiBootServicesData,\r
ed365e93 1993 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
a41b5272 1994 &Buffer,\r
1995 0\r
1996 );\r
1997\r
1998 if (EFI_ERROR (Status)) {\r
1999 //\r
2000 // Free mapped resource. \r
2001 //\r
2002 Status = EFI_OUT_OF_RESOURCES;\r
2003 goto Error5;\r
2004 }\r
2005\r
5dec0c68 2006 ZeroMem (Buffer, (UINTN)MaxCommandListSize);\r
a41b5272 2007\r
2008 AhciRegisters->AhciCmdList = Buffer;\r
2009 AhciRegisters->MaxCommandListSize = MaxCommandListSize;\r
5dec0c68 2010 Bytes = (UINTN)MaxCommandListSize;\r
a41b5272 2011\r
2012 Status = PciIo->Map (\r
2013 PciIo,\r
2014 EfiPciIoOperationBusMasterCommonBuffer,\r
2015 Buffer,\r
2016 &Bytes,\r
ed365e93 2017 &AhciCmdListPciAddr,\r
a41b5272 2018 &AhciRegisters->MapCmdList\r
2019 );\r
2020\r
2021 if (EFI_ERROR (Status) || (Bytes != MaxCommandListSize)) {\r
2022 //\r
2023 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2024 //\r
2025 Status = EFI_OUT_OF_RESOURCES;\r
2026 goto Error4;\r
2027 }\r
2028\r
ed365e93 2029 if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {\r
a41b5272 2030 //\r
2031 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2032 //\r
2033 Status = EFI_DEVICE_ERROR;\r
2034 goto Error3;\r
2035 }\r
ed365e93 2036 AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;\r
a41b5272 2037\r
2038 //\r
2039 // Allocate memory for command table\r
2040 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.\r
2041 //\r
2042 Buffer = NULL;\r
2043 MaxCommandTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);\r
2044\r
2045 Status = PciIo->AllocateBuffer (\r
2046 PciIo,\r
2047 AllocateAnyPages,\r
2048 EfiBootServicesData,\r
ed365e93 2049 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
a41b5272 2050 &Buffer,\r
2051 0\r
2052 );\r
2053\r
2054 if (EFI_ERROR (Status)) {\r
2055 //\r
2056 // Free mapped resource. \r
2057 //\r
2058 Status = EFI_OUT_OF_RESOURCES;\r
2059 goto Error3;\r
2060 }\r
2061\r
5dec0c68 2062 ZeroMem (Buffer, (UINTN)MaxCommandTableSize);\r
a41b5272 2063\r
2064 AhciRegisters->AhciCommandTable = Buffer;\r
2065 AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;\r
5dec0c68 2066 Bytes = (UINTN)MaxCommandTableSize;\r
a41b5272 2067\r
2068 Status = PciIo->Map (\r
2069 PciIo,\r
2070 EfiPciIoOperationBusMasterCommonBuffer,\r
2071 Buffer,\r
2072 &Bytes,\r
ed365e93 2073 &AhciCommandTablePciAddr,\r
a41b5272 2074 &AhciRegisters->MapCommandTable\r
2075 );\r
2076\r
2077 if (EFI_ERROR (Status) || (Bytes != MaxCommandTableSize)) {\r
2078 //\r
2079 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2080 //\r
2081 Status = EFI_OUT_OF_RESOURCES;\r
2082 goto Error2;\r
2083 }\r
2084\r
ed365e93 2085 if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {\r
a41b5272 2086 //\r
2087 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2088 //\r
2089 Status = EFI_DEVICE_ERROR;\r
2090 goto Error1;\r
2091 }\r
ed365e93 2092 AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;\r
a41b5272 2093\r
2094 return EFI_SUCCESS;\r
2095 //\r
2096 // Map error or unable to map the whole CmdList buffer into a contiguous region. \r
2097 //\r
2098Error1:\r
2099 PciIo->Unmap (\r
2100 PciIo,\r
2101 AhciRegisters->MapCommandTable\r
2102 );\r
2103Error2:\r
2104 PciIo->FreeBuffer (\r
2105 PciIo,\r
ed365e93 2106 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
a41b5272 2107 AhciRegisters->AhciCommandTable\r
2108 );\r
2109Error3:\r
2110 PciIo->Unmap (\r
2111 PciIo,\r
2112 AhciRegisters->MapCmdList\r
2113 );\r
2114Error4:\r
2115 PciIo->FreeBuffer (\r
2116 PciIo,\r
ed365e93 2117 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
a41b5272 2118 AhciRegisters->AhciCmdList\r
2119 );\r
2120Error5:\r
2121 PciIo->Unmap (\r
2122 PciIo,\r
2123 AhciRegisters->MapRFis\r
2124 );\r
2125Error6:\r
2126 PciIo->FreeBuffer (\r
2127 PciIo,\r
ed365e93 2128 EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
a41b5272 2129 AhciRegisters->AhciRFis\r
2130 );\r
2131\r
2132 return Status;\r
2133}\r
2134\r
2135/**\r
2136 Initialize ATA host controller at AHCI mode.\r
2137\r
2138 The function is designed to initialize ATA host controller. \r
2139 \r
2140 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
2141\r
2142**/\r
2143EFI_STATUS\r
2144EFIAPI\r
2145AhciModeInitialization (\r
2146 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance\r
2147 )\r
2148{\r
2149 EFI_STATUS Status;\r
2150 EFI_PCI_IO_PROTOCOL *PciIo;\r
2151 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2152 UINT32 Capability;\r
2153 UINT8 MaxPortNumber;\r
2154 UINT32 PortImplementBitMap;\r
2155 UINT8 MaxCommandSlotNumber;\r
2156 BOOLEAN Support64Bit;\r
2157\r
2158 EFI_AHCI_REGISTERS *AhciRegisters;\r
2159\r
2160 UINT8 Port;\r
2161 DATA_64 Data64;\r
2162 UINT32 Offset;\r
2163 UINT32 Data;\r
2164 EFI_IDENTIFY_DATA Buffer;\r
2165 EFI_ATA_DEVICE_TYPE DeviceType;\r
2166 EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
2167 EFI_ATA_TRANSFER_MODE TransferMode;\r
2168 \r
2169 if (Instance == NULL) {\r
2170 return EFI_INVALID_PARAMETER;\r
2171 }\r
2172\r
2173 PciIo = Instance->PciIo;\r
2174 IdeInit = Instance->IdeControllerInit;\r
2175\r
2176 Status = AhciReset (PciIo, ATA_ATAPI_TIMEOUT); \r
2177\r
2178 if (EFI_ERROR (Status)) {\r
2179 return EFI_DEVICE_ERROR;\r
2180 }\r
2181\r
2182 //\r
2183 // Enable AE before accessing any AHCI registers\r
2184 //\r
2185 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
2186\r
2187 //\r
2188 // Collect AHCI controller information\r
2189 //\r
2190 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
2191\r
2192 //\r
2193 // Get the number of command slots per port supported by this HBA.\r
2194 //\r
2195 MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
aca84419 2196 Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
a41b5272 2197\r
2198 //\r
2199 // Get the bit map of those ports exposed by this HBA.\r
2200 // It indicates which ports that the HBA supports are available for software to use. \r
2201 //\r
2202 PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
2203 MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
2204 \r
2205 AhciRegisters = &Instance->AhciRegisters;\r
2206 Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
2207\r
2208 if (EFI_ERROR (Status)) {\r
2209 return EFI_OUT_OF_RESOURCES;\r
2210 }\r
2211\r
2212 for (Port = 0; Port < MaxPortNumber; Port ++) { \r
2213 Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
2214 \r
2215 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
2216 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2217 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
2218 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2219 \r
2220 //\r
2221 // Single task envrionment, we only use one command table for all port\r
2222 //\r
2223 Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
2224 \r
2225 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
2226 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2227 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
2228 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2229 \r
2230 if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
2231 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
2232 \r
2233 if ((Capability & EFI_AHCI_PORT_CMD_ASP) != 0) {\r
2234 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
2235 }\r
2236 Data = AhciReadReg (PciIo, Offset);\r
2237 if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
2238 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
2239 }\r
2240 \r
2241 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE|EFI_AHCI_PORT_CMD_COL|EFI_AHCI_PORT_CMD_ST));\r
2242 }\r
2243 \r
2244 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
2245 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_MASK));\r
2246 \r
2247 AhciAndReg (PciIo, Offset,(UINT32) ~(EFI_AHCI_PORT_SCTL_IPM_PSD));\r
2248 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_PSD);\r
2249 \r
2250 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_SSD));\r
2251 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_SSD);\r
2252 \r
2253 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
2254 AhciAndReg (PciIo, Offset, 0);\r
2255 \r
2256 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
2257 AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
2258 }\r
2259\r
2260 //\r
2261 // Stall for 100 milliseconds.\r
2262 //\r
2263 MicroSecondDelay(100000);\r
2264 \r
2265 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
2266 \r
2267 for (Port = 0; Port < MaxPortNumber; Port ++) { \r
2268 if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
2269 \r
2270 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
2271 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
2272\r
2273 if (Data == 0) {\r
2274 continue;\r
2275 }\r
2276 //\r
2277 // Found device in the port\r
2278 //\r
2279 if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
2280 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
2281\r
2282 Status = AhciWaitMemSet (\r
2283 PciIo, \r
2284 Offset,\r
2285 0x0000FFFF,\r
2286 0x00000101,\r
2287 ATA_ATAPI_TIMEOUT\r
2288 );\r
2289 if (EFI_ERROR (Status)) {\r
2290 continue;\r
2291 }\r
2292\r
2293 //\r
2294 // Now inform the IDE Controller Init Module.\r
2295 //\r
2296 IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
2297\r
2298 Data = AhciReadReg (PciIo, Offset);\r
2299\r
2300 if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
2301 Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
2302\r
2303 if (EFI_ERROR (Status)) {\r
2304 continue;\r
2305 }\r
2306\r
2307 DeviceType = EfiIdeCdrom;\r
2308 } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
2309 Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
2310\r
2311 if (EFI_ERROR (Status)) {\r
2312 continue;\r
2313 }\r
2314\r
2315 DeviceType = EfiIdeHarddisk;\r
2316 } else {\r
2317 continue;\r
2318 }\r
aca84419 2319\r
a41b5272 2320 DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
2321 Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
2322\r
12873d57 2323 //\r
2324 // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
2325 //\r
2326 if (DeviceType == EfiIdeHarddisk) {\r
2327 AhciAtaSmartSupport (\r
2328 PciIo,\r
2329 AhciRegisters,\r
2330 Port,\r
2331 0,\r
2332 &Buffer,\r
2333 NULL\r
2334 );\r
2335 }\r
2336\r
a41b5272 2337 //\r
2338 // Submit identify data to IDE controller init driver\r
2339 //\r
2340 IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
2341\r
2342 //\r
2343 // Now start to config ide device parameter and transfer mode.\r
2344 //\r
2345 Status = IdeInit->CalculateMode (\r
2346 IdeInit,\r
2347 Port,\r
2348 0,\r
2349 &SupportedModes\r
2350 );\r
2351 if (EFI_ERROR (Status)) {\r
2352 DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
2353 continue;\r
2354 }\r
2355\r
2356 //\r
2357 // Set best supported PIO mode on this IDE device\r
2358 //\r
2359 if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
2360 TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
2361 } else {\r
2362 TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
2363 }\r
2364\r
2365 TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
2366 \r
2367 //\r
2368 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
2369 // be set together. Only one DMA mode can be set to a device. If setting\r
2370 // DMA mode operation fails, we can continue moving on because we only use\r
2371 // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
2372 //\r
2373 if (SupportedModes->UdmaMode.Valid) {\r
2374 TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
2375 TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
2376 } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
2377 TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
2378 TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode; \r
2379 }\r
2380\r
2381 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
aca84419 2382\r
a41b5272 2383 if (EFI_ERROR (Status)) {\r
2384 DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
2385 continue;\r
2386 }\r
2387 //\r
2388 // Found a ATA or ATAPI device, add it into the device list.\r
2389 //\r
2390 CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
2391 }\r
2392 }\r
2393 }\r
2394 return EFI_SUCCESS;\r
2395}\r
2396\r