]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
MdeModulePkg: Define correct ABI for issuing UNDI command and UNDI callback functions...
[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
a41b5272 1392 UINT32 Delay;\r
1393 UINT32 Value;\r
1394\r
1395 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
1396\r
1397 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
1398\r
a41b5272 1399 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
1400\r
1401 do {\r
1402 Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
1403\r
1404 if ((Value & EFI_AHCI_GHC_RESET) == 0) {\r
1405 break;\r
1406 }\r
1407\r
1408 //\r
1409 // Stall for 100 microseconds.\r
1410 //\r
1411 MicroSecondDelay(100);\r
1412\r
1413 Delay--;\r
1414 } while (Delay > 0);\r
1415\r
1416 if (Delay == 0) {\r
1417 return EFI_TIMEOUT;\r
1418 }\r
1419\r
1420 return EFI_SUCCESS;\r
1421}\r
1422\r
12873d57 1423/**\r
1424 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
1425\r
1426 @param PciIo The PCI IO protocol instance.\r
1427 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1428 @param Port The number of port.\r
1429 @param PortMultiplier The timeout value of stop.\r
1430 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1431\r
1432 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.\r
1433 @retval Others Fail to get return status data.\r
1434\r
1435**/\r
1436EFI_STATUS\r
1437EFIAPI\r
1438AhciAtaSmartReturnStatusCheck (\r
1439 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1440 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1441 IN UINT8 Port,\r
1442 IN UINT8 PortMultiplier,\r
1443 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
1444 )\r
1445{\r
1446 EFI_STATUS Status;\r
1447 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1448 UINT8 LBAMid;\r
1449 UINT8 LBAHigh;\r
1450 UINTN FisBaseAddr;\r
1451 UINT32 Value;\r
1452\r
1453 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1454\r
1455 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1456 AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;\r
1457 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1458 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1459\r
1460 //\r
1461 // Send S.M.A.R.T Read Return Status command to device\r
1462 //\r
1463 Status = AhciNonDataTransfer (\r
1464 PciIo,\r
1465 AhciRegisters,\r
1466 (UINT8)Port,\r
1467 (UINT8)PortMultiplier,\r
1468 NULL,\r
1469 0,\r
1470 &AtaCommandBlock,\r
1471 AtaStatusBlock,\r
490b5ea1 1472 ATA_ATAPI_TIMEOUT,\r
1473 NULL\r
12873d57 1474 );\r
1475\r
1476 if (EFI_ERROR (Status)) {\r
1477 return EFI_DEVICE_ERROR;\r
1478 }\r
1479\r
1480 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1481\r
1482 Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
1483\r
1484 if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
1485 LBAMid = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];\r
1486 LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];\r
1487\r
1488 if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
1489 //\r
1490 // The threshold exceeded condition is not detected by the device\r
1491 //\r
1492 DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
1493\r
1494 } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
1495 //\r
1496 // The threshold exceeded condition is detected by the device\r
1497 //\r
1498 DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
1499 }\r
1500 }\r
1501\r
1502 return EFI_SUCCESS;\r
1503}\r
1504\r
1505/**\r
1506 Enable SMART command of the disk if supported.\r
1507\r
1508 @param PciIo The PCI IO protocol instance.\r
1509 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1510 @param Port The number of port.\r
1511 @param PortMultiplier The timeout value of stop.\r
1512 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
1513 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1514\r
1515**/\r
1516VOID\r
1517EFIAPI\r
1518AhciAtaSmartSupport (\r
1519 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1520 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1521 IN UINT8 Port,\r
1522 IN UINT8 PortMultiplier,\r
490b5ea1 1523 IN EFI_IDENTIFY_DATA *IdentifyData,\r
12873d57 1524 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
1525 )\r
1526{\r
1527 EFI_STATUS Status;\r
1528 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1529\r
1530 //\r
1531 // Detect if the device supports S.M.A.R.T.\r
1532 //\r
1533 if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
1534 //\r
1535 // S.M.A.R.T is not supported by the device\r
1536 //\r
1537 DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n", \r
1538 Port, PortMultiplier));\r
1539 } else {\r
1540 //\r
1541 // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
1542 //\r
1543 if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
1544 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1545\r
1546 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1547 AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;\r
1548 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1549 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1550\r
1551 //\r
1552 // Send S.M.A.R.T Enable command to device\r
1553 //\r
1554 Status = AhciNonDataTransfer (\r
1555 PciIo,\r
1556 AhciRegisters,\r
1557 (UINT8)Port,\r
1558 (UINT8)PortMultiplier,\r
1559 NULL,\r
1560 0,\r
1561 &AtaCommandBlock,\r
1562 AtaStatusBlock,\r
490b5ea1 1563 ATA_ATAPI_TIMEOUT,\r
1564 NULL\r
12873d57 1565 );\r
1566\r
1567\r
1568 if (!EFI_ERROR (Status)) {\r
1569 //\r
1570 // Send S.M.A.R.T AutoSave command to device\r
1571 //\r
1572 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1573\r
1574 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1575 AtaCommandBlock.AtaFeatures = 0xD2;\r
1576 AtaCommandBlock.AtaSectorCount = 0xF1;\r
1577 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1578 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1579\r
1580 Status = AhciNonDataTransfer (\r
1581 PciIo,\r
1582 AhciRegisters,\r
1583 (UINT8)Port,\r
1584 (UINT8)PortMultiplier,\r
1585 NULL,\r
1586 0,\r
1587 &AtaCommandBlock,\r
1588 AtaStatusBlock,\r
490b5ea1 1589 ATA_ATAPI_TIMEOUT,\r
1590 NULL\r
12873d57 1591 );\r
1592\r
1593 if (!EFI_ERROR (Status)) {\r
1594 Status = AhciAtaSmartReturnStatusCheck (\r
1595 PciIo,\r
1596 AhciRegisters,\r
1597 (UINT8)Port,\r
1598 (UINT8)PortMultiplier,\r
1599 AtaStatusBlock\r
1600 );\r
1601 }\r
1602 }\r
1603 }\r
490b5ea1 1604 DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",\r
12873d57 1605 Port, PortMultiplier));\r
1606 }\r
1607\r
1608 return ;\r
1609}\r
1610\r
a41b5272 1611/**\r
1612 Send Buffer cmd to specific device.\r
1613 \r
aca84419 1614 @param PciIo The PCI IO protocol instance.\r
1615 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1616 @param Port The number of port.\r
a41b5272 1617 @param PortMultiplier The timeout value of stop.\r
aca84419 1618 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1619\r
1620 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1621 @retval EFI_TIMEOUT The operation is time out.\r
1622 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1623 @retval EFI_SUCCESS The cmd executes successfully.\r
1624\r
1625**/\r
1626EFI_STATUS\r
1627EFIAPI\r
1628AhciIdentify (\r
1629 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1630 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1631 IN UINT8 Port,\r
1632 IN UINT8 PortMultiplier,\r
1633 IN OUT EFI_IDENTIFY_DATA *Buffer \r
1634 )\r
1635{\r
1636 EFI_STATUS Status;\r
1637 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1638 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1639\r
1640 if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {\r
1641 return EFI_INVALID_PARAMETER;\r
1642 }\r
1643\r
1644 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1645 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 1646\r
a41b5272 1647 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
1648 AtaCommandBlock.AtaSectorCount = 1;\r
1649\r
1650 Status = AhciPioTransfer (\r
1651 PciIo,\r
1652 AhciRegisters,\r
1653 Port,\r
1654 PortMultiplier,\r
1655 NULL,\r
1656 0,\r
1657 TRUE,\r
1658 &AtaCommandBlock,\r
1659 &AtaStatusBlock,\r
1660 Buffer,\r
1661 sizeof (EFI_IDENTIFY_DATA),\r
490b5ea1 1662 ATA_ATAPI_TIMEOUT, \r
1663 NULL\r
a41b5272 1664 );\r
1665\r
1666 return Status;\r
1667}\r
1668\r
1669/**\r
1670 Send Buffer cmd to specific device.\r
1671 \r
aca84419 1672 @param PciIo The PCI IO protocol instance.\r
1673 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1674 @param Port The number of port.\r
a41b5272 1675 @param PortMultiplier The timeout value of stop.\r
aca84419 1676 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1677\r
1678 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1679 @retval EFI_TIMEOUT The operation is time out.\r
1680 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1681 @retval EFI_SUCCESS The cmd executes successfully.\r
1682\r
1683**/\r
1684EFI_STATUS\r
1685EFIAPI\r
1686AhciIdentifyPacket (\r
1687 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1688 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1689 IN UINT8 Port,\r
1690 IN UINT8 PortMultiplier,\r
1691 IN OUT EFI_IDENTIFY_DATA *Buffer \r
1692 )\r
1693{\r
1694 EFI_STATUS Status;\r
1695 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1696 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1697\r
1698 if (PciIo == NULL || AhciRegisters == NULL) {\r
1699 return EFI_INVALID_PARAMETER;\r
1700 }\r
490b5ea1 1701\r
a41b5272 1702 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1703 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1704\r
1705 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DEVICE;\r
1706 AtaCommandBlock.AtaSectorCount = 1;\r
1707\r
1708 Status = AhciPioTransfer (\r
1709 PciIo,\r
1710 AhciRegisters,\r
1711 Port,\r
1712 PortMultiplier,\r
1713 NULL,\r
1714 0,\r
1715 TRUE,\r
1716 &AtaCommandBlock,\r
1717 &AtaStatusBlock,\r
1718 Buffer,\r
1719 sizeof (EFI_IDENTIFY_DATA),\r
490b5ea1 1720 ATA_ATAPI_TIMEOUT,\r
1721 NULL\r
a41b5272 1722 );\r
1723\r
1724 return Status;\r
1725}\r
1726\r
1727/**\r
1728 Send SET FEATURE cmd on specific device.\r
1729 \r
aca84419 1730 @param PciIo The PCI IO protocol instance.\r
1731 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1732 @param Port The number of port.\r
a41b5272 1733 @param PortMultiplier The timeout value of stop.\r
aca84419 1734 @param Feature The data to send Feature register.\r
1735 @param FeatureSpecificData The specific data for SET FEATURE cmd.\r
a41b5272 1736\r
1737 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1738 @retval EFI_TIMEOUT The operation is time out.\r
1739 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1740 @retval EFI_SUCCESS The cmd executes successfully.\r
1741\r
1742**/\r
1743EFI_STATUS\r
1744EFIAPI\r
1745AhciDeviceSetFeature (\r
1746 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1747 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1748 IN UINT8 Port,\r
1749 IN UINT8 PortMultiplier,\r
1750 IN UINT16 Feature,\r
1751 IN UINT32 FeatureSpecificData\r
1752 )\r
1753{\r
1754 EFI_STATUS Status;\r
1755 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1756 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1757\r
1758 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1759 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 1760\r
a41b5272 1761 AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;\r
1762 AtaCommandBlock.AtaFeatures = (UINT8) Feature;\r
1763 AtaCommandBlock.AtaFeaturesExp = (UINT8) (Feature >> 8);\r
1764 AtaCommandBlock.AtaSectorCount = (UINT8) FeatureSpecificData;\r
1765 AtaCommandBlock.AtaSectorNumber = (UINT8) (FeatureSpecificData >> 8);\r
1766 AtaCommandBlock.AtaCylinderLow = (UINT8) (FeatureSpecificData >> 16);\r
1767 AtaCommandBlock.AtaCylinderHigh = (UINT8) (FeatureSpecificData >> 24);\r
1768\r
1769 Status = AhciNonDataTransfer (\r
1770 PciIo,\r
1771 AhciRegisters,\r
1772 (UINT8)Port,\r
1773 (UINT8)PortMultiplier,\r
1774 NULL,\r
1775 0,\r
1776 &AtaCommandBlock,\r
1777 &AtaStatusBlock,\r
490b5ea1 1778 ATA_ATAPI_TIMEOUT, \r
1779 NULL\r
a41b5272 1780 );\r
1781\r
1782 return Status;\r
1783}\r
1784\r
1785/**\r
1786 This function is used to send out ATAPI commands conforms to the Packet Command \r
1787 with PIO Protocol.\r
1788\r
1789 @param PciIo The PCI IO protocol instance.\r
1790 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1791 @param Port The number of port. \r
1792 @param PortMultiplier The number of port multiplier.\r
1793 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.\r
1794\r
1795 @retval EFI_SUCCESS send out the ATAPI packet command successfully\r
1796 and device sends data successfully.\r
1797 @retval EFI_DEVICE_ERROR the device failed to send data.\r
1798\r
1799**/\r
1800EFI_STATUS\r
1801EFIAPI\r
1802AhciPacketCommandExecute (\r
1803 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1804 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1805 IN UINT8 Port,\r
1806 IN UINT8 PortMultiplier,\r
1807 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
1808 )\r
1809{\r
1810 EFI_STATUS Status;\r
1811 VOID *Buffer;\r
1812 UINT32 Length;\r
1813 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1814 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1815 BOOLEAN Read;\r
a41b5272 1816\r
1817 if (Packet == NULL || Packet->Cdb == NULL) {\r
1818 return EFI_INVALID_PARAMETER;\r
1819 }\r
1820\r
1821 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1822 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1823 AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;\r
1824 //\r
1825 // No OVL; No DMA\r
1826 //\r
1827 AtaCommandBlock.AtaFeatures = 0x00;\r
1828 //\r
1829 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
1830 // determine how many data should be transferred.\r
1831 //\r
1832 AtaCommandBlock.AtaCylinderLow = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
1833 AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);\r
1834\r
1835 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1836 Buffer = Packet->InDataBuffer;\r
1837 Length = Packet->InTransferLength;\r
1838 Read = TRUE;\r
1839 } else {\r
1840 Buffer = Packet->OutDataBuffer;\r
1841 Length = Packet->OutTransferLength;\r
1842 Read = FALSE;\r
1843 }\r
1844\r
490b5ea1 1845 if (Length == 0) {\r
a41b5272 1846 Status = AhciNonDataTransfer (\r
1847 PciIo,\r
1848 AhciRegisters,\r
1849 Port,\r
1850 PortMultiplier,\r
1851 Packet->Cdb,\r
1852 Packet->CdbLength,\r
1853 &AtaCommandBlock,\r
1854 &AtaStatusBlock,\r
490b5ea1 1855 Packet->Timeout, \r
1856 NULL\r
a41b5272 1857 );\r
1858 } else {\r
cbd2a4b3 1859 Status = AhciPioTransfer (\r
1860 PciIo,\r
1861 AhciRegisters,\r
1862 Port,\r
1863 PortMultiplier,\r
1864 Packet->Cdb,\r
1865 Packet->CdbLength,\r
1866 Read,\r
1867 &AtaCommandBlock,\r
1868 &AtaStatusBlock,\r
1869 Buffer,\r
1870 Length,\r
1871 Packet->Timeout, \r
1872 NULL\r
1873 );\r
a41b5272 1874 }\r
1875 return Status;\r
1876}\r
1877\r
1878/**\r
1879 Allocate transfer-related data struct which is used at AHCI mode.\r
1880 \r
1881 @param PciIo The PCI IO protocol instance.\r
1882 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1883\r
1884**/\r
1885EFI_STATUS\r
1886EFIAPI\r
1887AhciCreateTransferDescriptor (\r
1888 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1889 IN OUT EFI_AHCI_REGISTERS *AhciRegisters\r
1890 )\r
1891{\r
1892 EFI_STATUS Status;\r
1893 UINTN Bytes;\r
1894 VOID *Buffer;\r
1895\r
1896 UINT32 Capability;\r
1897 UINT8 MaxPortNumber;\r
1898 UINT8 MaxCommandSlotNumber;\r
1899 BOOLEAN Support64Bit;\r
1900 UINT64 MaxReceiveFisSize;\r
1901 UINT64 MaxCommandListSize;\r
1902 UINT64 MaxCommandTableSize;\r
ed365e93 1903 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr;\r
1904 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr;\r
1905 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr;\r
a41b5272 1906\r
1907 Buffer = NULL;\r
1908 //\r
1909 // Collect AHCI controller information\r
1910 //\r
1911 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
1912 MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
1913 //\r
1914 // Get the number of command slots per port supported by this HBA.\r
1915 //\r
1916 MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
aca84419 1917 Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
a41b5272 1918\r
1919 MaxReceiveFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1920 Status = PciIo->AllocateBuffer (\r
1921 PciIo,\r
1922 AllocateAnyPages,\r
1923 EfiBootServicesData,\r
ed365e93 1924 EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
a41b5272 1925 &Buffer,\r
1926 0\r
1927 );\r
1928\r
1929 if (EFI_ERROR (Status)) {\r
1930 return EFI_OUT_OF_RESOURCES;\r
1931 }\r
1932\r
5dec0c68 1933 ZeroMem (Buffer, (UINTN)MaxReceiveFisSize);\r
a41b5272 1934\r
1935 AhciRegisters->AhciRFis = Buffer;\r
1936 AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;\r
5dec0c68 1937 Bytes = (UINTN)MaxReceiveFisSize;\r
a41b5272 1938\r
1939 Status = PciIo->Map (\r
1940 PciIo,\r
1941 EfiPciIoOperationBusMasterCommonBuffer,\r
1942 Buffer,\r
1943 &Bytes,\r
ed365e93 1944 &AhciRFisPciAddr,\r
a41b5272 1945 &AhciRegisters->MapRFis\r
1946 );\r
1947\r
1948 if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {\r
1949 //\r
1950 // Map error or unable to map the whole RFis buffer into a contiguous region. \r
1951 //\r
1952 Status = EFI_OUT_OF_RESOURCES;\r
1953 goto Error6;\r
1954 }\r
1955\r
ed365e93 1956 if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {\r
a41b5272 1957 //\r
1958 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
1959 //\r
1960 Status = EFI_DEVICE_ERROR;\r
1961 goto Error5;\r
1962 }\r
ed365e93 1963 AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;\r
a41b5272 1964\r
1965 //\r
1966 // Allocate memory for command list\r
1967 // Note that the implemenation is a single task model which only use a command list for all ports.\r
1968 //\r
1969 Buffer = NULL;\r
1970 MaxCommandListSize = MaxCommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST);\r
1971 Status = PciIo->AllocateBuffer (\r
1972 PciIo,\r
1973 AllocateAnyPages,\r
1974 EfiBootServicesData,\r
ed365e93 1975 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
a41b5272 1976 &Buffer,\r
1977 0\r
1978 );\r
1979\r
1980 if (EFI_ERROR (Status)) {\r
1981 //\r
1982 // Free mapped resource. \r
1983 //\r
1984 Status = EFI_OUT_OF_RESOURCES;\r
1985 goto Error5;\r
1986 }\r
1987\r
5dec0c68 1988 ZeroMem (Buffer, (UINTN)MaxCommandListSize);\r
a41b5272 1989\r
1990 AhciRegisters->AhciCmdList = Buffer;\r
1991 AhciRegisters->MaxCommandListSize = MaxCommandListSize;\r
5dec0c68 1992 Bytes = (UINTN)MaxCommandListSize;\r
a41b5272 1993\r
1994 Status = PciIo->Map (\r
1995 PciIo,\r
1996 EfiPciIoOperationBusMasterCommonBuffer,\r
1997 Buffer,\r
1998 &Bytes,\r
ed365e93 1999 &AhciCmdListPciAddr,\r
a41b5272 2000 &AhciRegisters->MapCmdList\r
2001 );\r
2002\r
2003 if (EFI_ERROR (Status) || (Bytes != MaxCommandListSize)) {\r
2004 //\r
2005 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2006 //\r
2007 Status = EFI_OUT_OF_RESOURCES;\r
2008 goto Error4;\r
2009 }\r
2010\r
ed365e93 2011 if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {\r
a41b5272 2012 //\r
2013 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2014 //\r
2015 Status = EFI_DEVICE_ERROR;\r
2016 goto Error3;\r
2017 }\r
ed365e93 2018 AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;\r
a41b5272 2019\r
2020 //\r
2021 // Allocate memory for command table\r
2022 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.\r
2023 //\r
2024 Buffer = NULL;\r
2025 MaxCommandTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);\r
2026\r
2027 Status = PciIo->AllocateBuffer (\r
2028 PciIo,\r
2029 AllocateAnyPages,\r
2030 EfiBootServicesData,\r
ed365e93 2031 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
a41b5272 2032 &Buffer,\r
2033 0\r
2034 );\r
2035\r
2036 if (EFI_ERROR (Status)) {\r
2037 //\r
2038 // Free mapped resource. \r
2039 //\r
2040 Status = EFI_OUT_OF_RESOURCES;\r
2041 goto Error3;\r
2042 }\r
2043\r
5dec0c68 2044 ZeroMem (Buffer, (UINTN)MaxCommandTableSize);\r
a41b5272 2045\r
2046 AhciRegisters->AhciCommandTable = Buffer;\r
2047 AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;\r
5dec0c68 2048 Bytes = (UINTN)MaxCommandTableSize;\r
a41b5272 2049\r
2050 Status = PciIo->Map (\r
2051 PciIo,\r
2052 EfiPciIoOperationBusMasterCommonBuffer,\r
2053 Buffer,\r
2054 &Bytes,\r
ed365e93 2055 &AhciCommandTablePciAddr,\r
a41b5272 2056 &AhciRegisters->MapCommandTable\r
2057 );\r
2058\r
2059 if (EFI_ERROR (Status) || (Bytes != MaxCommandTableSize)) {\r
2060 //\r
2061 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
2062 //\r
2063 Status = EFI_OUT_OF_RESOURCES;\r
2064 goto Error2;\r
2065 }\r
2066\r
ed365e93 2067 if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {\r
a41b5272 2068 //\r
2069 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
2070 //\r
2071 Status = EFI_DEVICE_ERROR;\r
2072 goto Error1;\r
2073 }\r
ed365e93 2074 AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;\r
a41b5272 2075\r
2076 return EFI_SUCCESS;\r
2077 //\r
2078 // Map error or unable to map the whole CmdList buffer into a contiguous region. \r
2079 //\r
2080Error1:\r
2081 PciIo->Unmap (\r
2082 PciIo,\r
2083 AhciRegisters->MapCommandTable\r
2084 );\r
2085Error2:\r
2086 PciIo->FreeBuffer (\r
2087 PciIo,\r
ed365e93 2088 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
a41b5272 2089 AhciRegisters->AhciCommandTable\r
2090 );\r
2091Error3:\r
2092 PciIo->Unmap (\r
2093 PciIo,\r
2094 AhciRegisters->MapCmdList\r
2095 );\r
2096Error4:\r
2097 PciIo->FreeBuffer (\r
2098 PciIo,\r
ed365e93 2099 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
a41b5272 2100 AhciRegisters->AhciCmdList\r
2101 );\r
2102Error5:\r
2103 PciIo->Unmap (\r
2104 PciIo,\r
2105 AhciRegisters->MapRFis\r
2106 );\r
2107Error6:\r
2108 PciIo->FreeBuffer (\r
2109 PciIo,\r
ed365e93 2110 EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
a41b5272 2111 AhciRegisters->AhciRFis\r
2112 );\r
2113\r
2114 return Status;\r
2115}\r
2116\r
2117/**\r
2118 Initialize ATA host controller at AHCI mode.\r
2119\r
2120 The function is designed to initialize ATA host controller. \r
2121 \r
2122 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
2123\r
2124**/\r
2125EFI_STATUS\r
2126EFIAPI\r
2127AhciModeInitialization (\r
2128 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance\r
2129 )\r
2130{\r
2131 EFI_STATUS Status;\r
2132 EFI_PCI_IO_PROTOCOL *PciIo;\r
2133 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2134 UINT32 Capability;\r
2135 UINT8 MaxPortNumber;\r
2136 UINT32 PortImplementBitMap;\r
a41b5272 2137\r
2138 EFI_AHCI_REGISTERS *AhciRegisters;\r
2139\r
2140 UINT8 Port;\r
2141 DATA_64 Data64;\r
2142 UINT32 Offset;\r
2143 UINT32 Data;\r
2144 EFI_IDENTIFY_DATA Buffer;\r
2145 EFI_ATA_DEVICE_TYPE DeviceType;\r
2146 EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
2147 EFI_ATA_TRANSFER_MODE TransferMode;\r
cbd2a4b3 2148 UINT32 PhyDetectDelay;\r
2149\r
a41b5272 2150 if (Instance == NULL) {\r
2151 return EFI_INVALID_PARAMETER;\r
2152 }\r
2153\r
2154 PciIo = Instance->PciIo;\r
2155 IdeInit = Instance->IdeControllerInit;\r
2156\r
cbd2a4b3 2157 Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT); \r
a41b5272 2158\r
2159 if (EFI_ERROR (Status)) {\r
2160 return EFI_DEVICE_ERROR;\r
2161 }\r
2162\r
2163 //\r
2164 // Enable AE before accessing any AHCI registers\r
2165 //\r
2166 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
2167\r
2168 //\r
2169 // Collect AHCI controller information\r
2170 //\r
2171 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
2172\r
2173 //\r
2174 // Get the number of command slots per port supported by this HBA.\r
2175 //\r
cbd2a4b3 2176 MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
a41b5272 2177\r
2178 //\r
2179 // Get the bit map of those ports exposed by this HBA.\r
2180 // It indicates which ports that the HBA supports are available for software to use. \r
2181 //\r
2182 PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
a41b5272 2183 \r
2184 AhciRegisters = &Instance->AhciRegisters;\r
2185 Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
2186\r
2187 if (EFI_ERROR (Status)) {\r
2188 return EFI_OUT_OF_RESOURCES;\r
2189 }\r
2190\r
2191 for (Port = 0; Port < MaxPortNumber; Port ++) { \r
a41b5272 2192 if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
cbd2a4b3 2193 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
2194\r
2195 //\r
2196 // Initialize FIS Base Address Register and Command List Base Address Register for use.\r
2197 //\r
2198 Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
2199 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
2200 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2201 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
2202 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2203\r
2204 Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
2205 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
2206 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2207 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
2208 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2209\r
a41b5272 2210 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
a41b5272 2211 Data = AhciReadReg (PciIo, Offset);\r
2212 if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
2213 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
2214 }\r
a41b5272 2215\r
cbd2a4b3 2216 if ((Capability & EFI_AHCI_CAP_SSS) != 0) {\r
2217 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
2218 }\r
2219\r
2220 //\r
2221 // Disable aggressive power management.\r
2222 //\r
2223 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
2224 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
2225 //\r
2226 // Disable the reporting of the corresponding interrupt to system software.\r
2227 //\r
2228 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
2229 AhciAndReg (PciIo, Offset, 0);\r
a41b5272 2230\r
cbd2a4b3 2231 //\r
2232 // Now inform the IDE Controller Init Module.\r
2233 //\r
2234 IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
2235\r
2236 //\r
2237 // Enable FIS Receive DMA engine for the first D2H FIS.\r
2238 //\r
2239 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
2240 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
2241 Status = AhciWaitMemSet (\r
2242 PciIo, \r
2243 Offset,\r
2244 EFI_AHCI_PORT_CMD_FR,\r
2245 EFI_AHCI_PORT_CMD_FR,\r
2246 EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT\r
2247 );\r
2248 if (EFI_ERROR (Status)) {\r
a41b5272 2249 continue;\r
2250 }\r
cbd2a4b3 2251\r
a41b5272 2252 //\r
cbd2a4b3 2253 // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.\r
2254 // It's the requirment from SATA1.0a spec section 5.2.\r
a41b5272 2255 //\r
cbd2a4b3 2256 PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;\r
2257 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
2258 do {\r
2259 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
2260 if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {\r
2261 break;\r
a41b5272 2262 }\r
2263\r
cbd2a4b3 2264 MicroSecondDelay (1000);\r
2265 PhyDetectDelay--;\r
2266 } while (PhyDetectDelay > 0);\r
2267\r
2268 if (PhyDetectDelay == 0) {\r
a41b5272 2269 //\r
cbd2a4b3 2270 // No device detected at this port.\r
a41b5272 2271 //\r
cbd2a4b3 2272 continue;\r
2273 }\r
a41b5272 2274\r
cbd2a4b3 2275 //\r
2276 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ\r
2277 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.\r
2278 //\r
2279 PhyDetectDelay = 16 * 1000;\r
2280 do {\r
2281 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
2282 if (AhciReadReg(PciIo, Offset) != 0) {\r
2283 AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset));\r
2284 }\r
2285 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
a41b5272 2286\r
cbd2a4b3 2287 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;\r
2288 if (Data == 0) {\r
2289 break;\r
2290 }\r
a41b5272 2291\r
cbd2a4b3 2292 MicroSecondDelay (1000);\r
2293 PhyDetectDelay--;\r
2294 } while (PhyDetectDelay > 0);\r
2295 \r
2296 if (PhyDetectDelay == 0) {\r
2297 continue;\r
2298 }\r
a41b5272 2299\r
cbd2a4b3 2300 //\r
2301 // When the first D2H register FIS is received, the content of PxSIG register is updated.\r
2302 //\r
2303 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
2304 Status = AhciWaitMemSet (\r
2305 PciIo, \r
2306 Offset,\r
2307 0x0000FFFF,\r
2308 0x00000101,\r
2309 EFI_TIMER_PERIOD_SECONDS(16)\r
2310 );\r
2311 if (EFI_ERROR (Status)) {\r
2312 continue;\r
2313 }\r
a41b5272 2314\r
cbd2a4b3 2315 Data = AhciReadReg (PciIo, Offset);\r
2316 if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
2317 Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
a41b5272 2318\r
cbd2a4b3 2319 if (EFI_ERROR (Status)) {\r
a41b5272 2320 continue;\r
2321 }\r
aca84419 2322\r
cbd2a4b3 2323 DeviceType = EfiIdeCdrom;\r
2324 } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
2325 Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
a41b5272 2326\r
a41b5272 2327 if (EFI_ERROR (Status)) {\r
cbd2a4b3 2328 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
a41b5272 2329 continue;\r
2330 }\r
2331\r
cbd2a4b3 2332 DeviceType = EfiIdeHarddisk;\r
2333 } else {\r
2334 continue;\r
2335 }\r
2336 DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
2337 Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
a41b5272 2338\r
cbd2a4b3 2339 //\r
2340 // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
2341 //\r
2342 if (DeviceType == EfiIdeHarddisk) {\r
2343 AhciAtaSmartSupport (\r
2344 PciIo,\r
2345 AhciRegisters,\r
2346 Port,\r
2347 0,\r
2348 &Buffer,\r
2349 NULL\r
2350 );\r
2351 }\r
a41b5272 2352\r
cbd2a4b3 2353 //\r
2354 // Submit identify data to IDE controller init driver\r
2355 //\r
2356 IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
aca84419 2357\r
cbd2a4b3 2358 //\r
2359 // Now start to config ide device parameter and transfer mode.\r
2360 //\r
2361 Status = IdeInit->CalculateMode (\r
2362 IdeInit,\r
2363 Port,\r
2364 0,\r
2365 &SupportedModes\r
2366 );\r
2367 if (EFI_ERROR (Status)) {\r
2368 DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
2369 continue;\r
2370 }\r
2371\r
2372 //\r
2373 // Set best supported PIO mode on this IDE device\r
2374 //\r
2375 if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
2376 TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
2377 } else {\r
2378 TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
2379 }\r
2380\r
2381 TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
2382\r
2383 //\r
2384 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
2385 // be set together. Only one DMA mode can be set to a device. If setting\r
2386 // DMA mode operation fails, we can continue moving on because we only use\r
2387 // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
2388 //\r
2389 if (SupportedModes->UdmaMode.Valid) {\r
2390 TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
2391 TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
2392 } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
2393 TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
2394 TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode; \r
2395 }\r
2396\r
2397 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
2398 if (EFI_ERROR (Status)) {\r
2399 DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
2400 continue;\r
2401 }\r
2402\r
2403 //\r
2404 // Found a ATA or ATAPI device, add it into the device list.\r
2405 //\r
2406 CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
2407 if (DeviceType == EfiIdeHarddisk) {\r
2408 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
a41b5272 2409 }\r
2410 }\r
2411 }\r
cbd2a4b3 2412\r
a41b5272 2413 return EFI_SUCCESS;\r
2414}\r
2415\r