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