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