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