]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c
d51865380ff26ea75939c86ffc50e18b42551a88
[mirror_edk2.git] / SecurityPkg / Tcg / Opal / OpalPassword / OpalAhciMode.c
1 /** @file
2 This driver is used for Opal Password Feature support at AHCI mode.
3
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15
16 #include "OpalPasswordPei.h"
17
18 /**
19 Start command for give slot on specific port.
20
21 @param AhciBar AHCI bar address.
22 @param Port The number of port.
23 @param CommandSlot The number of CommandSlot.
24 @param Timeout The timeout Value of start.
25
26 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
27 @retval EFI_TIMEOUT The operation is time out.
28 @retval EFI_SUCCESS The command start successfully.
29
30 **/
31 EFI_STATUS
32 EFIAPI
33 AhciStartCommand (
34 IN UINT32 AhciBar,
35 IN UINT8 Port,
36 IN UINT8 CommandSlot,
37 IN UINT64 Timeout
38 );
39
40 /**
41 Stop command running for giving port
42
43 @param AhciBar AHCI bar address.
44 @param Port The number of port.
45 @param Timeout The timeout Value of stop.
46
47 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
48 @retval EFI_TIMEOUT The operation is time out.
49 @retval EFI_SUCCESS The command stop successfully.
50
51 **/
52 EFI_STATUS
53 EFIAPI
54 AhciStopCommand (
55 IN UINT32 AhciBar,
56 IN UINT8 Port,
57 IN UINT64 Timeout
58 );
59
60 /**
61 Read AHCI Operation register.
62
63 @param AhciBar AHCI bar address.
64 @param Offset The operation register offset.
65
66 @return The register content read.
67
68 **/
69 UINT32
70 EFIAPI
71 AhciReadReg (
72 IN UINT32 AhciBar,
73 IN UINT32 Offset
74 )
75 {
76 UINT32 Data;
77
78 Data = 0;
79
80 Data = MmioRead32 (AhciBar + Offset);
81
82 return Data;
83 }
84
85 /**
86 Write AHCI Operation register.
87
88 @param AhciBar AHCI bar address.
89 @param Offset The operation register offset.
90 @param Data The Data used to write down.
91
92 **/
93 VOID
94 EFIAPI
95 AhciWriteReg (
96 IN UINT32 AhciBar,
97 IN UINT32 Offset,
98 IN UINT32 Data
99 )
100 {
101 MmioWrite32 (AhciBar + Offset, Data);
102
103 return ;
104 }
105
106 /**
107 Do AND operation with the Value of AHCI Operation register.
108
109 @param AhciBar AHCI bar address.
110 @param Offset The operation register offset.
111 @param AndData The Data used to do AND operation.
112
113 **/
114 VOID
115 EFIAPI
116 AhciAndReg (
117 IN UINT32 AhciBar,
118 IN UINT32 Offset,
119 IN UINT32 AndData
120 )
121 {
122 UINT32 Data;
123
124 Data = AhciReadReg (AhciBar, Offset);
125
126 Data &= AndData;
127
128 AhciWriteReg (AhciBar, Offset, Data);
129 }
130
131 /**
132 Do OR operation with the Value of AHCI Operation register.
133
134 @param AhciBar AHCI bar address.
135 @param Offset The operation register offset.
136 @param OrData The Data used to do OR operation.
137
138 **/
139 VOID
140 EFIAPI
141 AhciOrReg (
142 IN UINT32 AhciBar,
143 IN UINT32 Offset,
144 IN UINT32 OrData
145 )
146 {
147 UINT32 Data;
148
149 Data = AhciReadReg (AhciBar, Offset);
150
151 Data |= OrData;
152
153 AhciWriteReg (AhciBar, Offset, Data);
154 }
155
156 /**
157 Wait for memory set to the test Value.
158
159 @param AhciBar AHCI bar address.
160 @param Offset The memory offset to test.
161 @param MaskValue The mask Value of memory.
162 @param TestValue The test Value of memory.
163 @param Timeout The time out Value for wait memory set.
164
165 @retval EFI_DEVICE_ERROR The memory is not set.
166 @retval EFI_TIMEOUT The memory setting is time out.
167 @retval EFI_SUCCESS The memory is correct set.
168
169 **/
170 EFI_STATUS
171 EFIAPI
172 AhciWaitMmioSet (
173 IN UINT32 AhciBar,
174 IN UINT32 Offset,
175 IN UINT32 MaskValue,
176 IN UINT32 TestValue,
177 IN UINT64 Timeout
178 )
179 {
180 UINT32 Value;
181 UINT32 Delay;
182
183 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
184
185 do {
186 Value = AhciReadReg (AhciBar, Offset) & MaskValue;
187
188 if (Value == TestValue) {
189 return EFI_SUCCESS;
190 }
191
192 //
193 // Stall for 100 microseconds.
194 //
195 MicroSecondDelay (100);
196
197 Delay--;
198
199 } while (Delay > 0);
200
201 return EFI_TIMEOUT;
202 }
203 /**
204 Wait for the Value of the specified system memory set to the test Value.
205
206 @param Address The system memory address to test.
207 @param MaskValue The mask Value of memory.
208 @param TestValue The test Value of memory.
209 @param Timeout The time out Value for wait memory set, uses 100ns as a unit.
210
211 @retval EFI_TIMEOUT The system memory setting is time out.
212 @retval EFI_SUCCESS The system memory is correct set.
213
214 **/
215 EFI_STATUS
216 EFIAPI
217 AhciWaitMemSet (
218 IN EFI_PHYSICAL_ADDRESS Address,
219 IN UINT32 MaskValue,
220 IN UINT32 TestValue,
221 IN UINT64 Timeout
222 )
223 {
224 UINT32 Value;
225 UINT32 Delay;
226
227 Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
228
229 do {
230 //
231 // Access sytem memory to see if the Value is the tested one.
232 //
233 // The system memory pointed by Address will be updated by the
234 // SATA Host Controller, "volatile" is introduced to prevent
235 // compiler from optimizing the access to the memory address
236 // to only read once.
237 //
238 Value = *(volatile UINT32 *) (UINTN) Address;
239 Value &= MaskValue;
240
241 if (Value == TestValue) {
242 return EFI_SUCCESS;
243 }
244
245 //
246 // Stall for 100 microseconds.
247 //
248 MicroSecondDelay (100);
249
250 Delay--;
251
252 } while (Delay > 0);
253
254 return EFI_TIMEOUT;
255 }
256
257 /**
258 Check the memory status to the test Value.
259
260 @param[in] Address The memory address to test.
261 @param[in] MaskValue The mask Value of memory.
262 @param[in] TestValue The test Value of memory.
263 @param[in, out] RetryTimes The retry times Value for waitting memory set. If 0, then just try once.
264
265 @retval EFI_NOTREADY The memory is not set.
266 @retval EFI_TIMEOUT The memory setting retry times out.
267 @retval EFI_SUCCESS The memory is correct set.
268
269 **/
270 EFI_STATUS
271 EFIAPI
272 AhciCheckMemSet (
273 IN UINTN Address,
274 IN UINT32 MaskValue,
275 IN UINT32 TestValue,
276 IN OUT UINTN *RetryTimes OPTIONAL
277 )
278 {
279 UINT32 Value;
280
281 if (RetryTimes != NULL) {
282 (*RetryTimes)--;
283 }
284
285 Value = *(volatile UINT32 *) Address;
286 Value &= MaskValue;
287
288 if (Value == TestValue) {
289 return EFI_SUCCESS;
290 }
291
292 if ((RetryTimes != NULL) && (*RetryTimes == 0)) {
293 return EFI_TIMEOUT;
294 } else {
295 return EFI_NOT_READY;
296 }
297 }
298
299 /**
300 Clear the port interrupt and error status. It will also clear
301 HBA interrupt status.
302
303 @param AhciBar AHCI bar address.
304 @param Port The number of port.
305
306 **/
307 VOID
308 EFIAPI
309 AhciClearPortStatus (
310 IN UINT32 AhciBar,
311 IN UINT8 Port
312 )
313 {
314 UINT32 Offset;
315
316 //
317 // Clear any error status
318 //
319 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
320 AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
321
322 //
323 // Clear any port interrupt status
324 //
325 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
326 AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
327
328 //
329 // Clear any HBA interrupt status
330 //
331 AhciWriteReg (AhciBar, EFI_AHCI_IS_OFFSET, AhciReadReg (AhciBar, EFI_AHCI_IS_OFFSET));
332 }
333
334 /**
335 Enable the FIS running for giving port.
336
337 @param AhciBar AHCI bar address.
338 @param Port The number of port.
339 @param Timeout The timeout Value of enabling FIS.
340
341 @retval EFI_DEVICE_ERROR The FIS enable setting fails.
342 @retval EFI_TIMEOUT The FIS enable setting is time out.
343 @retval EFI_SUCCESS The FIS enable successfully.
344
345 **/
346 EFI_STATUS
347 EFIAPI
348 AhciEnableFisReceive (
349 IN UINT32 AhciBar,
350 IN UINT8 Port,
351 IN UINT64 Timeout
352 )
353 {
354 UINT32 Offset;
355
356 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
357 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_FRE);
358
359 return AhciWaitMmioSet (
360 AhciBar,
361 Offset,
362 EFI_AHCI_PORT_CMD_FR,
363 EFI_AHCI_PORT_CMD_FR,
364 Timeout
365 );
366 }
367
368 /**
369 Disable the FIS running for giving port.
370
371 @param AhciBar AHCI bar address.
372 @param Port The number of port.
373 @param Timeout The timeout Value of disabling FIS.
374
375 @retval EFI_DEVICE_ERROR The FIS disable setting fails.
376 @retval EFI_TIMEOUT The FIS disable setting is time out.
377 @retval EFI_UNSUPPORTED The port is in running state.
378 @retval EFI_SUCCESS The FIS disable successfully.
379
380 **/
381 EFI_STATUS
382 EFIAPI
383 AhciDisableFisReceive (
384 IN UINT32 AhciBar,
385 IN UINT8 Port,
386 IN UINT64 Timeout
387 )
388 {
389 UINT32 Offset;
390 UINT32 Data;
391
392 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
393 Data = AhciReadReg (AhciBar, Offset);
394
395 //
396 // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
397 //
398 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {
399 return EFI_UNSUPPORTED;
400 }
401
402 //
403 // Check if the Fis receive DMA engine for the port is running.
404 //
405 if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {
406 return EFI_SUCCESS;
407 }
408
409 AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));
410
411 return AhciWaitMmioSet (
412 AhciBar,
413 Offset,
414 EFI_AHCI_PORT_CMD_FR,
415 0,
416 Timeout
417 );
418 }
419
420 /**
421 Build the command list, command table and prepare the fis receiver.
422
423 @param AhciContext The pointer to the AHCI_CONTEXT.
424 @param Port The number of port.
425 @param PortMultiplier The timeout Value of stop.
426 @param CommandFis The control fis will be used for the transfer.
427 @param CommandList The command list will be used for the transfer.
428 @param AtapiCommand The atapi command will be used for the transfer.
429 @param AtapiCommandLength The Length of the atapi command.
430 @param CommandSlotNumber The command slot will be used for the transfer.
431 @param DataPhysicalAddr The pointer to the Data Buffer pci bus master address.
432 @param DataLength The Data count to be transferred.
433
434 **/
435 VOID
436 EFIAPI
437 AhciBuildCommand (
438 IN AHCI_CONTEXT *AhciContext,
439 IN UINT8 Port,
440 IN UINT8 PortMultiplier,
441 IN EFI_AHCI_COMMAND_FIS *CommandFis,
442 IN EFI_AHCI_COMMAND_LIST *CommandList,
443 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
444 IN UINT8 AtapiCommandLength,
445 IN UINT8 CommandSlotNumber,
446 IN OUT VOID *DataPhysicalAddr,
447 IN UINT64 DataLength
448 )
449 {
450 EFI_AHCI_REGISTERS *AhciRegisters;
451 UINT32 AhciBar;
452 UINT64 BaseAddr;
453 UINT64 PrdtNumber;
454 UINTN RemainedData;
455 UINTN MemAddr;
456 DATA_64 Data64;
457 UINT32 Offset;
458
459 AhciRegisters = &AhciContext->AhciRegisters;
460 AhciBar = AhciContext->AhciBar;
461
462 //
463 // Filling the PRDT
464 //
465 PrdtNumber = DivU64x32 (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1, EFI_AHCI_MAX_DATA_PER_PRDT);
466
467 //
468 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB Data block.
469 // It also limits that the maximum amount of the PRDT entry in the command table
470 // is 65535.
471 //
472 ASSERT (PrdtNumber <= 1);
473
474 Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis);
475
476 BaseAddr = Data64.Uint64;
477
478 ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
479
480 ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));
481
482 CommandFis->AhciCFisPmNum = PortMultiplier;
483
484 CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));
485
486 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
487 if (AtapiCommand != NULL) {
488 CopyMem (
489 &AhciRegisters->AhciCommandTable->AtapiCmd,
490 AtapiCommand,
491 AtapiCommandLength
492 );
493
494 CommandList->AhciCmdA = 1;
495 CommandList->AhciCmdP = 1;
496
497 AhciOrReg (AhciBar, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
498 } else {
499 AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
500 }
501
502 RemainedData = (UINTN) DataLength;
503 MemAddr = (UINTN) DataPhysicalAddr;
504 CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;
505
506 AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbc = (UINT32)RemainedData - 1;
507
508 Data64.Uint64 = (UINT64)MemAddr;
509 AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDba = Data64.Uint32.Lower32;
510 AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbau = Data64.Uint32.Upper32;
511
512 //
513 // Set the last PRDT to Interrupt On Complete
514 //
515 AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtIoc = 1;
516
517 CopyMem (
518 (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),
519 CommandList,
520 sizeof (EFI_AHCI_COMMAND_LIST)
521 );
522
523 Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTable;
524 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;
525 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;
526 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;
527
528 }
529
530 /**
531 Buid a command FIS.
532
533 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS Data structure.
534 @param AtaCommandBlock A pointer to the AhciBuildCommandFis Data structure.
535
536 **/
537 VOID
538 EFIAPI
539 AhciBuildCommandFis (
540 IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,
541 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock
542 )
543 {
544 ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));
545
546 CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;
547 //
548 // Indicator it's a command
549 //
550 CmdFis->AhciCFisCmdInd = 0x1;
551 CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;
552
553 CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;
554 CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;
555
556 CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;
557 CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;
558
559 CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;
560 CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;
561
562 CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;
563 CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;
564
565 CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;
566 CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;
567
568 CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);
569 }
570
571 /**
572 Start a PIO Data transfer on specific port.
573
574 @param AhciContext The pointer to the AHCI_CONTEXT.
575 @param Port The number of port.
576 @param PortMultiplier The timeout Value of stop.
577 @param AtapiCommand The atapi command will be used for the transfer.
578 @param AtapiCommandLength The Length of the atapi command.
579 @param Read The transfer direction.
580 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK Data.
581 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK Data.
582 @param MemoryAddr The pointer to the Data Buffer.
583 @param DataCount The Data count to be transferred.
584 @param Timeout The timeout Value of non Data transfer.
585
586 @retval EFI_DEVICE_ERROR The PIO Data transfer abort with error occurs.
587 @retval EFI_TIMEOUT The operation is time out.
588 @retval EFI_UNSUPPORTED The device is not ready for transfer.
589 @retval EFI_SUCCESS The PIO Data transfer executes successfully.
590
591 **/
592 EFI_STATUS
593 EFIAPI
594 AhciPioTransfer (
595 IN AHCI_CONTEXT *AhciContext,
596 IN UINT8 Port,
597 IN UINT8 PortMultiplier,
598 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
599 IN UINT8 AtapiCommandLength,
600 IN BOOLEAN Read,
601 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
602 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
603 IN OUT VOID *MemoryAddr,
604 IN UINT32 DataCount,
605 IN UINT64 Timeout
606 )
607 {
608 EFI_STATUS Status;
609 EFI_AHCI_REGISTERS *AhciRegisters;
610 UINT32 AhciBar;
611 UINT32 FisBaseAddr;
612 UINT32 Offset;
613 UINT32 Delay;
614 EFI_AHCI_COMMAND_FIS CFis;
615 EFI_AHCI_COMMAND_LIST CmdList;
616 UINT32 PortTfd;
617 UINT32 PrdCount;
618 UINT32 OldRfisLo;
619 UINT32 OldRfisHi;
620 UINT32 OldCmdListLo;
621 UINT32 OldCmdListHi;
622
623 AhciRegisters = &AhciContext->AhciRegisters;
624 AhciBar = AhciContext->AhciBar;
625
626 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
627 OldRfisLo = AhciReadReg (AhciBar, Offset);
628 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
629 OldRfisHi = AhciReadReg (AhciBar, Offset);
630 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
631 AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);
632 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
633 AhciWriteReg (AhciBar, Offset, 0);
634
635 //
636 // Single task envrionment, we only use one command table for all port
637 //
638 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
639 OldCmdListLo = AhciReadReg (AhciBar, Offset);
640 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
641 OldCmdListHi = AhciReadReg (AhciBar, Offset);
642 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
643 AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);
644 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
645 AhciWriteReg (AhciBar, Offset, 0);
646
647 //
648 // Package read needed
649 //
650 AhciBuildCommandFis (&CFis, AtaCommandBlock);
651
652 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
653
654 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
655 CmdList.AhciCmdW = Read ? 0 : 1;
656
657 AhciBuildCommand (
658 AhciContext,
659 Port,
660 PortMultiplier,
661 &CFis,
662 &CmdList,
663 AtapiCommand,
664 AtapiCommandLength,
665 0,
666 MemoryAddr,
667 DataCount
668 );
669
670 Status = AhciStartCommand (
671 AhciBar,
672 Port,
673 0,
674 Timeout
675 );
676 if (EFI_ERROR (Status)) {
677 goto Exit;
678 }
679
680 //
681 // Checking the status and wait the driver sending Data
682 //
683 FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis;
684 if (Read && (AtapiCommand == 0)) {
685 //
686 // Wait device sends the PIO setup fis before Data transfer
687 //
688 Status = EFI_TIMEOUT;
689 Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
690 do {
691 Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;
692
693 Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);
694 if (!EFI_ERROR (Status)) {
695 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
696 PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
697 //
698 // PxTFD will be updated if there is a D2H or SetupFIS received.
699 // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.
700 //
701 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
702 Status = EFI_DEVICE_ERROR;
703 break;
704 }
705
706 PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));
707 if (PrdCount == DataCount) {
708 break;
709 }
710 }
711
712 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
713 Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);
714 if (!EFI_ERROR (Status)) {
715 Status = EFI_DEVICE_ERROR;
716 break;
717 }
718
719 //
720 // Stall for 100 microseconds.
721 //
722 MicroSecondDelay(100);
723
724 Delay--;
725 } while (Delay > 0);
726 } else {
727 //
728 // Wait for D2H Fis is received
729 //
730 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
731 Status = AhciWaitMemSet (
732 Offset,
733 EFI_AHCI_FIS_TYPE_MASK,
734 EFI_AHCI_FIS_REGISTER_D2H,
735 Timeout
736 );
737
738 if (EFI_ERROR (Status)) {
739 goto Exit;
740 }
741
742 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
743 PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
744 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
745 Status = EFI_DEVICE_ERROR;
746 }
747 }
748
749 Exit:
750 AhciStopCommand (
751 AhciBar,
752 Port,
753 Timeout
754 );
755
756 AhciDisableFisReceive (
757 AhciBar,
758 Port,
759 Timeout
760 );
761
762 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
763 AhciWriteReg (AhciBar, Offset, OldRfisLo);
764 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
765 AhciWriteReg (AhciBar, Offset, OldRfisHi);
766
767 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
768 AhciWriteReg (AhciBar, Offset, OldCmdListLo);
769 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
770 AhciWriteReg (AhciBar, Offset, OldCmdListHi);
771
772 return Status;
773 }
774
775 /**
776 Stop command running for giving port
777
778 @param AhciBar AHCI bar address.
779 @param Port The number of port.
780 @param Timeout The timeout Value of stop.
781
782 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
783 @retval EFI_TIMEOUT The operation is time out.
784 @retval EFI_SUCCESS The command stop successfully.
785
786 **/
787 EFI_STATUS
788 EFIAPI
789 AhciStopCommand (
790 IN UINT32 AhciBar,
791 IN UINT8 Port,
792 IN UINT64 Timeout
793 )
794 {
795 UINT32 Offset;
796 UINT32 Data;
797
798 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
799 Data = AhciReadReg (AhciBar, Offset);
800
801 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {
802 return EFI_SUCCESS;
803 }
804
805 if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {
806 AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));
807 }
808
809 return AhciWaitMmioSet (
810 AhciBar,
811 Offset,
812 EFI_AHCI_PORT_CMD_CR,
813 0,
814 Timeout
815 );
816 }
817
818 /**
819 Start command for give slot on specific port.
820
821 @param AhciBar AHCI bar address.
822 @param Port The number of port.
823 @param CommandSlot The number of CommandSlot.
824 @param Timeout The timeout Value of start.
825
826 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
827 @retval EFI_TIMEOUT The operation is time out.
828 @retval EFI_SUCCESS The command start successfully.
829
830 **/
831 EFI_STATUS
832 EFIAPI
833 AhciStartCommand (
834 IN UINT32 AhciBar,
835 IN UINT8 Port,
836 IN UINT8 CommandSlot,
837 IN UINT64 Timeout
838 )
839 {
840 UINT32 CmdSlotBit;
841 EFI_STATUS Status;
842 UINT32 PortStatus;
843 UINT32 StartCmd;
844 UINT32 PortTfd;
845 UINT32 Offset;
846 UINT32 Capability;
847
848 //
849 // Collect AHCI controller information
850 //
851 Capability = AhciReadReg(AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
852
853 CmdSlotBit = (UINT32) (1 << CommandSlot);
854
855 AhciClearPortStatus (
856 AhciBar,
857 Port
858 );
859
860 Status = AhciEnableFisReceive (
861 AhciBar,
862 Port,
863 Timeout
864 );
865
866 if (EFI_ERROR (Status)) {
867 return Status;
868 }
869
870 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
871 PortStatus = AhciReadReg (AhciBar, Offset);
872
873 StartCmd = 0;
874 if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {
875 StartCmd = AhciReadReg (AhciBar, Offset);
876 StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;
877 StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;
878 }
879
880 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
881 PortTfd = AhciReadReg (AhciBar, Offset);
882
883 if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {
884 if ((Capability & BIT24) != 0) {
885 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
886 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_COL);
887
888 AhciWaitMmioSet (
889 AhciBar,
890 Offset,
891 EFI_AHCI_PORT_CMD_COL,
892 0,
893 Timeout
894 );
895 }
896 }
897
898 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
899 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);
900
901 //
902 // Setting the command
903 //
904 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;
905 AhciAndReg (AhciBar, Offset, 0);
906 AhciOrReg (AhciBar, Offset, CmdSlotBit);
907
908 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
909 AhciAndReg (AhciBar, Offset, 0);
910 AhciOrReg (AhciBar, Offset, CmdSlotBit);
911 return EFI_SUCCESS;
912 }
913
914
915 /**
916 Do AHCI HBA reset.
917
918 @param[in] AhciBar AHCI bar address.
919 @param[in] Timeout The timeout Value of reset.
920
921 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
922 @retval EFI_TIMEOUT The reset operation is time out.
923 @retval EFI_SUCCESS AHCI controller is reset successfully.
924
925 **/
926 EFI_STATUS
927 EFIAPI
928 AhciReset (
929 IN UINT32 AhciBar,
930 IN UINT64 Timeout
931 )
932 {
933 UINT32 Delay;
934 UINT32 Value;
935 UINT32 Capability;
936
937 //
938 // Collect AHCI controller information
939 //
940 Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
941
942 //
943 // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
944 //
945 if ((Capability & EFI_AHCI_CAP_SAM) == 0) {
946 AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
947 }
948
949 AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);
950
951 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
952
953 do {
954 Value = AhciReadReg(AhciBar, EFI_AHCI_GHC_OFFSET);
955 if ((Value & EFI_AHCI_GHC_RESET) == 0) {
956 return EFI_SUCCESS;
957 }
958
959 //
960 // Stall for 100 microseconds.
961 //
962 MicroSecondDelay(100);
963
964 Delay--;
965 } while (Delay > 0);
966
967 return EFI_TIMEOUT;
968
969
970 }
971
972 /**
973 Send Buffer cmd to specific device.
974
975 @param[in] AhciContext The pointer to the AHCI_CONTEXT.
976 @param[in] Port The port number of attached ATA device.
977 @param[in] PortMultiplier The port number of port multiplier of attached ATA device.
978 @param[in, out] Buffer The Data Buffer to store IDENTIFY PACKET Data.
979
980 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
981 @retval EFI_TIMEOUT The operation is time out.
982 @retval EFI_UNSUPPORTED The device is not ready for executing.
983 @retval EFI_SUCCESS The cmd executes successfully.
984
985 **/
986 EFI_STATUS
987 EFIAPI
988 AhciIdentify (
989 IN AHCI_CONTEXT *AhciContext,
990 IN UINT8 Port,
991 IN UINT8 PortMultiplier,
992 IN OUT ATA_IDENTIFY_DATA *Buffer
993 )
994 {
995 EFI_STATUS Status;
996 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
997
998 if (AhciContext == NULL || Buffer == NULL) {
999 return EFI_INVALID_PARAMETER;
1000 }
1001
1002 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
1003
1004 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
1005 AtaCommandBlock.AtaSectorCount = 1;
1006
1007 Status = AhciPioTransfer (
1008 AhciContext,
1009 Port,
1010 PortMultiplier,
1011 NULL,
1012 0,
1013 TRUE,
1014 &AtaCommandBlock,
1015 NULL,
1016 Buffer,
1017 sizeof (ATA_IDENTIFY_DATA),
1018 ATA_TIMEOUT
1019 );
1020
1021 return Status;
1022 }
1023
1024 /**
1025 Allocate transfer-related data struct which is used at AHCI mode.
1026
1027 @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.
1028
1029 @retval EFI_OUT_OF_RESOURCE No enough resource.
1030 @retval EFI_SUCCESS Successful to allocate resource.
1031
1032 **/
1033 EFI_STATUS
1034 EFIAPI
1035 AhciAllocateResource (
1036 IN OUT AHCI_CONTEXT *AhciContext
1037 )
1038 {
1039 EFI_STATUS Status;
1040 EFI_AHCI_REGISTERS *AhciRegisters;
1041 EFI_PHYSICAL_ADDRESS DeviceAddress;
1042 VOID *Base;
1043 VOID *Mapping;
1044
1045 AhciRegisters = &AhciContext->AhciRegisters;
1046
1047 //
1048 // Allocate resources required by AHCI host controller.
1049 //
1050 Status = IoMmuAllocateBuffer (
1051 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1052 &Base,
1053 &DeviceAddress,
1054 &Mapping
1055 );
1056 if (EFI_ERROR (Status)) {
1057 return EFI_OUT_OF_RESOURCES;
1058 }
1059 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
1060 AhciRegisters->AhciRFisMapping = Mapping;
1061 AhciRegisters->AhciRFis = Base;
1062 ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)));
1063
1064 Status = IoMmuAllocateBuffer (
1065 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
1066 &Base,
1067 &DeviceAddress,
1068 &Mapping
1069 );
1070 if (EFI_ERROR (Status)) {
1071 IoMmuFreeBuffer (
1072 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1073 AhciRegisters->AhciRFis,
1074 AhciRegisters->AhciRFisMapping
1075 );
1076 AhciRegisters->AhciRFis = NULL;
1077 return EFI_OUT_OF_RESOURCES;
1078 }
1079 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
1080 AhciRegisters->AhciCmdListMapping = Mapping;
1081 AhciRegisters->AhciCmdList = Base;
1082 ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)));
1083
1084 Status = IoMmuAllocateBuffer (
1085 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),
1086 &Base,
1087 &DeviceAddress,
1088 &Mapping
1089 );
1090 if (EFI_ERROR (Status)) {
1091 IoMmuFreeBuffer (
1092 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
1093 AhciRegisters->AhciCmdList,
1094 AhciRegisters->AhciCmdListMapping
1095 );
1096 AhciRegisters->AhciCmdList = NULL;
1097 IoMmuFreeBuffer (
1098 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1099 AhciRegisters->AhciRFis,
1100 AhciRegisters->AhciRFisMapping
1101 );
1102 AhciRegisters->AhciRFis = NULL;
1103 return EFI_OUT_OF_RESOURCES;
1104 }
1105 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
1106 AhciRegisters->AhciCommandTableMapping = Mapping;
1107 AhciRegisters->AhciCommandTable = Base;
1108 ZeroMem (AhciRegisters->AhciCommandTable, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)));
1109
1110 //
1111 // Allocate resources for data transfer.
1112 //
1113 Status = IoMmuAllocateBuffer (
1114 EFI_SIZE_TO_PAGES (HDD_PAYLOAD),
1115 &Base,
1116 &DeviceAddress,
1117 &Mapping
1118 );
1119 if (EFI_ERROR (Status)) {
1120 IoMmuFreeBuffer (
1121 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1122 AhciRegisters->AhciCommandTable,
1123 AhciRegisters->AhciCommandTableMapping
1124 );
1125 AhciRegisters->AhciCommandTable = NULL;
1126 IoMmuFreeBuffer (
1127 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
1128 AhciRegisters->AhciCmdList,
1129 AhciRegisters->AhciCmdListMapping
1130 );
1131 AhciRegisters->AhciCmdList = NULL;
1132 IoMmuFreeBuffer (
1133 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1134 AhciRegisters->AhciRFis,
1135 AhciRegisters->AhciRFisMapping
1136 );
1137 AhciRegisters->AhciRFis = NULL;
1138 return EFI_OUT_OF_RESOURCES;
1139 }
1140 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
1141 AhciContext->BufferMapping = Mapping;
1142 AhciContext->Buffer = Base;
1143 ZeroMem (AhciContext->Buffer, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (HDD_PAYLOAD));
1144
1145 DEBUG ((
1146 DEBUG_INFO,
1147 "%a() AhciContext 0x%x 0x%x 0x%x 0x%x\n",
1148 __FUNCTION__,
1149 AhciContext->Buffer,
1150 AhciRegisters->AhciRFis,
1151 AhciRegisters->AhciCmdList,
1152 AhciRegisters->AhciCommandTable
1153 ));
1154 return EFI_SUCCESS;
1155 }
1156
1157 /**
1158 Free allocated transfer-related data struct which is used at AHCI mode.
1159
1160 @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.
1161
1162 **/
1163 VOID
1164 EFIAPI
1165 AhciFreeResource (
1166 IN OUT AHCI_CONTEXT *AhciContext
1167 )
1168 {
1169 EFI_AHCI_REGISTERS *AhciRegisters;
1170
1171 AhciRegisters = &AhciContext->AhciRegisters;
1172
1173 if (AhciContext->Buffer != NULL) {
1174 IoMmuFreeBuffer (
1175 EFI_SIZE_TO_PAGES (HDD_PAYLOAD),
1176 AhciContext->Buffer,
1177 AhciContext->BufferMapping
1178 );
1179 AhciContext->Buffer = NULL;
1180 }
1181
1182 if (AhciRegisters->AhciCommandTable != NULL) {
1183 IoMmuFreeBuffer (
1184 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),
1185 AhciRegisters->AhciCommandTable,
1186 AhciRegisters->AhciCommandTableMapping
1187 );
1188 AhciRegisters->AhciCommandTable = NULL;
1189 }
1190
1191 if (AhciRegisters->AhciCmdList != NULL) {
1192 IoMmuFreeBuffer (
1193 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
1194 AhciRegisters->AhciCmdList,
1195 AhciRegisters->AhciCmdListMapping
1196 );
1197 AhciRegisters->AhciCmdList = NULL;
1198 }
1199
1200 if (AhciRegisters->AhciRFis != NULL) {
1201 IoMmuFreeBuffer (
1202 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1203 AhciRegisters->AhciRFis,
1204 AhciRegisters->AhciRFisMapping
1205 );
1206 AhciRegisters->AhciRFis = NULL;
1207 }
1208 }
1209
1210 /**
1211 Initialize ATA host controller at AHCI mode.
1212
1213 The function is designed to initialize ATA host controller.
1214
1215 @param[in] AhciContext The pointer to the AHCI_CONTEXT.
1216 @param[in] Port The port number to do initialization.
1217
1218 **/
1219 EFI_STATUS
1220 EFIAPI
1221 AhciModeInitialize (
1222 IN AHCI_CONTEXT *AhciContext,
1223 IN UINT8 Port
1224 )
1225 {
1226 EFI_STATUS Status;
1227 EFI_AHCI_REGISTERS *AhciRegisters;
1228 UINT32 AhciBar;
1229 UINT32 Capability;
1230 UINT32 Offset;
1231 UINT32 Data;
1232 UINT32 PhyDetectDelay;
1233
1234 AhciRegisters = &AhciContext->AhciRegisters;
1235 AhciBar = AhciContext->AhciBar;
1236
1237 Status = AhciReset (AhciBar, ATA_TIMEOUT);
1238 if (EFI_ERROR (Status)) {
1239 return Status;
1240 }
1241
1242 //
1243 // Collect AHCI controller information
1244 //
1245 Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
1246
1247 //
1248 // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
1249 //
1250 if ((Capability & EFI_AHCI_CAP_SAM) == 0) {
1251 AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
1252 }
1253
1254 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
1255 AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);
1256
1257 //
1258 // Single task envrionment, we only use one command table for all port
1259 //
1260 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
1261 AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);
1262
1263 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
1264 Data = AhciReadReg (AhciBar, Offset);
1265 if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {
1266 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_POD);
1267 }
1268
1269 if ((Capability & BIT27) != 0) {
1270 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_SUD);
1271 }
1272
1273 //
1274 // Disable aggressive power management.
1275 //
1276 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
1277 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);
1278 //
1279 // Disable the reporting of the corresponding interrupt to system software.
1280 //
1281 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;
1282 AhciAndReg (AhciBar, Offset, 0);
1283
1284 Status = AhciEnableFisReceive (
1285 AhciBar,
1286 Port,
1287 5000000
1288 );
1289 ASSERT_EFI_ERROR (Status);
1290 if (EFI_ERROR (Status)) {
1291 return Status;
1292 }
1293
1294 //
1295 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
1296 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
1297 //
1298 PhyDetectDelay = 16 * 1000;
1299 do {
1300 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
1301 if (AhciReadReg(AhciBar, Offset) != 0) {
1302 AhciWriteReg (AhciBar, Offset, AhciReadReg(AhciBar, Offset));
1303 }
1304 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
1305
1306 Data = AhciReadReg (AhciBar, Offset) & EFI_AHCI_PORT_TFD_MASK;
1307 if (Data == 0) {
1308 break;
1309 }
1310
1311 MicroSecondDelay (1000);
1312 PhyDetectDelay--;
1313 } while (PhyDetectDelay > 0);
1314
1315 if (PhyDetectDelay == 0) {
1316 return EFI_NOT_FOUND;
1317 }
1318
1319 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;
1320 Status = AhciWaitMmioSet (
1321 AhciBar,
1322 Offset,
1323 0x0000FFFF,
1324 0x00000101,
1325 160000000
1326 );
1327
1328 if (EFI_ERROR (Status)) {
1329 return Status;
1330 }
1331
1332 return Status;
1333 }
1334