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