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